1 package f2 2 3 import ( 4 "errors" 5 "flag" 6 "testing" 7 8 "edge-infra.dev/test/f2/fctx" 9 ) 10 11 // TODO: add diagram for test execution flow 12 13 // Context is a type alias 14 type Context = fctx.Context 15 16 // FrameworkFn is a framework-level lifecycle function defined by the user, called by 17 // [Framework.Setup] and [Framework.Teardown]. 18 // 19 // Changes to context are expected to be returned to caller. 20 type FrameworkFn func(Context) (Context, error) 21 22 // FrameworkTestFn is a lifecycle function executed by [Framework] in the context 23 // of a test run, e.g. [Framework.BeforeEachTest]. 24 // 25 // Changes to context are expected to be returned to caller. 26 type FrameworkTestFn func(Context, *testing.T) (Context, error) 27 28 // FeatureFn is a feature-level lifecycle function executed by [Framework], e.g. 29 // before the framework executes each feature, in the context of a test run. It 30 // is a [FrameworkTestFn] that gets information about the [Feature] being tested 31 // injected. 32 // 33 // Changes to context are expected to be returned to caller. 34 type FeatureFn func(Context, *testing.T, Feature) (Context, error) 35 36 // ErrSkip can be returned by FrameworkFns to signal that the entire test suite 37 // should be skipped. When this error is detected, the framework exits from 38 // TestMain with an exit code of 0. Callers should wrap this error with a 39 // specific reason for skipping that includes information on why the test suite 40 // was skipped and how to remediate it. 41 // 42 // This error is not checked on Teardown, because what is the point in skipping 43 // something which is already terminating? 44 var ErrSkip = errors.New("skipping") 45 46 type Extension interface { 47 RegisterFns(Framework) 48 IntoContext(Context) Context 49 } 50 51 type FlagBinder interface { 52 BindFlags(*flag.FlagSet) 53 } 54 55 type Labeler interface { 56 Labels() map[string]string 57 } 58 59 // StepFn is the function called for each step of a [Feature] test, including 60 // actual test execution, executed by the [Feature], not by the [Framework] 61 // directly. 62 // 63 // Changes to context are expected to be returned to caller. 64 type StepFn func(Context, *testing.T) Context 65 66 // Phase defines the individual lifecycle phases. 67 type Phase uint8 68 69 // Test lifecycle phases listed in the order they are triggered during test 70 // execution from the perspective of the framework, working outward (the 71 // framework setup function) in and then back out (ending on framework teardown). 72 // 73 // Within a feature, the ordering is: 74 // 75 // phaseBeforeTest -> phaseTest -> phaseAfterTest 76 const ( 77 phaseSetup Phase = iota 78 phaseBeforeTest 79 phaseBeforeFeature 80 phaseTest // where feature is executed, with its own before/after hooks 81 phaseAfterFeature 82 phaseAfterTest 83 phaseTeardown 84 ) 85 86 func (p Phase) String() string { 87 switch p { 88 case phaseSetup: 89 return "Setup" 90 case phaseBeforeTest: 91 return "BeforeEachTest" 92 case phaseBeforeFeature: 93 return "BeforeEachFeature" 94 case phaseTest: 95 return "Test" 96 case phaseAfterFeature: 97 return "AfterEachFeature" 98 case phaseAfterTest: 99 return "AfterEachTest" 100 case phaseTeardown: 101 return "Teardown" 102 default: 103 return "Impossible" 104 } 105 } 106 107 // Interface for testing.M so that we can provide alternative implementations 108 // for e.g. testing framework behavior. 109 type TestingMain interface { 110 Run() (code int) 111 } 112