github.com/nya3jp/tast@v0.0.0-20230601000426-85c8e4d83a9b/src/go.chromium.org/tast/core/internal/testing/fixt.go (about) 1 // Copyright 2020 The ChromiumOS Authors 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 package testing 6 7 import ( 8 "context" 9 "regexp" 10 "time" 11 12 "go.chromium.org/tast/core/errors" 13 "go.chromium.org/tast/core/internal/protocol" 14 ) 15 16 // Fixture represents fixtures to register to the framework. 17 type Fixture struct { 18 // Name is the name of the fixture. 19 // Tests and fixtures use the name to specify the fixture. 20 // The name must be camelCase starting with a lowercase letter and containing only digits and letters. 21 Name string 22 23 // Desc is the description of the fixture. 24 Desc string 25 26 // Contacts is a list of email addresses of persons and groups who are familiar with the 27 // fixture. At least one personal email address of an active committer should be specified so 28 // that we can file bugs or ask for code review. 29 Contacts []string 30 31 // Impl is the implementation of the fixture. 32 Impl FixtureImpl 33 34 // Parent specifies the parent fixture name, or empty if it has no parent. 35 Parent string 36 37 // SetUpTimeout is the timeout applied to SetUp. 38 // Even if fixtures are nested, the timeout is applied only to this stage. 39 // This timeout is by default 0. 40 SetUpTimeout time.Duration 41 42 // ResetTimeout is the timeout applied to Reset. 43 // Even if fixtures are nested, the timeout is applied only to this stage. 44 // This timeout is by default 0. 45 ResetTimeout time.Duration 46 47 // PreTestTimeout is the timeout applied to PreTest. 48 // Even if fixtures are nested, the timeout is applied only to this stage. 49 // This timeout is by default 0. 50 PreTestTimeout time.Duration 51 52 // PostTestTimeout is the timeout applied to PostTest. 53 // Even if fixtures are nested, the timeout is applied only to this stage. 54 // This timeout is by default 0. 55 PostTestTimeout time.Duration 56 57 // TearDownTimeout is the timeout applied to TearDown. 58 // Even if fixtures are nested, the timeout is applied only to this stage. 59 // This timeout is by default 0. 60 TearDownTimeout time.Duration 61 62 // ServiceDeps contains a list of RPC service names in local test bundles that this remote fixture 63 // will access. This field is valid only for remote fixtures. 64 ServiceDeps []string 65 66 // Vars contains the names of runtime variables used to pass out-of-band data to tests. 67 // Values are supplied using "tast run -var=name=value", and tests can access values via State.Var. 68 Vars []string 69 70 // Data contains paths of data files needed by the fixture, relative to a 71 // "data" subdirectory within the directory in which the fixture is registered. 72 Data []string 73 74 // PrivateAttr contains freeform text private attributres describing the fixture. 75 PrivateAttr []string 76 77 // TODO(oka): Add Param fields. 78 } 79 80 func (f *Fixture) instantiate(pkg string) (*FixtureInstance, error) { 81 if err := validateFixture(f); err != nil { 82 return nil, err 83 } 84 return &FixtureInstance{ 85 Pkg: pkg, 86 Name: f.Name, 87 Desc: f.Desc, 88 Contacts: append([]string(nil), f.Contacts...), 89 Impl: f.Impl, 90 Parent: f.Parent, 91 SetUpTimeout: f.SetUpTimeout, 92 ResetTimeout: f.ResetTimeout, 93 PreTestTimeout: f.PreTestTimeout, 94 PostTestTimeout: f.PostTestTimeout, 95 TearDownTimeout: f.TearDownTimeout, 96 ServiceDeps: append([]string(nil), f.ServiceDeps...), 97 Data: append([]string(nil), f.Data...), 98 Vars: append([]string(nil), f.Vars...), 99 PrivateAttr: append([]string(nil), f.PrivateAttr...), 100 }, nil 101 } 102 103 // FixtureInstance represents a fixture instance registered to the framework. 104 // 105 // FixtureInstance is to Fixture what TestInstance is to Test. 106 type FixtureInstance struct { 107 // Pkg is the package from which the fixture is registered. 108 Pkg string 109 110 // Following fields are copied from Fixture. 111 Name string 112 Desc string 113 Contacts []string 114 Impl FixtureImpl 115 Parent string 116 SetUpTimeout time.Duration 117 ResetTimeout time.Duration 118 PreTestTimeout time.Duration 119 PostTestTimeout time.Duration 120 TearDownTimeout time.Duration 121 Data []string 122 ServiceDeps []string 123 Vars []string 124 PrivateAttr []string 125 126 // Bundle is the name of the test bundle this test belongs to. 127 // This field is empty initially, and later set when the test is added 128 // to testing.Registry. 129 Bundle string 130 } 131 132 // Constraints returns EntityConstraints for this fixture. 133 func (f *FixtureInstance) Constraints() *EntityConstraints { 134 return &EntityConstraints{ 135 allVars: append([]string(nil), f.Vars...), 136 allData: append([]string(nil), f.Data...), 137 } 138 } 139 140 // EntityProto returns a protocol buffer message representation of f. 141 func (f *FixtureInstance) EntityProto() *protocol.Entity { 142 return &protocol.Entity{ 143 Type: protocol.EntityType_FIXTURE, 144 Package: f.Pkg, 145 Name: f.Name, 146 Description: f.Desc, 147 Fixture: f.Parent, 148 Dependencies: &protocol.EntityDependencies{ 149 DataFiles: append([]string(nil), f.Data...), 150 Services: append([]string(nil), f.ServiceDeps...), 151 }, 152 Contacts: &protocol.EntityContacts{ 153 Emails: append([]string(nil), f.Contacts...), 154 }, 155 LegacyData: &protocol.EntityLegacyData{ 156 Variables: append([]string(nil), f.Vars...), 157 Bundle: f.Bundle, 158 }, 159 } 160 } 161 162 // fixtureNameRegexp defines the valid fixture name pattern. 163 var fixtureNameRegexp = regexp.MustCompile(`^[a-z][A-Za-z0-9]*$`) 164 165 // validateFixture validates a user-supplied Fixture metadata. 166 func validateFixture(f *Fixture) error { 167 if !fixtureNameRegexp.MatchString(f.Name) { 168 return errors.Errorf("invalid fixture name: %q", f.Name) 169 } 170 return nil 171 } 172 173 // FixtureImpl provides implementation of the fixture registered to the framework. 174 type FixtureImpl interface { 175 // SetUp is called by the framework to set up the environment with possibly heavy-weight 176 // operations. 177 // 178 // The context and state passed to SetUp are associated with the fixture metadata. For example, 179 // testing.ContextOutDir(ctx) and s.OutDir() return the output directory allocated for the 180 // fixture itself. testing.ContextSoftwareDeps(ctx) fails since fixtures can't declare software 181 // dependencies. 182 // 183 // TODO(oka): Consider updating ContextSoftwareDeps API so that it's meaningful for fixture 184 // scoped contexts. For tests, ContextSoftwareDeps returns the dependencies the test declares, 185 // and utility methods (e.g. arc.New) use it to check that tests declare proper software 186 // dependencies. For fixtures, it is uncertain what ContextSoftwareDeps should return. One 187 // might think it could return the intersection of the software deps of the tests depending on 188 // the fixture, but it doesn't work considering arc.New checks OR condition of the software 189 // deps. Still, fixtures can call functions like arc.New that calls ContextSoftwareDeps. It 190 // indicates that we need to reconsider ContextSoftwareDeps API. 191 // 192 // The return value is made available to the direct children of this fixture in the entity 193 // graph, as long as this fixture and a child live in the same process. 194 // If any resource is associated with the value (e.g. Chrome browser connection), it must not 195 // be released in Reset, PreTest and PostTest because descendant fixtures may cache it or 196 // construct subresources derived from it (e.g. Chrome tab connection). 197 // 198 // SetUp is called in descending order (parents to children) when fixtures are nested. 199 // 200 // SetUp can be called multiple times. This happens when this fixture's TearDown is called 201 // before completing all tests depending on it in the following cases: 202 // - This fixture's Reset requested it by returning an error. 203 // - Ascendant fixtures' Reset requested it by returning an error. 204 // In any case, TearDown is called in a pair with a successful SetUp call. 205 // 206 // Errors in this method are reported as errors of the fixture itself, rather than tests 207 // depending on it. 208 // 209 // If one or more errors are reported in SetUp by s.Error or s.Fatal, all remaining tests 210 // depending on this fixture are marked failed without actually running. TearDown is not called 211 // in this case. If s.Fatal is called, SetUp immediately aborts. 212 // 213 // This method is the best place to do a heavy-weight setup of the system environment, e.g. 214 // restarting a Chrome session. 215 // 216 // Note that SetUpTimeout is by default 0. Change it to have a valid context. 217 SetUp(ctx context.Context, s *FixtState) interface{} 218 219 // Reset is called by the framework after each test (except for the last one) to do a 220 // light-weight reset of the environment to the original state. 221 // 222 // The context passed to Reset is associated with the fixture metadata. See SetUp for details. 223 // 224 // If Reset returns a non-nil error, the framework tears down and re-sets up the fixture to 225 // recover. To be accurate, the following methods are called in order: 226 // - Descendant fixtures' TearDown in ascending order 227 // - This fixture's TearDown 228 // - This fixture's SetUp 229 // - Descendant fixtures' SetUp in descending order 230 // Consequently, errors Reset returns don't affect ascendant fixtures. 231 // 232 // Returning an error from Reset is valid when light-weight reset doesn't restore the 233 // condition the fixture declares. 234 // 235 // Reset is called in descending order (parents to children) when fixtures are nested. 236 // 237 // This method is the best place to do a light-weight cleanup of the system environment to the 238 // original one when the fixture was set up, e.g. closing open Chrome tabs. 239 // 240 // Note that ResetTimeout is by default 0. Change it to have a valid context. 241 Reset(ctx context.Context) error 242 243 // PreTest is called by the framework before each test to do a light-weight set up for the test. 244 // 245 // The context and state passed to PreTest are associated with the test metadata. For example, 246 // testing.ContextOutDir(ctx) and s.OutDir() return the output directory allocated to the test. 247 // 248 // PreTest is called in descending order (parents to children) when fixtures are nested. 249 // 250 // s.Error or s.Fatal can be used to report errors in PreTest. When s.Fatal is called PreTest 251 // immediately aborts. The error is marked as the test failure. 252 // 253 // This method is always called if fixture is successfully reset by SetUp or Reset. 254 // 255 // In any case, PostTest is called in a pair with a successful PreTest call. 256 // 257 // If errors are reported in PreTest, it is reported as the test failure. 258 // 259 // If errors are reported in PreTest, the test and PostTest are not run. 260 // 261 // This method is the best place to do a setup for the test runs next. e.g. redirect logs to a 262 // file in the test's output directory. 263 // 264 // Note that PreTestTimeout is by default 0. Change it to have a valid context. 265 PreTest(ctx context.Context, s *FixtTestState) 266 267 // PostTest is called by the framework after each test to tear down changes PreTest made. 268 // 269 // The context and state passed to PostTest are associated with the test metadata. For example, 270 // testing.ContextOutDir(ctx) and s.OutDir() return the output directory allocated to the test. 271 // 272 // PostTest is called in ascending order (children to parent) when fixtures are nested. 273 // 274 // s.Error or s.Fatal can be used to report errors in PostTest. When s.Fatal is called PostTest 275 // immediately aborts. The error is marked as the test failure. 276 // 277 // This method is always called if PreTest succeeds. 278 // 279 // PostTest is always called in a pair with a successful PreTest call. 280 // 281 // If errors are reported in PostTest, it is reported as the test failure. 282 // 283 // The errors PostTest reports don't affect the order of the fixture methods the framework 284 // calls. 285 // 286 // This method is the best place to tear down changes PreTest made. e.g. close log files in the 287 // test output directory. 288 // 289 // Note that PostTestTimeout is by default 0. Change it to have a valid context. 290 PostTest(ctx context.Context, s *FixtTestState) 291 292 // TearDown is called by the framework to tear down the environment SetUp set up. 293 // 294 // The context and state passed to TearDown are associated with the fixture metadata. See SetUp 295 // for details. 296 // 297 // TearDown is called in an ascending order (children to parents) when fixtures are nested. 298 // 299 // TearDown is always called in a pair with a successful SetUp call. 300 // 301 // Errors in this method are reported as errors of the fixture itself, rather than tests 302 // depending on it. 303 // 304 // Errors in TearDown doesn't affect the order of the fixture methods the framework calls. 305 // That is, even if this fixture's TearDown reports errors, its ascendants' TearDown are still 306 // called. 307 // 308 // This method is the best place to tear down changes SetUp made. e.g. Unenroll enterprise 309 // enrollment. 310 // Changes that shouldn't hinder healthy execution of succeeding tests are not necessarily to 311 // be teared down. e.g. Chrome session can be left open. 312 // 313 // Note that TearDownTimeout is by default 0. Change it to have a valid context. 314 TearDown(ctx context.Context, s *FixtState) 315 }