1// Copyright 2021 Google Inc. All rights reserved. 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15package android 16 17import ( 18 "fmt" 19 "runtime" 20 "strings" 21 "testing" 22) 23 24// Provides support for creating test fixtures on which tests can be run. Reduces duplication 25// of test setup by allow tests to easily reuse setup code. 26// 27// Fixture 28// ======= 29// These determine the environment within which a test can be run. Fixtures are mutable and are 30// created and mutated by FixturePreparer instances. They are created by first creating a base 31// Fixture (which is essentially empty) and then applying FixturePreparer instances to it to modify 32// the environment. 33// 34// FixturePreparer 35// =============== 36// These are responsible for modifying a Fixture in preparation for it to run a test. Preparers are 37// intended to be immutable and able to prepare multiple Fixture objects simultaneously without 38// them sharing any data. 39// 40// They provide the basic capabilities for running tests too. 41// 42// FixturePreparers are only ever applied once per test fixture. Prior to application the list of 43// FixturePreparers are flattened and deduped while preserving the order they first appear in the 44// list. This makes it easy to reuse, group and combine FixturePreparers together. 45// 46// Each small self contained piece of test setup should be their own FixturePreparer. e.g. 47// * A group of related modules. 48// * A group of related mutators. 49// * A combination of both. 50// * Configuration. 51// 52// They should not overlap, e.g. the same module type should not be registered by different 53// FixturePreparers as using them both would cause a build error. In that case the preparer should 54// be split into separate parts and combined together using FixturePreparers(...). 55// 56// e.g. attempting to use AllPreparers in preparing a Fixture would break as it would attempt to 57// register module bar twice: 58// var Preparer1 = FixtureRegisterWithContext(RegisterModuleFooAndBar) 59// var Preparer2 = FixtureRegisterWithContext(RegisterModuleBarAndBaz) 60// var AllPreparers = GroupFixturePreparers(Preparer1, Preparer2) 61// 62// However, when restructured like this it would work fine: 63// var PreparerFoo = FixtureRegisterWithContext(RegisterModuleFoo) 64// var PreparerBar = FixtureRegisterWithContext(RegisterModuleBar) 65// var PreparerBaz = FixtureRegisterWithContext(RegisterModuleBaz) 66// var Preparer1 = GroupFixturePreparers(RegisterModuleFoo, RegisterModuleBar) 67// var Preparer2 = GroupFixturePreparers(RegisterModuleBar, RegisterModuleBaz) 68// var AllPreparers = GroupFixturePreparers(Preparer1, Preparer2) 69// 70// As after deduping and flattening AllPreparers would result in the following preparers being 71// applied: 72// 1. PreparerFoo 73// 2. PreparerBar 74// 3. PreparerBaz 75// 76// Preparers can be used for both integration and unit tests. 77// 78// Integration tests typically use all the module types, mutators and singletons that are available 79// for that package to try and replicate the behavior of the runtime build as closely as possible. 80// However, that realism comes at a cost of increased fragility (as they can be broken by changes in 81// many different parts of the build) and also increased runtime, especially if they use lots of 82// singletons and mutators. 83// 84// Unit tests on the other hand try and minimize the amount of code being tested which makes them 85// less susceptible to changes elsewhere in the build and quick to run but at a cost of potentially 86// not testing realistic scenarios. 87// 88// Supporting unit tests effectively require that preparers are available at the lowest granularity 89// possible. Supporting integration tests effectively require that the preparers are organized into 90// groups that provide all the functionality available. 91// 92// At least in terms of tests that check the behavior of build components via processing 93// `Android.bp` there is no clear separation between a unit test and an integration test. Instead 94// they vary from one end that tests a single module (e.g. filegroup) to the other end that tests a 95// whole system of modules, mutators and singletons (e.g. apex + hiddenapi). 96// 97// TestResult 98// ========== 99// These are created by running tests in a Fixture and provide access to the Config and TestContext 100// in which the tests were run. 101// 102// Example 103// ======= 104// 105// An exported preparer for use by other packages that need to use java modules. 106// 107// package java 108// var PrepareForIntegrationTestWithJava = GroupFixturePreparers( 109// android.PrepareForIntegrationTestWithAndroid, 110// FixtureRegisterWithContext(RegisterAGroupOfRelatedModulesMutatorsAndSingletons), 111// FixtureRegisterWithContext(RegisterAnotherGroupOfRelatedModulesMutatorsAndSingletons), 112// ... 113// ) 114// 115// Some files to use in tests in the java package. 116// 117// var javaMockFS = android.MockFS{ 118// "api/current.txt": nil, 119// "api/removed.txt": nil, 120// ... 121// } 122// 123// A package private preparer for use for testing java within the java package. 124// 125// var prepareForJavaTest = android.GroupFixturePreparers( 126// PrepareForIntegrationTestWithJava, 127// FixtureRegisterWithContext(func(ctx android.RegistrationContext) { 128// ctx.RegisterModuleType("test_module", testModule) 129// }), 130// javaMockFS.AddToFixture(), 131// ... 132// } 133// 134// func TestJavaStuff(t *testing.T) { 135// result := android.GroupFixturePreparers( 136// prepareForJavaTest, 137// android.FixtureWithRootAndroidBp(`java_library {....}`), 138// android.MockFS{...}.AddToFixture(), 139// ).RunTest(t) 140// ... test result ... 141// } 142// 143// package cc 144// var PrepareForTestWithCC = android.GroupFixturePreparers( 145// android.PrepareForArchMutator, 146// android.prepareForPrebuilts, 147// FixtureRegisterWithContext(RegisterRequiredBuildComponentsForTest), 148// ... 149// ) 150// 151// package apex 152// 153// var PrepareForApex = GroupFixturePreparers( 154// ... 155// ) 156// 157// Use modules and mutators from java, cc and apex. Any duplicate preparers (like 158// android.PrepareForArchMutator) will be automatically deduped. 159// 160// var prepareForApexTest = android.GroupFixturePreparers( 161// PrepareForJava, 162// PrepareForCC, 163// PrepareForApex, 164// ) 165// 166 167// A set of mock files to add to the mock file system. 168type MockFS map[string][]byte 169 170// Merge adds the extra entries from the supplied map to this one. 171// 172// Fails if the supplied map files with the same paths are present in both of them. 173func (fs MockFS) Merge(extra map[string][]byte) { 174 for p, c := range extra { 175 validateFixtureMockFSPath(p) 176 if _, ok := fs[p]; ok { 177 panic(fmt.Errorf("attempted to add file %s to the mock filesystem but it already exists", p)) 178 } 179 fs[p] = c 180 } 181} 182 183// Ensure that tests cannot add paths into the mock file system which would not be allowed in the 184// runtime, e.g. absolute paths, paths relative to the 'out/' directory. 185func validateFixtureMockFSPath(path string) { 186 // This uses validateSafePath rather than validatePath because the latter prevents adding files 187 // that include a $ but there are tests that allow files with a $ to be used, albeit only by 188 // globbing. 189 validatedPath, err := validateSafePath(path) 190 if err != nil { 191 panic(err) 192 } 193 194 // Make sure that the path is canonical. 195 if validatedPath != path { 196 panic(fmt.Errorf("path %q is not a canonical path, use %q instead", path, validatedPath)) 197 } 198 199 if path == "out" || strings.HasPrefix(path, "out/") { 200 panic(fmt.Errorf("cannot add output path %q to the mock file system", path)) 201 } 202} 203 204func (fs MockFS) AddToFixture() FixturePreparer { 205 return FixtureMergeMockFs(fs) 206} 207 208// FixtureCustomPreparer allows for the modification of any aspect of the fixture. 209// 210// This should only be used if one of the other more specific preparers are not suitable. 211func FixtureCustomPreparer(mutator func(fixture Fixture)) FixturePreparer { 212 return newSimpleFixturePreparer(func(f *fixture) { 213 mutator(f) 214 }) 215} 216 217// FixtureTestRunner determines the type of test to run. 218// 219// If no custom FixtureTestRunner is provided (using the FixtureSetTestRunner) then the default test 220// runner will run a standard Soong test that corresponds to what happens when Soong is run on the 221// command line. 222type FixtureTestRunner interface { 223 // FinalPreparer is a function that is run immediately before parsing the blueprint files. It is 224 // intended to perform the initialization needed by PostParseProcessor. 225 // 226 // It returns a CustomTestResult that is passed into PostParseProcessor and returned from 227 // FixturePreparer.RunTestWithCustomResult. If it needs to return some custom data then it must 228 // provide its own implementation of CustomTestResult and return an instance of that. Otherwise, 229 // it can just return the supplied *TestResult. 230 FinalPreparer(result *TestResult) CustomTestResult 231 232 // PostParseProcessor is called after successfully parsing the blueprint files and can do further 233 // work on the result of parsing the files. 234 // 235 // Successfully parsing simply means that no errors were encountered when parsing the blueprint 236 // files. 237 // 238 // This must collate any information useful for testing, e.g. errs, ninja deps and custom data in 239 // the supplied result. 240 PostParseProcessor(result CustomTestResult) 241} 242 243// FixtureSetTestRunner sets the FixtureTestRunner in the fixture. 244// 245// It is an error if more than one of these is applied to a single fixture. If none of these are 246// applied then the fixture will use the defaultTestRunner which will run the test as if it was 247// being run in `m <target>`. 248func FixtureSetTestRunner(testRunner FixtureTestRunner) FixturePreparer { 249 return newSimpleFixturePreparer(func(fixture *fixture) { 250 if fixture.testRunner != nil { 251 panic("fixture test runner has already been set") 252 } 253 fixture.testRunner = testRunner 254 }) 255} 256 257// Modify the config 258func FixtureModifyConfig(mutator func(config Config)) FixturePreparer { 259 return newSimpleFixturePreparer(func(f *fixture) { 260 mutator(f.config) 261 }) 262} 263 264// Modify the config and context 265func FixtureModifyConfigAndContext(mutator func(config Config, ctx *TestContext)) FixturePreparer { 266 return newSimpleFixturePreparer(func(f *fixture) { 267 mutator(f.config, f.ctx) 268 }) 269} 270 271// Modify the context 272func FixtureModifyContext(mutator func(ctx *TestContext)) FixturePreparer { 273 return newSimpleFixturePreparer(func(f *fixture) { 274 mutator(f.ctx) 275 }) 276} 277 278func FixtureRegisterWithContext(registeringFunc func(ctx RegistrationContext)) FixturePreparer { 279 return FixtureModifyContext(func(ctx *TestContext) { registeringFunc(ctx) }) 280} 281 282// Modify the mock filesystem 283func FixtureModifyMockFS(mutator func(fs MockFS)) FixturePreparer { 284 return newSimpleFixturePreparer(func(f *fixture) { 285 mutator(f.mockFS) 286 287 // Make sure that invalid paths were not added to the mock filesystem. 288 for p, _ := range f.mockFS { 289 validateFixtureMockFSPath(p) 290 } 291 }) 292} 293 294// Merge the supplied file system into the mock filesystem. 295// 296// Paths that already exist in the mock file system are overridden. 297func FixtureMergeMockFs(mockFS MockFS) FixturePreparer { 298 return FixtureModifyMockFS(func(fs MockFS) { 299 fs.Merge(mockFS) 300 }) 301} 302 303// Add a file to the mock filesystem 304// 305// Fail if the filesystem already contains a file with that path, use FixtureOverrideFile instead. 306func FixtureAddFile(path string, contents []byte) FixturePreparer { 307 return FixtureModifyMockFS(func(fs MockFS) { 308 validateFixtureMockFSPath(path) 309 if _, ok := fs[path]; ok { 310 panic(fmt.Errorf("attempted to add file %s to the mock filesystem but it already exists, use FixtureOverride*File instead", path)) 311 } 312 fs[path] = contents 313 }) 314} 315 316// Add a text file to the mock filesystem 317// 318// Fail if the filesystem already contains a file with that path. 319func FixtureAddTextFile(path string, contents string) FixturePreparer { 320 return FixtureAddFile(path, []byte(contents)) 321} 322 323// Override a file in the mock filesystem 324// 325// If the file does not exist this behaves as FixtureAddFile. 326func FixtureOverrideFile(path string, contents []byte) FixturePreparer { 327 return FixtureModifyMockFS(func(fs MockFS) { 328 fs[path] = contents 329 }) 330} 331 332// Override a text file in the mock filesystem 333// 334// If the file does not exist this behaves as FixtureAddTextFile. 335func FixtureOverrideTextFile(path string, contents string) FixturePreparer { 336 return FixtureOverrideFile(path, []byte(contents)) 337} 338 339// Add the root Android.bp file with the supplied contents. 340func FixtureWithRootAndroidBp(contents string) FixturePreparer { 341 return FixtureAddTextFile("Android.bp", contents) 342} 343 344// Merge some environment variables into the fixture. 345func FixtureMergeEnv(env map[string]string) FixturePreparer { 346 return FixtureModifyConfig(func(config Config) { 347 for k, v := range env { 348 if k == "PATH" { 349 panic("Cannot set PATH environment variable") 350 } 351 config.env[k] = v 352 } 353 }) 354} 355 356// Modify the env. 357// 358// Will panic if the mutator changes the PATH environment variable. 359func FixtureModifyEnv(mutator func(env map[string]string)) FixturePreparer { 360 return FixtureModifyConfig(func(config Config) { 361 oldPath := config.env["PATH"] 362 mutator(config.env) 363 newPath := config.env["PATH"] 364 if newPath != oldPath { 365 panic(fmt.Errorf("Cannot change PATH environment variable from %q to %q", oldPath, newPath)) 366 } 367 }) 368} 369 370// Allow access to the product variables when preparing the fixture. 371type FixtureProductVariables struct { 372 *productVariables 373} 374 375// Modify product variables. 376func FixtureModifyProductVariables(mutator func(variables FixtureProductVariables)) FixturePreparer { 377 return FixtureModifyConfig(func(config Config) { 378 productVariables := FixtureProductVariables{&config.productVariables} 379 mutator(productVariables) 380 }) 381} 382 383var PrepareForSkipTestOnMac = newSimpleFixturePreparer(func(fixture *fixture) { 384 if runtime.GOOS != "linux" { 385 fixture.t.Skip("Test is only supported on linux.") 386 } 387}) 388 389// PrepareForDebug_DO_NOT_SUBMIT puts the fixture into debug which will cause it to output its 390// state before running the test. 391// 392// This must only be added temporarily to a test for local debugging and must be removed from the 393// test before submitting. 394var PrepareForDebug_DO_NOT_SUBMIT = newSimpleFixturePreparer(func(fixture *fixture) { 395 fixture.debug = true 396}) 397 398// GroupFixturePreparers creates a composite FixturePreparer that is equivalent to applying each of 399// the supplied FixturePreparer instances in order. 400// 401// Before preparing the fixture the list of preparers is flattened by replacing each 402// instance of GroupFixturePreparers with its contents. 403func GroupFixturePreparers(preparers ...FixturePreparer) FixturePreparer { 404 all := dedupAndFlattenPreparers(nil, preparers) 405 return newFixturePreparer(all) 406} 407 408// NullFixturePreparer is a preparer that does nothing. 409var NullFixturePreparer = GroupFixturePreparers() 410 411// OptionalFixturePreparer will return the supplied preparer if it is non-nil, otherwise it will 412// return the NullFixturePreparer 413func OptionalFixturePreparer(preparer FixturePreparer) FixturePreparer { 414 if preparer == nil { 415 return NullFixturePreparer 416 } else { 417 return preparer 418 } 419} 420 421// FixturePreparer provides the ability to create, modify and then run tests within a fixture. 422type FixturePreparer interface { 423 // Return the flattened and deduped list of simpleFixturePreparer pointers. 424 list() []*simpleFixturePreparer 425 426 // Create a Fixture. 427 Fixture(t *testing.T) Fixture 428 429 // ExtendWithErrorHandler creates a new FixturePreparer that will use the supplied error handler 430 // to check the errors (may be 0) reported by the test. 431 // 432 // The default handlers is FixtureExpectsNoErrors which will fail the go test immediately if any 433 // errors are reported. 434 ExtendWithErrorHandler(errorHandler FixtureErrorHandler) FixturePreparer 435 436 // Run the test, checking any errors reported and returning a TestResult instance. 437 // 438 // Shorthand for Fixture(t).RunTest() 439 RunTest(t *testing.T) *TestResult 440 441 // RunTestWithCustomResult runs the test just as RunTest(t) does but instead of returning a 442 // *TestResult it returns the CustomTestResult that was returned by the custom 443 // FixtureTestRunner.PostParseProcessor method that ran the test, or the *TestResult if that 444 // method returned nil. 445 // 446 // This method must be used when needing to access custom data collected by the 447 // FixtureTestRunner.PostParseProcessor method. 448 // 449 // e.g. something like this 450 // 451 // preparers := ...FixtureSetTestRunner(&myTestRunner)... 452 // customResult := preparers.RunTestWithCustomResult(t).(*myCustomTestResult) 453 // doSomething(customResult.data) 454 RunTestWithCustomResult(t *testing.T) CustomTestResult 455 456 // Run the test with the supplied Android.bp file. 457 // 458 // preparer.RunTestWithBp(t, bp) is shorthand for 459 // android.GroupFixturePreparers(preparer, android.FixtureWithRootAndroidBp(bp)).RunTest(t) 460 RunTestWithBp(t *testing.T, bp string) *TestResult 461 462 // RunTestWithConfig is a temporary method added to help ease the migration of existing tests to 463 // the test fixture. 464 // 465 // In order to allow the Config object to be customized separately to the TestContext a lot of 466 // existing test code has `test...WithConfig` funcs that allow the Config object to be supplied 467 // from the test and then have the TestContext created and configured automatically. e.g. 468 // testCcWithConfig, testCcErrorWithConfig, testJavaWithConfig, etc. 469 // 470 // This method allows those methods to be migrated to use the test fixture pattern without 471 // requiring that every test that uses those methods be migrated at the same time. That allows 472 // those tests to benefit from correctness in the order of registration quickly. 473 // 474 // This method discards the config (along with its mock file system, product variables, 475 // environment, etc.) that may have been set up by FixturePreparers. 476 // 477 // deprecated 478 RunTestWithConfig(t *testing.T, config Config) *TestResult 479} 480 481// dedupAndFlattenPreparers removes any duplicates and flattens any composite FixturePreparer 482// instances. 483// 484// base - a list of already flattened and deduped preparers that will be applied first before 485// 486// the list of additional preparers. Any duplicates of these in the additional preparers 487// will be ignored. 488// 489// preparers - a list of additional unflattened, undeduped preparers that will be applied after the 490// 491// base preparers. 492// 493// Returns a deduped and flattened list of the preparers starting with the ones in base with any 494// additional ones from the preparers list added afterwards. 495func dedupAndFlattenPreparers(base []*simpleFixturePreparer, preparers []FixturePreparer) []*simpleFixturePreparer { 496 if len(preparers) == 0 { 497 return base 498 } 499 500 list := make([]*simpleFixturePreparer, len(base)) 501 visited := make(map[*simpleFixturePreparer]struct{}) 502 503 // Mark the already flattened and deduped preparers, if any, as having been seen so that 504 // duplicates of these in the additional preparers will be discarded. Add them to the output 505 // list. 506 for i, s := range base { 507 visited[s] = struct{}{} 508 list[i] = s 509 } 510 511 for _, p := range preparers { 512 for _, s := range p.list() { 513 if _, seen := visited[s]; !seen { 514 visited[s] = struct{}{} 515 list = append(list, s) 516 } 517 } 518 } 519 520 return list 521} 522 523// compositeFixturePreparer is a FixturePreparer created from a list of fixture preparers. 524type compositeFixturePreparer struct { 525 baseFixturePreparer 526 // The flattened and deduped list of simpleFixturePreparer pointers encapsulated within this 527 // composite preparer. 528 preparers []*simpleFixturePreparer 529} 530 531func (c *compositeFixturePreparer) list() []*simpleFixturePreparer { 532 return c.preparers 533} 534 535func newFixturePreparer(preparers []*simpleFixturePreparer) FixturePreparer { 536 if len(preparers) == 1 { 537 return preparers[0] 538 } 539 p := &compositeFixturePreparer{ 540 preparers: preparers, 541 } 542 p.initBaseFixturePreparer(p) 543 return p 544} 545 546// simpleFixturePreparer is a FixturePreparer that applies a function to a fixture. 547type simpleFixturePreparer struct { 548 baseFixturePreparer 549 function func(fixture *fixture) 550} 551 552func (s *simpleFixturePreparer) list() []*simpleFixturePreparer { 553 return []*simpleFixturePreparer{s} 554} 555 556func newSimpleFixturePreparer(preparer func(fixture *fixture)) FixturePreparer { 557 p := &simpleFixturePreparer{function: preparer} 558 p.initBaseFixturePreparer(p) 559 return p 560} 561 562// FixtureErrorHandler determines how to respond to errors reported by the code under test. 563// 564// Some possible responses: 565// - Fail the test if any errors are reported, see FixtureExpectsNoErrors. 566// - Fail the test if at least one error that matches a pattern is not reported see 567// FixtureExpectsAtLeastOneErrorMatchingPattern 568// - Fail the test if any unexpected errors are reported. 569// 570// Although at the moment all the error handlers are implemented as simply a wrapper around a 571// function this is defined as an interface to allow future enhancements, e.g. provide different 572// ways other than patterns to match an error and to combine handlers together. 573type FixtureErrorHandler interface { 574 // CheckErrors checks the errors reported. 575 // 576 // The supplied result can be used to access the state of the code under test just as the main 577 // body of the test would but if any errors other than ones expected are reported the state may 578 // be indeterminate. 579 CheckErrors(t *testing.T, result *TestResult) 580} 581 582type simpleErrorHandler struct { 583 function func(t *testing.T, result *TestResult) 584} 585 586func (h simpleErrorHandler) CheckErrors(t *testing.T, result *TestResult) { 587 t.Helper() 588 h.function(t, result) 589} 590 591// The default fixture error handler. 592// 593// Will fail the test immediately if any errors are reported. 594// 595// If the test fails this handler will call `result.FailNow()` which will exit the goroutine within 596// which the test is being run which means that the RunTest() method will not return. 597var FixtureExpectsNoErrors = FixtureCustomErrorHandler( 598 func(t *testing.T, result *TestResult) { 599 t.Helper() 600 FailIfErrored(t, result.Errs) 601 }, 602) 603 604// FixtureIgnoreErrors ignores any errors. 605// 606// If this is used then it is the responsibility of the test to check the TestResult.Errs does not 607// contain any unexpected errors. 608var FixtureIgnoreErrors = FixtureCustomErrorHandler(func(t *testing.T, result *TestResult) { 609 // Ignore the errors 610}) 611 612// FixtureExpectsAtLeastOneMatchingError returns an error handler that will cause the test to fail 613// if at least one error that matches the regular expression is not found. 614// 615// The test will be failed if: 616// * No errors are reported. 617// * One or more errors are reported but none match the pattern. 618// 619// The test will not fail if: 620// * Multiple errors are reported that do not match the pattern as long as one does match. 621// 622// If the test fails this handler will call `result.FailNow()` which will exit the goroutine within 623// which the test is being run which means that the RunTest() method will not return. 624func FixtureExpectsAtLeastOneErrorMatchingPattern(pattern string) FixtureErrorHandler { 625 return FixtureCustomErrorHandler(func(t *testing.T, result *TestResult) { 626 t.Helper() 627 if !FailIfNoMatchingErrors(t, pattern, result.Errs) { 628 t.FailNow() 629 } 630 }) 631} 632 633// FixtureExpectsOneErrorToMatchPerPattern returns an error handler that will cause the test to fail 634// if there are any unexpected errors. 635// 636// The test will be failed if: 637// * The number of errors reported does not exactly match the patterns. 638// * One or more of the reported errors do not match a pattern. 639// * No patterns are provided and one or more errors are reported. 640// 641// The test will not fail if: 642// * One or more of the patterns does not match an error. 643// 644// If the test fails this handler will call `result.FailNow()` which will exit the goroutine within 645// which the test is being run which means that the RunTest() method will not return. 646func FixtureExpectsAllErrorsToMatchAPattern(patterns []string) FixtureErrorHandler { 647 return FixtureCustomErrorHandler(func(t *testing.T, result *TestResult) { 648 t.Helper() 649 CheckErrorsAgainstExpectations(t, result.Errs, patterns) 650 }) 651} 652 653// FixtureExpectsOneErrorPattern returns an error handler that will cause the test to fail 654// if there is more than one error or the error does not match the pattern. 655// 656// If the test fails this handler will call `result.FailNow()` which will exit the goroutine within 657// which the test is being run which means that the RunTest() method will not return. 658func FixtureExpectsOneErrorPattern(pattern string) FixtureErrorHandler { 659 return FixtureCustomErrorHandler(func(t *testing.T, result *TestResult) { 660 t.Helper() 661 CheckErrorsAgainstExpectations(t, result.Errs, []string{pattern}) 662 }) 663} 664 665// FixtureCustomErrorHandler creates a custom error handler 666func FixtureCustomErrorHandler(function func(t *testing.T, result *TestResult)) FixtureErrorHandler { 667 return simpleErrorHandler{ 668 function: function, 669 } 670} 671 672// Fixture defines the test environment. 673type Fixture interface { 674 // Config returns the fixture's configuration. 675 Config() Config 676 677 // Context returns the fixture's test context. 678 Context() *TestContext 679 680 // MockFS returns the fixture's mock filesystem. 681 MockFS() MockFS 682 683 // Run the test, checking any errors reported and returning a TestResult instance. 684 RunTest() CustomTestResult 685} 686 687// Struct to allow TestResult to embed a *TestContext and allow call forwarding to its methods. 688type testContext struct { 689 *TestContext 690} 691 692// The result of running a test. 693type TestResult struct { 694 testContext 695 696 fixture *fixture 697 Config Config 698 699 // The errors that were reported during the test. 700 Errs []error 701 702 // The ninja deps is a list of the ninja files dependencies that were added by the modules and 703 // singletons via the *.AddNinjaFileDeps() methods. 704 NinjaDeps []string 705} 706 707func (r *TestResult) testResult() *TestResult { return r } 708 709// CustomTestResult is the interface that FixtureTestRunner implementations who wish to return 710// custom data must implement. It must embed *TestResult and initialize that to the value passed 711// into the method. It is returned from the FixtureTestRunner.FinalPreparer, passed into the 712// FixtureTestRunner.PostParseProcessor and returned from FixturePreparer.RunTestWithCustomResult. 713// 714// e.g. something like this: 715// 716// type myCustomTestResult struct { 717// *android.TestResult 718// data []string 719// } 720// 721// func (r *myTestRunner) FinalPreparer(result *TestResult) CustomTestResult { 722// ... do some final test preparation ... 723// return &myCustomTestResult{TestResult: result) 724// } 725// 726// func (r *myTestRunner) PostParseProcessor(result CustomTestResult) { 727// ... 728// myData := []string {....} 729// ... 730// customResult := result.(*myCustomTestResult) 731// customResult.data = myData 732// } 733type CustomTestResult interface { 734 // testResult returns the embedded *TestResult. 735 testResult() *TestResult 736} 737 738var _ CustomTestResult = (*TestResult)(nil) 739 740type TestPathContext struct { 741 *TestResult 742} 743 744var _ PathContext = &TestPathContext{} 745 746func (t *TestPathContext) Config() Config { 747 return t.TestResult.Config 748} 749 750func (t *TestPathContext) AddNinjaFileDeps(deps ...string) { 751 panic("unimplemented") 752} 753 754func createFixture(t *testing.T, buildDir string, preparers []*simpleFixturePreparer) Fixture { 755 config := TestConfig(buildDir, nil, "", nil) 756 ctx := newTestContextForFixture(config) 757 fixture := &fixture{ 758 preparers: preparers, 759 t: t, 760 config: config, 761 ctx: ctx, 762 mockFS: make(MockFS), 763 // Set the default error handler. 764 errorHandler: FixtureExpectsNoErrors, 765 } 766 767 for _, preparer := range preparers { 768 preparer.function(fixture) 769 } 770 771 return fixture 772} 773 774type baseFixturePreparer struct { 775 self FixturePreparer 776} 777 778func (b *baseFixturePreparer) initBaseFixturePreparer(self FixturePreparer) { 779 b.self = self 780} 781 782func (b *baseFixturePreparer) Fixture(t *testing.T) Fixture { 783 return createFixture(t, t.TempDir(), b.self.list()) 784} 785 786func (b *baseFixturePreparer) ExtendWithErrorHandler(errorHandler FixtureErrorHandler) FixturePreparer { 787 return GroupFixturePreparers(b.self, newSimpleFixturePreparer(func(fixture *fixture) { 788 fixture.errorHandler = errorHandler 789 })) 790} 791 792func (b *baseFixturePreparer) RunTest(t *testing.T) *TestResult { 793 t.Helper() 794 return b.RunTestWithCustomResult(t).testResult() 795} 796 797func (b *baseFixturePreparer) RunTestWithCustomResult(t *testing.T) CustomTestResult { 798 t.Helper() 799 fixture := b.self.Fixture(t) 800 return fixture.RunTest() 801} 802 803func (b *baseFixturePreparer) RunTestWithBp(t *testing.T, bp string) *TestResult { 804 t.Helper() 805 return GroupFixturePreparers(b.self, FixtureWithRootAndroidBp(bp)).RunTest(t) 806} 807 808func (b *baseFixturePreparer) RunTestWithConfig(t *testing.T, config Config) *TestResult { 809 t.Helper() 810 // Create the fixture as normal. 811 fixture := b.self.Fixture(t).(*fixture) 812 813 // Discard the mock filesystem as otherwise that will override the one in the config. 814 fixture.mockFS = nil 815 816 // Replace the config with the supplied one in the fixture. 817 fixture.config = config 818 819 // Ditto with config derived information in the TestContext. 820 ctx := fixture.ctx 821 ctx.config = config 822 ctx.SetFs(ctx.config.fs) 823 if ctx.config.mockBpList != "" { 824 ctx.SetModuleListFile(ctx.config.mockBpList) 825 } 826 827 return fixture.RunTest().testResult() 828} 829 830type fixture struct { 831 // The preparers used to create this fixture. 832 preparers []*simpleFixturePreparer 833 834 // The test runner used in this fixture, defaults to defaultTestRunner if not set. 835 testRunner FixtureTestRunner 836 837 // The gotest state of the go test within which this was created. 838 t *testing.T 839 840 // The configuration prepared for this fixture. 841 config Config 842 843 // The test context prepared for this fixture. 844 ctx *TestContext 845 846 // The mock filesystem prepared for this fixture. 847 mockFS MockFS 848 849 // The error handler used to check the errors, if any, that are reported. 850 errorHandler FixtureErrorHandler 851 852 // Debug mode status 853 debug bool 854} 855 856func (f *fixture) Config() Config { 857 return f.config 858} 859 860func (f *fixture) Context() *TestContext { 861 return f.ctx 862} 863 864func (f *fixture) MockFS() MockFS { 865 return f.mockFS 866} 867 868func (f *fixture) RunTest() CustomTestResult { 869 f.t.Helper() 870 871 // If in debug mode output the state of the fixture before running the test. 872 if f.debug { 873 f.outputDebugState() 874 } 875 876 ctx := f.ctx 877 878 // Do not use the fixture's mockFS to initialize the config's mock file system if it has been 879 // cleared by RunTestWithConfig. 880 if f.mockFS != nil { 881 // The TestConfig() method assumes that the mock filesystem is available when creating so 882 // creates the mock file system immediately. Similarly, the NewTestContext(Config) method 883 // assumes that the supplied Config's FileSystem has been properly initialized before it is 884 // called and so it takes its own reference to the filesystem. However, fixtures create the 885 // Config and TestContext early so they can be modified by preparers at which time the mockFS 886 // has not been populated (because it too is modified by preparers). So, this reinitializes the 887 // Config and TestContext's FileSystem using the now populated mockFS. 888 f.config.mockFileSystem("", f.mockFS) 889 890 ctx.SetFs(ctx.config.fs) 891 if ctx.config.mockBpList != "" { 892 ctx.SetModuleListFile(ctx.config.mockBpList) 893 } 894 } 895 896 // Create and set the Context's NameInterface. It needs to be created here as it depends on the 897 // configuration that has been prepared for this fixture. 898 resolver := NewNameResolver(ctx.config) 899 900 // Set the NameInterface in the main Context. 901 ctx.SetNameInterface(resolver) 902 903 // Set the NameResolver in the TestContext. 904 ctx.NameResolver = resolver 905 906 // If test runner has not been set then use the default runner. 907 if f.testRunner == nil { 908 f.testRunner = defaultTestRunner 909 } 910 911 // Create the result to collate result information. 912 result := &TestResult{ 913 testContext: testContext{ctx}, 914 fixture: f, 915 Config: f.config, 916 } 917 918 // Do any last minute preparation before parsing the blueprint files. 919 customResult := f.testRunner.FinalPreparer(result) 920 921 // Parse the blueprint files adding the information to the result. 922 extraNinjaDeps, errs := ctx.ParseBlueprintsFiles("ignored") 923 result.NinjaDeps = append(result.NinjaDeps, extraNinjaDeps...) 924 result.Errs = append(result.Errs, errs...) 925 926 if len(result.Errs) == 0 { 927 // If parsing the blueprint files was successful then perform any additional processing. 928 f.testRunner.PostParseProcessor(customResult) 929 } 930 931 f.errorHandler.CheckErrors(f.t, result) 932 933 return customResult 934} 935 936// standardTestRunner is the implementation of the default test runner 937type standardTestRunner struct{} 938 939func (s *standardTestRunner) FinalPreparer(result *TestResult) CustomTestResult { 940 // Register the hard coded mutators and singletons used by the standard Soong build as well as 941 // any additional instances that have been registered with this fixture. 942 result.TestContext.Register() 943 return result 944} 945 946func (s *standardTestRunner) PostParseProcessor(customResult CustomTestResult) { 947 result := customResult.(*TestResult) 948 ctx := result.TestContext 949 cfg := result.Config 950 // Prepare the build actions, i.e. run all the mutators, singletons and then invoke the 951 // GenerateAndroidBuildActions methods on all the modules. 952 extraNinjaDeps, errs := ctx.PrepareBuildActions(cfg) 953 result.NinjaDeps = append(result.NinjaDeps, extraNinjaDeps...) 954 result.CollateErrs(errs) 955} 956 957var defaultTestRunner FixtureTestRunner = &standardTestRunner{} 958 959func (f *fixture) outputDebugState() { 960 fmt.Printf("Begin Fixture State for %s\n", f.t.Name()) 961 if len(f.config.env) == 0 { 962 fmt.Printf(" Fixture Env is empty\n") 963 } else { 964 fmt.Printf(" Begin Env\n") 965 for k, v := range f.config.env { 966 fmt.Printf(" - %s=%s\n", k, v) 967 } 968 fmt.Printf(" End Env\n") 969 } 970 if len(f.mockFS) == 0 { 971 fmt.Printf(" Mock FS is empty\n") 972 } else { 973 fmt.Printf(" Begin Mock FS Contents\n") 974 for p, c := range f.mockFS { 975 if c == nil { 976 fmt.Printf("\n - %s: nil\n", p) 977 } else { 978 contents := string(c) 979 separator := " ========================================================================" 980 fmt.Printf(" - %s\n%s\n", p, separator) 981 for i, line := range strings.Split(contents, "\n") { 982 fmt.Printf(" %6d: %s\n", i+1, line) 983 } 984 fmt.Printf("%s\n", separator) 985 } 986 } 987 fmt.Printf(" End Mock FS Contents\n") 988 } 989 fmt.Printf("End Fixture State for %s\n", f.t.Name()) 990} 991 992// NormalizePathForTesting removes the test invocation specific build directory from the supplied 993// path. 994// 995// If the path is within the build directory (e.g. an OutputPath) then this returns the relative 996// path to avoid tests having to deal with the dynamically generated build directory. 997// 998// Otherwise, this returns the supplied path as it is almost certainly a source path that is 999// relative to the root of the source tree. 1000// 1001// Even though some information is removed from some paths and not others it should be possible to 1002// differentiate between them by the paths themselves, e.g. output paths will likely include 1003// ".intermediates" but source paths won't. 1004func (r *TestResult) NormalizePathForTesting(path Path) string { 1005 pathContext := PathContextForTesting(r.Config) 1006 pathAsString := path.String() 1007 if rel, isRel := MaybeRel(pathContext, r.Config.SoongOutDir(), pathAsString); isRel { 1008 return rel 1009 } 1010 return pathAsString 1011} 1012 1013// NormalizePathsForTesting normalizes each path in the supplied list and returns their normalized 1014// forms. 1015func (r *TestResult) NormalizePathsForTesting(paths Paths) []string { 1016 var result []string 1017 for _, path := range paths { 1018 result = append(result, r.NormalizePathForTesting(path)) 1019 } 1020 return result 1021} 1022 1023// Preparer will return a FixturePreparer encapsulating all the preparers used to create the fixture 1024// that produced this result. 1025// 1026// e.g. assuming that this result was created by running: 1027// 1028// GroupFixturePreparers(preparer1, preparer2, preparer3).RunTest(t) 1029// 1030// Then this method will be equivalent to running: 1031// 1032// GroupFixturePreparers(preparer1, preparer2, preparer3) 1033// 1034// This is intended for use by tests whose output is Android.bp files to verify that those files 1035// are valid, e.g. tests of the snapshots produced by the sdk module type. 1036func (r *TestResult) Preparer() FixturePreparer { 1037 return newFixturePreparer(r.fixture.preparers) 1038} 1039 1040// Module returns the module with the specific name and of the specified variant. 1041func (r *TestResult) Module(name string, variant string) Module { 1042 return r.ModuleForTests(name, variant).Module() 1043} 1044 1045// CollateErrs adds additional errors to the result and returns true if there is more than one 1046// error in the result. 1047func (r *TestResult) CollateErrs(errs []error) bool { 1048 r.Errs = append(r.Errs, errs...) 1049 return len(r.Errs) > 0 1050} 1051