diff --git a/test/e2e/framework/framework.go b/test/e2e/framework/framework.go index 1f3ad75ea87..3f9e5fef8df 100644 --- a/test/e2e/framework/framework.go +++ b/test/e2e/framework/framework.go @@ -102,6 +102,11 @@ type Framework struct { // should abort, the AfterSuite hook should run all Cleanup actions. cleanupHandle CleanupActionHandle + // afterEaches is a map of name to function to be called after each test. These are not + // cleared. The call order is randomized so that no dependencies can grow between + // the various afterEaches + afterEaches map[string]AfterEachActionFunc + // configuration for framework's client Options Options @@ -113,6 +118,9 @@ type Framework struct { clusterAutoscalerMetricsBeforeTest e2emetrics.Collection } +// AfterEachActionFunc is a function that can be called after each test +type AfterEachActionFunc func(f *Framework, failed bool) + // TestDataSummary is an interface for managing test data. type TestDataSummary interface { SummaryKind() string @@ -146,6 +154,18 @@ func NewFramework(baseName string, options Options, client clientset.Interface) ClientSet: client, } + f.AddAfterEach("dumpNamespaceInfo", func(f *Framework, failed bool) { + if !failed { + return + } + if !TestContext.DumpLogsOnFailure { + return + } + if !f.SkipNamespaceCreation { + DumpAllNamespaceInfo(f.ClientSet, f.Namespace.Name) + } + }) + ginkgo.BeforeEach(f.BeforeEach) ginkgo.AfterEach(f.AfterEach) @@ -315,6 +335,19 @@ func printSummaries(summaries []TestDataSummary, testBaseName string) { } } +// AddAfterEach is a way to add a function to be called after every test. The execution order is intentionally random +// to avoid growing dependencies. If you register the same name twice, it is a coding error and will panic. +func (f *Framework) AddAfterEach(name string, fn AfterEachActionFunc) { + if _, ok := f.afterEaches[name]; ok { + panic(fmt.Sprintf("%q is already registered", name)) + } + + if f.afterEaches == nil { + f.afterEaches = map[string]AfterEachActionFunc{} + } + f.afterEaches[name] = fn +} + // AfterEach deletes the namespace, after reading its events. func (f *Framework) AfterEach() { RemoveCleanupAction(f.cleanupHandle) @@ -365,12 +398,9 @@ func (f *Framework) AfterEach() { } }() - // Print events if the test failed. - if ginkgo.CurrentGinkgoTestDescription().Failed && TestContext.DumpLogsOnFailure { - // Pass both unversioned client and versioned clientset, till we have removed all uses of the unversioned client. - if !f.SkipNamespaceCreation { - DumpAllNamespaceInfo(f.ClientSet, f.Namespace.Name) - } + // run all aftereach functions in random order to ensure no dependencies grow + for _, afterEachFn := range f.afterEaches { + afterEachFn(f, ginkgo.CurrentGinkgoTestDescription().Failed) } if TestContext.GatherKubeSystemResourceUsageData != "false" && TestContext.GatherKubeSystemResourceUsageData != "none" && f.gatherer != nil {