github.com/moby/docker@v26.1.3+incompatible/internal/test/suite/suite.go (about) 1 // Package suite is a simplified version of testify's suite package which has unnecessary dependencies. 2 // Please remove this package whenever possible. 3 package suite 4 5 import ( 6 "context" 7 "flag" 8 "reflect" 9 "runtime/debug" 10 "strings" 11 "testing" 12 13 "github.com/docker/docker/testutil" 14 ) 15 16 // TimeoutFlag is the flag to set a per-test timeout when running tests. Defaults to `-timeout`. 17 var TimeoutFlag = flag.Duration("timeout", 0, "DO NOT USE") 18 19 var typTestingT = reflect.TypeOf(new(testing.T)) 20 21 // Run takes a testing suite and runs all of the tests attached to it. 22 func Run(ctx context.Context, t *testing.T, suite interface{}) { 23 defer failOnPanic(t) 24 25 ctx = testutil.StartSpan(ctx, t) 26 suiteCtx := ctx 27 28 suiteSetupDone := false 29 30 defer func() { 31 if suiteSetupDone { 32 if tearDownAllSuite, ok := getTeardownAllSuite(suite); ok { 33 tearDownAllSuite.TearDownSuite(suiteCtx, t) 34 } 35 } 36 }() 37 38 methodFinder := reflect.TypeOf(suite) 39 for index := 0; index < methodFinder.NumMethod(); index++ { 40 method := methodFinder.Method(index) 41 if !methodFilter(method.Name, method.Type) { 42 continue 43 } 44 t.Run(method.Name, func(t *testing.T) { 45 ctx := testutil.StartSpan(ctx, t) 46 testutil.SetContext(t, ctx) 47 t.Cleanup(func() { 48 testutil.CleanupContext(t) 49 }) 50 51 defer failOnPanic(t) 52 53 if !suiteSetupDone { 54 if setupAllSuite, ok := getSetupAllSuite(suite); ok { 55 setupAllSuite.SetUpSuite(suiteCtx, t) 56 } 57 suiteSetupDone = true 58 } 59 60 if setupTestSuite, ok := getSetupTestSuite(suite); ok { 61 setupTestSuite.SetUpTest(ctx, t) 62 } 63 defer func() { 64 if tearDownTestSuite, ok := getTearDownTestSuite(suite); ok { 65 tearDownTestSuite.TearDownTest(ctx, t) 66 } 67 }() 68 69 method.Func.Call([]reflect.Value{reflect.ValueOf(suite), reflect.ValueOf(t)}) 70 }) 71 } 72 } 73 74 func getSetupAllSuite(suite interface{}) (SetupAllSuite, bool) { 75 setupAllSuite, ok := suite.(SetupAllSuite) 76 if ok { 77 return setupAllSuite, ok 78 } 79 80 t := reflect.TypeOf(suite) 81 for i := 0; i < t.NumMethod(); i++ { 82 if t.Method(i).Name == "SetUpSuite" { 83 panic("Wrong SetUpSuite signature") 84 } 85 } 86 return nil, false 87 } 88 89 func getSetupTestSuite(suite interface{}) (SetupTestSuite, bool) { 90 setupAllTest, ok := suite.(SetupTestSuite) 91 if ok { 92 return setupAllTest, ok 93 } 94 95 t := reflect.TypeOf(suite) 96 for i := 0; i < t.NumMethod(); i++ { 97 if t.Method(i).Name == "SetUpTest" { 98 panic("Wrong SetUpTest signature") 99 } 100 } 101 return nil, false 102 } 103 104 func getTearDownTestSuite(suite interface{}) (TearDownTestSuite, bool) { 105 tearDownTest, ok := suite.(TearDownTestSuite) 106 if ok { 107 return tearDownTest, ok 108 } 109 110 t := reflect.TypeOf(suite) 111 for i := 0; i < t.NumMethod(); i++ { 112 if t.Method(i).Name == "TearDownTest" { 113 panic("Wrong TearDownTest signature") 114 } 115 } 116 return nil, false 117 } 118 119 func getTeardownAllSuite(suite interface{}) (TearDownAllSuite, bool) { 120 tearDownAll, ok := suite.(TearDownAllSuite) 121 if ok { 122 return tearDownAll, ok 123 } 124 125 t := reflect.TypeOf(suite) 126 for i := 0; i < t.NumMethod(); i++ { 127 if t.Method(i).Name == "TearDownSuite" { 128 panic("Wrong TearDownSuite signature") 129 } 130 } 131 return nil, false 132 } 133 134 func failOnPanic(t *testing.T) { 135 r := recover() 136 if r != nil { 137 t.Errorf("test suite panicked: %v\n%s", r, debug.Stack()) 138 t.FailNow() 139 } 140 } 141 142 func methodFilter(name string, typ reflect.Type) bool { 143 return strings.HasPrefix(name, "Test") && typ.NumIn() == 2 && typ.In(1) == typTestingT // 2 params: method receiver and *testing.T 144 }