1// Copyright 2017 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 "bytes" 19 "fmt" 20 "path/filepath" 21 "regexp" 22 "sort" 23 "strings" 24 "sync" 25 "testing" 26 27 mkparser "android/soong/androidmk/parser" 28 29 "github.com/google/blueprint" 30 "github.com/google/blueprint/proptools" 31) 32 33func NewTestContext(config Config) *TestContext { 34 namespaceExportFilter := func(namespace *Namespace) bool { 35 return true 36 } 37 38 nameResolver := NewNameResolver(namespaceExportFilter) 39 ctx := &TestContext{ 40 Context: &Context{blueprint.NewContext(), config}, 41 NameResolver: nameResolver, 42 } 43 44 ctx.SetNameInterface(nameResolver) 45 46 ctx.postDeps = append(ctx.postDeps, registerPathDepsMutator) 47 48 ctx.SetFs(ctx.config.fs) 49 if ctx.config.mockBpList != "" { 50 ctx.SetModuleListFile(ctx.config.mockBpList) 51 } 52 53 return ctx 54} 55 56var PrepareForTestWithArchMutator = GroupFixturePreparers( 57 // Configure architecture targets in the fixture config. 58 FixtureModifyConfig(modifyTestConfigToSupportArchMutator), 59 60 // Add the arch mutator to the context. 61 FixtureRegisterWithContext(func(ctx RegistrationContext) { 62 ctx.PreDepsMutators(registerArchMutator) 63 }), 64) 65 66var PrepareForTestWithDefaults = FixtureRegisterWithContext(func(ctx RegistrationContext) { 67 ctx.PreArchMutators(RegisterDefaultsPreArchMutators) 68}) 69 70var PrepareForTestWithComponentsMutator = FixtureRegisterWithContext(func(ctx RegistrationContext) { 71 ctx.PreArchMutators(RegisterComponentsMutator) 72}) 73 74var PrepareForTestWithPrebuilts = FixtureRegisterWithContext(RegisterPrebuiltMutators) 75 76var PrepareForTestWithOverrides = FixtureRegisterWithContext(func(ctx RegistrationContext) { 77 ctx.PostDepsMutators(RegisterOverridePostDepsMutators) 78}) 79 80var PrepareForTestWithLicenses = GroupFixturePreparers( 81 FixtureRegisterWithContext(RegisterLicenseKindBuildComponents), 82 FixtureRegisterWithContext(RegisterLicenseBuildComponents), 83 FixtureRegisterWithContext(registerLicenseMutators), 84) 85 86func registerLicenseMutators(ctx RegistrationContext) { 87 ctx.PreArchMutators(RegisterLicensesPackageMapper) 88 ctx.PreArchMutators(RegisterLicensesPropertyGatherer) 89 ctx.PostDepsMutators(RegisterLicensesDependencyChecker) 90} 91 92var PrepareForTestWithLicenseDefaultModules = GroupFixturePreparers( 93 FixtureAddTextFile("build/soong/licenses/Android.bp", ` 94 license { 95 name: "Android-Apache-2.0", 96 package_name: "Android", 97 license_kinds: ["SPDX-license-identifier-Apache-2.0"], 98 copyright_notice: "Copyright (C) The Android Open Source Project", 99 license_text: ["LICENSE"], 100 } 101 102 license_kind { 103 name: "SPDX-license-identifier-Apache-2.0", 104 conditions: ["notice"], 105 url: "https://spdx.org/licenses/Apache-2.0.html", 106 } 107 108 license_kind { 109 name: "legacy_unencumbered", 110 conditions: ["unencumbered"], 111 } 112 `), 113 FixtureAddFile("build/soong/licenses/LICENSE", nil), 114) 115 116var PrepareForTestWithNamespace = FixtureRegisterWithContext(func(ctx RegistrationContext) { 117 registerNamespaceBuildComponents(ctx) 118 ctx.PreArchMutators(RegisterNamespaceMutator) 119}) 120 121var PrepareForTestWithMakevars = FixtureRegisterWithContext(func(ctx RegistrationContext) { 122 ctx.RegisterSingletonType("makevars", makeVarsSingletonFunc) 123}) 124 125// Test fixture preparer that will register most java build components. 126// 127// Singletons and mutators should only be added here if they are needed for a majority of java 128// module types, otherwise they should be added under a separate preparer to allow them to be 129// selected only when needed to reduce test execution time. 130// 131// Module types do not have much of an overhead unless they are used so this should include as many 132// module types as possible. The exceptions are those module types that require mutators and/or 133// singletons in order to function in which case they should be kept together in a separate 134// preparer. 135// 136// The mutators in this group were chosen because they are needed by the vast majority of tests. 137var PrepareForTestWithAndroidBuildComponents = GroupFixturePreparers( 138 // Sorted alphabetically as the actual order does not matter as tests automatically enforce the 139 // correct order. 140 PrepareForTestWithArchMutator, 141 PrepareForTestWithComponentsMutator, 142 PrepareForTestWithDefaults, 143 PrepareForTestWithFilegroup, 144 PrepareForTestWithOverrides, 145 PrepareForTestWithPackageModule, 146 PrepareForTestWithPrebuilts, 147 PrepareForTestWithVisibility, 148) 149 150// Prepares an integration test with all build components from the android package. 151// 152// This should only be used by tests that want to run with as much of the build enabled as possible. 153var PrepareForIntegrationTestWithAndroid = GroupFixturePreparers( 154 PrepareForTestWithAndroidBuildComponents, 155) 156 157// Prepares a test that may be missing dependencies by setting allow_missing_dependencies to 158// true. 159var PrepareForTestWithAllowMissingDependencies = GroupFixturePreparers( 160 FixtureModifyProductVariables(func(variables FixtureProductVariables) { 161 variables.Allow_missing_dependencies = proptools.BoolPtr(true) 162 }), 163 FixtureModifyContext(func(ctx *TestContext) { 164 ctx.SetAllowMissingDependencies(true) 165 }), 166) 167 168// Prepares a test that disallows non-existent paths. 169var PrepareForTestDisallowNonExistentPaths = FixtureModifyConfig(func(config Config) { 170 config.TestAllowNonExistentPaths = false 171}) 172 173func NewTestArchContext(config Config) *TestContext { 174 ctx := NewTestContext(config) 175 ctx.preDeps = append(ctx.preDeps, registerArchMutator) 176 return ctx 177} 178 179type TestContext struct { 180 *Context 181 preArch, preDeps, postDeps, finalDeps []RegisterMutatorFunc 182 bp2buildPreArch, bp2buildMutators []RegisterMutatorFunc 183 NameResolver *NameResolver 184 185 // The list of pre-singletons and singletons registered for the test. 186 preSingletons, singletons sortableComponents 187 188 // The order in which the pre-singletons, mutators and singletons will be run in this test 189 // context; for debugging. 190 preSingletonOrder, mutatorOrder, singletonOrder []string 191} 192 193func (ctx *TestContext) PreArchMutators(f RegisterMutatorFunc) { 194 ctx.preArch = append(ctx.preArch, f) 195} 196 197func (ctx *TestContext) HardCodedPreArchMutators(f RegisterMutatorFunc) { 198 // Register mutator function as normal for testing. 199 ctx.PreArchMutators(f) 200} 201 202func (ctx *TestContext) PreDepsMutators(f RegisterMutatorFunc) { 203 ctx.preDeps = append(ctx.preDeps, f) 204} 205 206func (ctx *TestContext) PostDepsMutators(f RegisterMutatorFunc) { 207 ctx.postDeps = append(ctx.postDeps, f) 208} 209 210func (ctx *TestContext) FinalDepsMutators(f RegisterMutatorFunc) { 211 ctx.finalDeps = append(ctx.finalDeps, f) 212} 213 214func (ctx *TestContext) RegisterBp2BuildConfig(config bp2BuildConversionAllowlist) { 215 ctx.config.bp2buildPackageConfig = config 216} 217 218// PreArchBp2BuildMutators adds mutators to be register for converting Android Blueprint modules 219// into Bazel BUILD targets that should run prior to deps and conversion. 220func (ctx *TestContext) PreArchBp2BuildMutators(f RegisterMutatorFunc) { 221 ctx.bp2buildPreArch = append(ctx.bp2buildPreArch, f) 222} 223 224// registeredComponentOrder defines the order in which a sortableComponent type is registered at 225// runtime and provides support for reordering the components registered for a test in the same 226// way. 227type registeredComponentOrder struct { 228 // The name of the component type, used for error messages. 229 componentType string 230 231 // The names of the registered components in the order in which they were registered. 232 namesInOrder []string 233 234 // Maps from the component name to its position in the runtime ordering. 235 namesToIndex map[string]int 236 237 // A function that defines the order between two named components that can be used to sort a slice 238 // of component names into the same order as they appear in namesInOrder. 239 less func(string, string) bool 240} 241 242// registeredComponentOrderFromExistingOrder takes an existing slice of sortableComponents and 243// creates a registeredComponentOrder that contains a less function that can be used to sort a 244// subset of that list of names so it is in the same order as the original sortableComponents. 245func registeredComponentOrderFromExistingOrder(componentType string, existingOrder sortableComponents) registeredComponentOrder { 246 // Only the names from the existing order are needed for this so create a list of component names 247 // in the correct order. 248 namesInOrder := componentsToNames(existingOrder) 249 250 // Populate the map from name to position in the list. 251 nameToIndex := make(map[string]int) 252 for i, n := range namesInOrder { 253 nameToIndex[n] = i 254 } 255 256 // A function to use to map from a name to an index in the original order. 257 indexOf := func(name string) int { 258 index, ok := nameToIndex[name] 259 if !ok { 260 // Should never happen as tests that use components that are not known at runtime do not sort 261 // so should never use this function. 262 panic(fmt.Errorf("internal error: unknown %s %q should be one of %s", componentType, name, strings.Join(namesInOrder, ", "))) 263 } 264 return index 265 } 266 267 // The less function. 268 less := func(n1, n2 string) bool { 269 i1 := indexOf(n1) 270 i2 := indexOf(n2) 271 return i1 < i2 272 } 273 274 return registeredComponentOrder{ 275 componentType: componentType, 276 namesInOrder: namesInOrder, 277 namesToIndex: nameToIndex, 278 less: less, 279 } 280} 281 282// componentsToNames maps from the slice of components to a slice of their names. 283func componentsToNames(components sortableComponents) []string { 284 names := make([]string, len(components)) 285 for i, c := range components { 286 names[i] = c.componentName() 287 } 288 return names 289} 290 291// enforceOrdering enforces the supplied components are in the same order as is defined in this 292// object. 293// 294// If the supplied components contains any components that are not registered at runtime, i.e. test 295// specific components, then it is impossible to sort them into an order that both matches the 296// runtime and also preserves the implicit ordering defined in the test. In that case it will not 297// sort the components, instead it will just check that the components are in the correct order. 298// 299// Otherwise, this will sort the supplied components in place. 300func (o *registeredComponentOrder) enforceOrdering(components sortableComponents) { 301 // Check to see if the list of components contains any components that are 302 // not registered at runtime. 303 var unknownComponents []string 304 testOrder := componentsToNames(components) 305 for _, name := range testOrder { 306 if _, ok := o.namesToIndex[name]; !ok { 307 unknownComponents = append(unknownComponents, name) 308 break 309 } 310 } 311 312 // If the slice contains some unknown components then it is not possible to 313 // sort them into an order that matches the runtime while also preserving the 314 // order expected from the test, so in that case don't sort just check that 315 // the order of the known mutators does match. 316 if len(unknownComponents) > 0 { 317 // Check order. 318 o.checkTestOrder(testOrder, unknownComponents) 319 } else { 320 // Sort the components. 321 sort.Slice(components, func(i, j int) bool { 322 n1 := components[i].componentName() 323 n2 := components[j].componentName() 324 return o.less(n1, n2) 325 }) 326 } 327} 328 329// checkTestOrder checks that the supplied testOrder matches the one defined by this object, 330// panicking if it does not. 331func (o *registeredComponentOrder) checkTestOrder(testOrder []string, unknownComponents []string) { 332 lastMatchingTest := -1 333 matchCount := 0 334 // Take a copy of the runtime order as it is modified during the comparison. 335 runtimeOrder := append([]string(nil), o.namesInOrder...) 336 componentType := o.componentType 337 for i, j := 0, 0; i < len(testOrder) && j < len(runtimeOrder); { 338 test := testOrder[i] 339 runtime := runtimeOrder[j] 340 341 if test == runtime { 342 testOrder[i] = test + fmt.Sprintf(" <-- matched with runtime %s %d", componentType, j) 343 runtimeOrder[j] = runtime + fmt.Sprintf(" <-- matched with test %s %d", componentType, i) 344 lastMatchingTest = i 345 i += 1 346 j += 1 347 matchCount += 1 348 } else if _, ok := o.namesToIndex[test]; !ok { 349 // The test component is not registered globally so assume it is the correct place, treat it 350 // as having matched and skip it. 351 i += 1 352 matchCount += 1 353 } else { 354 // Assume that the test list is in the same order as the runtime list but the runtime list 355 // contains some components that are not present in the tests. So, skip the runtime component 356 // to try and find the next one that matches the current test component. 357 j += 1 358 } 359 } 360 361 // If every item in the test order was either test specific or matched one in the runtime then 362 // it is in the correct order. Otherwise, it was not so fail. 363 if matchCount != len(testOrder) { 364 // The test component names were not all matched with a runtime component name so there must 365 // either be a component present in the test that is not present in the runtime or they must be 366 // in the wrong order. 367 testOrder[lastMatchingTest+1] = testOrder[lastMatchingTest+1] + " <--- unmatched" 368 panic(fmt.Errorf("the tests uses test specific components %q and so cannot be automatically sorted."+ 369 " Unfortunately it uses %s components in the wrong order.\n"+ 370 "test order:\n %s\n"+ 371 "runtime order\n %s\n", 372 SortedUniqueStrings(unknownComponents), 373 componentType, 374 strings.Join(testOrder, "\n "), 375 strings.Join(runtimeOrder, "\n "))) 376 } 377} 378 379// registrationSorter encapsulates the information needed to ensure that the test mutators are 380// registered, and thereby executed, in the same order as they are at runtime. 381// 382// It MUST be populated lazily AFTER all package initialization has been done otherwise it will 383// only define the order for a subset of all the registered build components that are available for 384// the packages being tested. 385// 386// e.g if this is initialized during say the cc package initialization then any tests run in the 387// java package will not sort build components registered by the java package's init() functions. 388type registrationSorter struct { 389 // Used to ensure that this is only created once. 390 once sync.Once 391 392 // The order of pre-singletons 393 preSingletonOrder registeredComponentOrder 394 395 // The order of mutators 396 mutatorOrder registeredComponentOrder 397 398 // The order of singletons 399 singletonOrder registeredComponentOrder 400} 401 402// populate initializes this structure from globally registered build components. 403// 404// Only the first call has any effect. 405func (s *registrationSorter) populate() { 406 s.once.Do(func() { 407 // Create an ordering from the globally registered pre-singletons. 408 s.preSingletonOrder = registeredComponentOrderFromExistingOrder("pre-singleton", preSingletons) 409 410 // Created an ordering from the globally registered mutators. 411 globallyRegisteredMutators := collateGloballyRegisteredMutators() 412 s.mutatorOrder = registeredComponentOrderFromExistingOrder("mutator", globallyRegisteredMutators) 413 414 // Create an ordering from the globally registered singletons. 415 globallyRegisteredSingletons := collateGloballyRegisteredSingletons() 416 s.singletonOrder = registeredComponentOrderFromExistingOrder("singleton", globallyRegisteredSingletons) 417 }) 418} 419 420// Provides support for enforcing the same order in which build components are registered globally 421// to the order in which they are registered during tests. 422// 423// MUST only be accessed via the globallyRegisteredComponentsOrder func. 424var globalRegistrationSorter registrationSorter 425 426// globallyRegisteredComponentsOrder returns the globalRegistrationSorter after ensuring it is 427// correctly populated. 428func globallyRegisteredComponentsOrder() *registrationSorter { 429 globalRegistrationSorter.populate() 430 return &globalRegistrationSorter 431} 432 433func (ctx *TestContext) Register() { 434 globalOrder := globallyRegisteredComponentsOrder() 435 436 // Ensure that the pre-singletons used in the test are in the same order as they are used at 437 // runtime. 438 globalOrder.preSingletonOrder.enforceOrdering(ctx.preSingletons) 439 ctx.preSingletons.registerAll(ctx.Context) 440 441 mutators := collateRegisteredMutators(ctx.preArch, ctx.preDeps, ctx.postDeps, ctx.finalDeps) 442 // Ensure that the mutators used in the test are in the same order as they are used at runtime. 443 globalOrder.mutatorOrder.enforceOrdering(mutators) 444 mutators.registerAll(ctx.Context) 445 446 // Ensure that the singletons used in the test are in the same order as they are used at runtime. 447 globalOrder.singletonOrder.enforceOrdering(ctx.singletons) 448 ctx.singletons.registerAll(ctx.Context) 449 450 // Save the sorted components order away to make them easy to access while debugging. 451 ctx.preSingletonOrder = componentsToNames(preSingletons) 452 ctx.mutatorOrder = componentsToNames(mutators) 453 ctx.singletonOrder = componentsToNames(singletons) 454} 455 456// RegisterForBazelConversion prepares a test context for bp2build conversion. 457func (ctx *TestContext) RegisterForBazelConversion() { 458 ctx.SetRunningAsBp2build() 459 RegisterMutatorsForBazelConversion(ctx.Context, ctx.bp2buildPreArch) 460} 461 462func (ctx *TestContext) ParseFileList(rootDir string, filePaths []string) (deps []string, errs []error) { 463 // This function adapts the old style ParseFileList calls that are spread throughout the tests 464 // to the new style that takes a config. 465 return ctx.Context.ParseFileList(rootDir, filePaths, ctx.config) 466} 467 468func (ctx *TestContext) ParseBlueprintsFiles(rootDir string) (deps []string, errs []error) { 469 // This function adapts the old style ParseBlueprintsFiles calls that are spread throughout the 470 // tests to the new style that takes a config. 471 return ctx.Context.ParseBlueprintsFiles(rootDir, ctx.config) 472} 473 474func (ctx *TestContext) RegisterModuleType(name string, factory ModuleFactory) { 475 ctx.Context.RegisterModuleType(name, ModuleFactoryAdaptor(factory)) 476} 477 478func (ctx *TestContext) RegisterSingletonModuleType(name string, factory SingletonModuleFactory) { 479 s, m := SingletonModuleFactoryAdaptor(name, factory) 480 ctx.RegisterSingletonType(name, s) 481 ctx.RegisterModuleType(name, m) 482} 483 484func (ctx *TestContext) RegisterSingletonType(name string, factory SingletonFactory) { 485 ctx.singletons = append(ctx.singletons, newSingleton(name, factory)) 486} 487 488func (ctx *TestContext) RegisterPreSingletonType(name string, factory SingletonFactory) { 489 ctx.preSingletons = append(ctx.preSingletons, newPreSingleton(name, factory)) 490} 491 492// ModuleVariantForTests selects a specific variant of the module with the given 493// name by matching the variations map against the variations of each module 494// variant. A module variant matches the map if every variation that exists in 495// both have the same value. Both the module and the map are allowed to have 496// extra variations that the other doesn't have. Panics if not exactly one 497// module variant matches. 498func (ctx *TestContext) ModuleVariantForTests(name string, matchVariations map[string]string) TestingModule { 499 modules := []Module{} 500 ctx.VisitAllModules(func(m blueprint.Module) { 501 if ctx.ModuleName(m) == name { 502 am := m.(Module) 503 amMut := am.base().commonProperties.DebugMutators 504 amVar := am.base().commonProperties.DebugVariations 505 matched := true 506 for i, mut := range amMut { 507 if wantedVar, found := matchVariations[mut]; found && amVar[i] != wantedVar { 508 matched = false 509 break 510 } 511 } 512 if matched { 513 modules = append(modules, am) 514 } 515 } 516 }) 517 518 if len(modules) == 0 { 519 // Show all the modules or module variants that do exist. 520 var allModuleNames []string 521 var allVariants []string 522 ctx.VisitAllModules(func(m blueprint.Module) { 523 allModuleNames = append(allModuleNames, ctx.ModuleName(m)) 524 if ctx.ModuleName(m) == name { 525 allVariants = append(allVariants, m.(Module).String()) 526 } 527 }) 528 529 if len(allVariants) == 0 { 530 panic(fmt.Errorf("failed to find module %q. All modules:\n %s", 531 name, strings.Join(SortedUniqueStrings(allModuleNames), "\n "))) 532 } else { 533 sort.Strings(allVariants) 534 panic(fmt.Errorf("failed to find module %q matching %v. All variants:\n %s", 535 name, matchVariations, strings.Join(allVariants, "\n "))) 536 } 537 } 538 539 if len(modules) > 1 { 540 moduleStrings := []string{} 541 for _, m := range modules { 542 moduleStrings = append(moduleStrings, m.String()) 543 } 544 sort.Strings(moduleStrings) 545 panic(fmt.Errorf("module %q has more than one variant that match %v:\n %s", 546 name, matchVariations, strings.Join(moduleStrings, "\n "))) 547 } 548 549 return newTestingModule(ctx.config, modules[0]) 550} 551 552func (ctx *TestContext) ModuleForTests(name, variant string) TestingModule { 553 var module Module 554 ctx.VisitAllModules(func(m blueprint.Module) { 555 if ctx.ModuleName(m) == name && ctx.ModuleSubDir(m) == variant { 556 module = m.(Module) 557 } 558 }) 559 560 if module == nil { 561 // find all the modules that do exist 562 var allModuleNames []string 563 var allVariants []string 564 ctx.VisitAllModules(func(m blueprint.Module) { 565 allModuleNames = append(allModuleNames, ctx.ModuleName(m)) 566 if ctx.ModuleName(m) == name { 567 allVariants = append(allVariants, ctx.ModuleSubDir(m)) 568 } 569 }) 570 sort.Strings(allVariants) 571 572 if len(allVariants) == 0 { 573 panic(fmt.Errorf("failed to find module %q. All modules:\n %s", 574 name, strings.Join(SortedUniqueStrings(allModuleNames), "\n "))) 575 } else { 576 panic(fmt.Errorf("failed to find module %q variant %q. All variants:\n %s", 577 name, variant, strings.Join(allVariants, "\n "))) 578 } 579 } 580 581 return newTestingModule(ctx.config, module) 582} 583 584func (ctx *TestContext) ModuleVariantsForTests(name string) []string { 585 var variants []string 586 ctx.VisitAllModules(func(m blueprint.Module) { 587 if ctx.ModuleName(m) == name { 588 variants = append(variants, ctx.ModuleSubDir(m)) 589 } 590 }) 591 return variants 592} 593 594// SingletonForTests returns a TestingSingleton for the singleton registered with the given name. 595func (ctx *TestContext) SingletonForTests(name string) TestingSingleton { 596 allSingletonNames := []string{} 597 for _, s := range ctx.Singletons() { 598 n := ctx.SingletonName(s) 599 if n == name { 600 return TestingSingleton{ 601 baseTestingComponent: newBaseTestingComponent(ctx.config, s.(testBuildProvider)), 602 singleton: s.(*singletonAdaptor).Singleton, 603 } 604 } 605 allSingletonNames = append(allSingletonNames, n) 606 } 607 608 panic(fmt.Errorf("failed to find singleton %q."+ 609 "\nall singletons: %v", name, allSingletonNames)) 610} 611 612type InstallMakeRule struct { 613 Target string 614 Deps []string 615 OrderOnlyDeps []string 616} 617 618func parseMkRules(t *testing.T, config Config, nodes []mkparser.Node) []InstallMakeRule { 619 var rules []InstallMakeRule 620 for _, node := range nodes { 621 if mkParserRule, ok := node.(*mkparser.Rule); ok { 622 var rule InstallMakeRule 623 624 if targets := mkParserRule.Target.Words(); len(targets) == 0 { 625 t.Fatalf("no targets for rule %s", mkParserRule.Dump()) 626 } else if len(targets) > 1 { 627 t.Fatalf("unsupported multiple targets for rule %s", mkParserRule.Dump()) 628 } else if !targets[0].Const() { 629 t.Fatalf("unsupported non-const target for rule %s", mkParserRule.Dump()) 630 } else { 631 rule.Target = normalizeStringRelativeToTop(config, targets[0].Value(nil)) 632 } 633 634 prereqList := &rule.Deps 635 for _, prereq := range mkParserRule.Prerequisites.Words() { 636 if !prereq.Const() { 637 t.Fatalf("unsupported non-const prerequisite for rule %s", mkParserRule.Dump()) 638 } 639 640 if prereq.Value(nil) == "|" { 641 prereqList = &rule.OrderOnlyDeps 642 continue 643 } 644 645 *prereqList = append(*prereqList, normalizeStringRelativeToTop(config, prereq.Value(nil))) 646 } 647 648 rules = append(rules, rule) 649 } 650 } 651 652 return rules 653} 654 655func (ctx *TestContext) InstallMakeRulesForTesting(t *testing.T) []InstallMakeRule { 656 installs := ctx.SingletonForTests("makevars").Singleton().(*makeVarsSingleton).installsForTesting 657 buf := bytes.NewBuffer(append([]byte(nil), installs...)) 658 parser := mkparser.NewParser("makevars", buf) 659 660 nodes, errs := parser.Parse() 661 if len(errs) > 0 { 662 t.Fatalf("error parsing install rules: %s", errs[0]) 663 } 664 665 return parseMkRules(t, ctx.config, nodes) 666} 667 668func (ctx *TestContext) Config() Config { 669 return ctx.config 670} 671 672type testBuildProvider interface { 673 BuildParamsForTests() []BuildParams 674 RuleParamsForTests() map[blueprint.Rule]blueprint.RuleParams 675} 676 677type TestingBuildParams struct { 678 BuildParams 679 RuleParams blueprint.RuleParams 680 681 config Config 682} 683 684// RelativeToTop creates a new instance of this which has had any usages of the current test's 685// temporary and test specific build directory replaced with a path relative to the notional top. 686// 687// The parts of this structure which are changed are: 688// * BuildParams 689// * Args 690// * All Path, Paths, WritablePath and WritablePaths fields. 691// 692// * RuleParams 693// * Command 694// * Depfile 695// * Rspfile 696// * RspfileContent 697// * SymlinkOutputs 698// * CommandDeps 699// * CommandOrderOnly 700// 701// See PathRelativeToTop for more details. 702// 703// deprecated: this is no longer needed as TestingBuildParams are created in this form. 704func (p TestingBuildParams) RelativeToTop() TestingBuildParams { 705 // If this is not a valid params then just return it back. That will make it easy to use with the 706 // Maybe...() methods. 707 if p.Rule == nil { 708 return p 709 } 710 if p.config.config == nil { 711 return p 712 } 713 // Take a copy of the build params and replace any args that contains test specific temporary 714 // paths with paths relative to the top. 715 bparams := p.BuildParams 716 bparams.Depfile = normalizeWritablePathRelativeToTop(bparams.Depfile) 717 bparams.Output = normalizeWritablePathRelativeToTop(bparams.Output) 718 bparams.Outputs = bparams.Outputs.RelativeToTop() 719 bparams.SymlinkOutput = normalizeWritablePathRelativeToTop(bparams.SymlinkOutput) 720 bparams.SymlinkOutputs = bparams.SymlinkOutputs.RelativeToTop() 721 bparams.ImplicitOutput = normalizeWritablePathRelativeToTop(bparams.ImplicitOutput) 722 bparams.ImplicitOutputs = bparams.ImplicitOutputs.RelativeToTop() 723 bparams.Input = normalizePathRelativeToTop(bparams.Input) 724 bparams.Inputs = bparams.Inputs.RelativeToTop() 725 bparams.Implicit = normalizePathRelativeToTop(bparams.Implicit) 726 bparams.Implicits = bparams.Implicits.RelativeToTop() 727 bparams.OrderOnly = bparams.OrderOnly.RelativeToTop() 728 bparams.Validation = normalizePathRelativeToTop(bparams.Validation) 729 bparams.Validations = bparams.Validations.RelativeToTop() 730 bparams.Args = normalizeStringMapRelativeToTop(p.config, bparams.Args) 731 732 // Ditto for any fields in the RuleParams. 733 rparams := p.RuleParams 734 rparams.Command = normalizeStringRelativeToTop(p.config, rparams.Command) 735 rparams.Depfile = normalizeStringRelativeToTop(p.config, rparams.Depfile) 736 rparams.Rspfile = normalizeStringRelativeToTop(p.config, rparams.Rspfile) 737 rparams.RspfileContent = normalizeStringRelativeToTop(p.config, rparams.RspfileContent) 738 rparams.SymlinkOutputs = normalizeStringArrayRelativeToTop(p.config, rparams.SymlinkOutputs) 739 rparams.CommandDeps = normalizeStringArrayRelativeToTop(p.config, rparams.CommandDeps) 740 rparams.CommandOrderOnly = normalizeStringArrayRelativeToTop(p.config, rparams.CommandOrderOnly) 741 742 return TestingBuildParams{ 743 BuildParams: bparams, 744 RuleParams: rparams, 745 } 746} 747 748func normalizeWritablePathRelativeToTop(path WritablePath) WritablePath { 749 if path == nil { 750 return nil 751 } 752 return path.RelativeToTop().(WritablePath) 753} 754 755func normalizePathRelativeToTop(path Path) Path { 756 if path == nil { 757 return nil 758 } 759 return path.RelativeToTop() 760} 761 762// baseTestingComponent provides functionality common to both TestingModule and TestingSingleton. 763type baseTestingComponent struct { 764 config Config 765 provider testBuildProvider 766} 767 768func newBaseTestingComponent(config Config, provider testBuildProvider) baseTestingComponent { 769 return baseTestingComponent{config, provider} 770} 771 772// A function that will normalize a string containing paths, e.g. ninja command, by replacing 773// any references to the test specific temporary build directory that changes with each run to a 774// fixed path relative to a notional top directory. 775// 776// This is similar to StringPathRelativeToTop except that assumes the string is a single path 777// containing at most one instance of the temporary build directory at the start of the path while 778// this assumes that there can be any number at any position. 779func normalizeStringRelativeToTop(config Config, s string) string { 780 // The soongOutDir usually looks something like: /tmp/testFoo2345/001 781 // 782 // Replace any usage of the soongOutDir with out/soong, e.g. replace "/tmp/testFoo2345/001" with 783 // "out/soong". 784 outSoongDir := filepath.Clean(config.soongOutDir) 785 re := regexp.MustCompile(`\Q` + outSoongDir + `\E\b`) 786 s = re.ReplaceAllString(s, "out/soong") 787 788 // Replace any usage of the soongOutDir/.. with out, e.g. replace "/tmp/testFoo2345" with 789 // "out". This must come after the previous replacement otherwise this would replace 790 // "/tmp/testFoo2345/001" with "out/001" instead of "out/soong". 791 outDir := filepath.Dir(outSoongDir) 792 re = regexp.MustCompile(`\Q` + outDir + `\E\b`) 793 s = re.ReplaceAllString(s, "out") 794 795 return s 796} 797 798// normalizeStringArrayRelativeToTop creates a new slice constructed by applying 799// normalizeStringRelativeToTop to each item in the slice. 800func normalizeStringArrayRelativeToTop(config Config, slice []string) []string { 801 newSlice := make([]string, len(slice)) 802 for i, s := range slice { 803 newSlice[i] = normalizeStringRelativeToTop(config, s) 804 } 805 return newSlice 806} 807 808// normalizeStringMapRelativeToTop creates a new map constructed by applying 809// normalizeStringRelativeToTop to each value in the map. 810func normalizeStringMapRelativeToTop(config Config, m map[string]string) map[string]string { 811 newMap := map[string]string{} 812 for k, v := range m { 813 newMap[k] = normalizeStringRelativeToTop(config, v) 814 } 815 return newMap 816} 817 818func (b baseTestingComponent) newTestingBuildParams(bparams BuildParams) TestingBuildParams { 819 return TestingBuildParams{ 820 config: b.config, 821 BuildParams: bparams, 822 RuleParams: b.provider.RuleParamsForTests()[bparams.Rule], 823 }.RelativeToTop() 824} 825 826func (b baseTestingComponent) maybeBuildParamsFromRule(rule string) (TestingBuildParams, []string) { 827 var searchedRules []string 828 buildParams := b.provider.BuildParamsForTests() 829 for _, p := range buildParams { 830 ruleAsString := p.Rule.String() 831 searchedRules = append(searchedRules, ruleAsString) 832 if strings.Contains(ruleAsString, rule) { 833 return b.newTestingBuildParams(p), searchedRules 834 } 835 } 836 return TestingBuildParams{}, searchedRules 837} 838 839func (b baseTestingComponent) buildParamsFromRule(rule string) TestingBuildParams { 840 p, searchRules := b.maybeBuildParamsFromRule(rule) 841 if p.Rule == nil { 842 panic(fmt.Errorf("couldn't find rule %q.\nall rules:\n%s", rule, strings.Join(searchRules, "\n"))) 843 } 844 return p 845} 846 847func (b baseTestingComponent) maybeBuildParamsFromDescription(desc string) (TestingBuildParams, []string) { 848 var searchedDescriptions []string 849 for _, p := range b.provider.BuildParamsForTests() { 850 searchedDescriptions = append(searchedDescriptions, p.Description) 851 if strings.Contains(p.Description, desc) { 852 return b.newTestingBuildParams(p), searchedDescriptions 853 } 854 } 855 return TestingBuildParams{}, searchedDescriptions 856} 857 858func (b baseTestingComponent) buildParamsFromDescription(desc string) TestingBuildParams { 859 p, searchedDescriptions := b.maybeBuildParamsFromDescription(desc) 860 if p.Rule == nil { 861 panic(fmt.Errorf("couldn't find description %q\nall descriptions:\n%s", desc, strings.Join(searchedDescriptions, "\n"))) 862 } 863 return p 864} 865 866func (b baseTestingComponent) maybeBuildParamsFromOutput(file string) (TestingBuildParams, []string) { 867 searchedOutputs := WritablePaths(nil) 868 for _, p := range b.provider.BuildParamsForTests() { 869 outputs := append(WritablePaths(nil), p.Outputs...) 870 outputs = append(outputs, p.ImplicitOutputs...) 871 if p.Output != nil { 872 outputs = append(outputs, p.Output) 873 } 874 for _, f := range outputs { 875 if f.String() == file || f.Rel() == file || PathRelativeToTop(f) == file { 876 return b.newTestingBuildParams(p), nil 877 } 878 searchedOutputs = append(searchedOutputs, f) 879 } 880 } 881 882 formattedOutputs := []string{} 883 for _, f := range searchedOutputs { 884 formattedOutputs = append(formattedOutputs, 885 fmt.Sprintf("%s (rel=%s)", PathRelativeToTop(f), f.Rel())) 886 } 887 888 return TestingBuildParams{}, formattedOutputs 889} 890 891func (b baseTestingComponent) buildParamsFromOutput(file string) TestingBuildParams { 892 p, searchedOutputs := b.maybeBuildParamsFromOutput(file) 893 if p.Rule == nil { 894 panic(fmt.Errorf("couldn't find output %q.\nall outputs:\n %s\n", 895 file, strings.Join(searchedOutputs, "\n "))) 896 } 897 return p 898} 899 900func (b baseTestingComponent) allOutputs() []string { 901 var outputFullPaths []string 902 for _, p := range b.provider.BuildParamsForTests() { 903 outputs := append(WritablePaths(nil), p.Outputs...) 904 outputs = append(outputs, p.ImplicitOutputs...) 905 if p.Output != nil { 906 outputs = append(outputs, p.Output) 907 } 908 outputFullPaths = append(outputFullPaths, outputs.Strings()...) 909 } 910 return outputFullPaths 911} 912 913// MaybeRule finds a call to ctx.Build with BuildParams.Rule set to a rule with the given name. Returns an empty 914// BuildParams if no rule is found. 915func (b baseTestingComponent) MaybeRule(rule string) TestingBuildParams { 916 r, _ := b.maybeBuildParamsFromRule(rule) 917 return r 918} 919 920// Rule finds a call to ctx.Build with BuildParams.Rule set to a rule with the given name. Panics if no rule is found. 921func (b baseTestingComponent) Rule(rule string) TestingBuildParams { 922 return b.buildParamsFromRule(rule) 923} 924 925// MaybeDescription finds a call to ctx.Build with BuildParams.Description set to a the given string. Returns an empty 926// BuildParams if no rule is found. 927func (b baseTestingComponent) MaybeDescription(desc string) TestingBuildParams { 928 p, _ := b.maybeBuildParamsFromDescription(desc) 929 return p 930} 931 932// Description finds a call to ctx.Build with BuildParams.Description set to a the given string. Panics if no rule is 933// found. 934func (b baseTestingComponent) Description(desc string) TestingBuildParams { 935 return b.buildParamsFromDescription(desc) 936} 937 938// MaybeOutput finds a call to ctx.Build with a BuildParams.Output or BuildParams.Outputs whose String() or Rel() 939// value matches the provided string. Returns an empty BuildParams if no rule is found. 940func (b baseTestingComponent) MaybeOutput(file string) TestingBuildParams { 941 p, _ := b.maybeBuildParamsFromOutput(file) 942 return p 943} 944 945// Output finds a call to ctx.Build with a BuildParams.Output or BuildParams.Outputs whose String() or Rel() 946// value matches the provided string. Panics if no rule is found. 947func (b baseTestingComponent) Output(file string) TestingBuildParams { 948 return b.buildParamsFromOutput(file) 949} 950 951// AllOutputs returns all 'BuildParams.Output's and 'BuildParams.Outputs's in their full path string forms. 952func (b baseTestingComponent) AllOutputs() []string { 953 return b.allOutputs() 954} 955 956// TestingModule is wrapper around an android.Module that provides methods to find information about individual 957// ctx.Build parameters for verification in tests. 958type TestingModule struct { 959 baseTestingComponent 960 module Module 961} 962 963func newTestingModule(config Config, module Module) TestingModule { 964 return TestingModule{ 965 newBaseTestingComponent(config, module), 966 module, 967 } 968} 969 970// Module returns the Module wrapped by the TestingModule. 971func (m TestingModule) Module() Module { 972 return m.module 973} 974 975// VariablesForTestsRelativeToTop returns a copy of the Module.VariablesForTests() with every value 976// having any temporary build dir usages replaced with paths relative to a notional top. 977func (m TestingModule) VariablesForTestsRelativeToTop() map[string]string { 978 return normalizeStringMapRelativeToTop(m.config, m.module.VariablesForTests()) 979} 980 981// OutputFiles calls OutputFileProducer.OutputFiles on the encapsulated module, exits the test 982// immediately if there is an error and otherwise returns the result of calling Paths.RelativeToTop 983// on the returned Paths. 984func (m TestingModule) OutputFiles(t *testing.T, tag string) Paths { 985 producer, ok := m.module.(OutputFileProducer) 986 if !ok { 987 t.Fatalf("%q must implement OutputFileProducer\n", m.module.Name()) 988 } 989 paths, err := producer.OutputFiles(tag) 990 if err != nil { 991 t.Fatal(err) 992 } 993 994 return paths.RelativeToTop() 995} 996 997// TestingSingleton is wrapper around an android.Singleton that provides methods to find information about individual 998// ctx.Build parameters for verification in tests. 999type TestingSingleton struct { 1000 baseTestingComponent 1001 singleton Singleton 1002} 1003 1004// Singleton returns the Singleton wrapped by the TestingSingleton. 1005func (s TestingSingleton) Singleton() Singleton { 1006 return s.singleton 1007} 1008 1009func FailIfErrored(t *testing.T, errs []error) { 1010 t.Helper() 1011 if len(errs) > 0 { 1012 for _, err := range errs { 1013 t.Error(err) 1014 } 1015 t.FailNow() 1016 } 1017} 1018 1019// Fail if no errors that matched the regular expression were found. 1020// 1021// Returns true if a matching error was found, false otherwise. 1022func FailIfNoMatchingErrors(t *testing.T, pattern string, errs []error) bool { 1023 t.Helper() 1024 1025 matcher, err := regexp.Compile(pattern) 1026 if err != nil { 1027 t.Fatalf("failed to compile regular expression %q because %s", pattern, err) 1028 } 1029 1030 found := false 1031 for _, err := range errs { 1032 if matcher.FindStringIndex(err.Error()) != nil { 1033 found = true 1034 break 1035 } 1036 } 1037 if !found { 1038 t.Errorf("missing the expected error %q (checked %d error(s))", pattern, len(errs)) 1039 for i, err := range errs { 1040 t.Errorf("errs[%d] = %q", i, err) 1041 } 1042 } 1043 1044 return found 1045} 1046 1047func CheckErrorsAgainstExpectations(t *testing.T, errs []error, expectedErrorPatterns []string) { 1048 t.Helper() 1049 1050 if expectedErrorPatterns == nil { 1051 FailIfErrored(t, errs) 1052 } else { 1053 for _, expectedError := range expectedErrorPatterns { 1054 FailIfNoMatchingErrors(t, expectedError, errs) 1055 } 1056 if len(errs) > len(expectedErrorPatterns) { 1057 t.Errorf("additional errors found, expected %d, found %d", 1058 len(expectedErrorPatterns), len(errs)) 1059 for i, expectedError := range expectedErrorPatterns { 1060 t.Errorf("expectedErrors[%d] = %s", i, expectedError) 1061 } 1062 for i, err := range errs { 1063 t.Errorf("errs[%d] = %s", i, err) 1064 } 1065 t.FailNow() 1066 } 1067 } 1068} 1069 1070func SetKatiEnabledForTests(config Config) { 1071 config.katiEnabled = true 1072} 1073 1074func AndroidMkEntriesForTest(t *testing.T, ctx *TestContext, mod blueprint.Module) []AndroidMkEntries { 1075 var p AndroidMkEntriesProvider 1076 var ok bool 1077 if p, ok = mod.(AndroidMkEntriesProvider); !ok { 1078 t.Errorf("module does not implement AndroidMkEntriesProvider: " + mod.Name()) 1079 } 1080 1081 entriesList := p.AndroidMkEntries() 1082 for i, _ := range entriesList { 1083 entriesList[i].fillInEntries(ctx, mod) 1084 } 1085 return entriesList 1086} 1087 1088func AndroidMkDataForTest(t *testing.T, ctx *TestContext, mod blueprint.Module) AndroidMkData { 1089 var p AndroidMkDataProvider 1090 var ok bool 1091 if p, ok = mod.(AndroidMkDataProvider); !ok { 1092 t.Errorf("module does not implement AndroidMkDataProvider: " + mod.Name()) 1093 } 1094 data := p.AndroidMk() 1095 data.fillInData(ctx, mod) 1096 return data 1097} 1098 1099// Normalize the path for testing. 1100// 1101// If the path is relative to the build directory then return the relative path 1102// to avoid tests having to deal with the dynamically generated build directory. 1103// 1104// Otherwise, return the supplied path as it is almost certainly a source path 1105// that is relative to the root of the source tree. 1106// 1107// The build and source paths should be distinguishable based on their contents. 1108// 1109// deprecated: use PathRelativeToTop instead as it handles make install paths and differentiates 1110// between output and source properly. 1111func NormalizePathForTesting(path Path) string { 1112 if path == nil { 1113 return "<nil path>" 1114 } 1115 p := path.String() 1116 if w, ok := path.(WritablePath); ok { 1117 rel, err := filepath.Rel(w.getSoongOutDir(), p) 1118 if err != nil { 1119 panic(err) 1120 } 1121 return rel 1122 } 1123 return p 1124} 1125 1126// NormalizePathsForTesting creates a slice of strings where each string is the result of applying 1127// NormalizePathForTesting to the corresponding Path in the input slice. 1128// 1129// deprecated: use PathsRelativeToTop instead as it handles make install paths and differentiates 1130// between output and source properly. 1131func NormalizePathsForTesting(paths Paths) []string { 1132 var result []string 1133 for _, path := range paths { 1134 relative := NormalizePathForTesting(path) 1135 result = append(result, relative) 1136 } 1137 return result 1138} 1139 1140// PathRelativeToTop returns a string representation of the path relative to a notional top 1141// directory. 1142// 1143// It return "<nil path>" if the supplied path is nil, otherwise it returns the result of calling 1144// Path.RelativeToTop to obtain a relative Path and then calling Path.String on that to get the 1145// string representation. 1146func PathRelativeToTop(path Path) string { 1147 if path == nil { 1148 return "<nil path>" 1149 } 1150 return path.RelativeToTop().String() 1151} 1152 1153// PathsRelativeToTop creates a slice of strings where each string is the result of applying 1154// PathRelativeToTop to the corresponding Path in the input slice. 1155func PathsRelativeToTop(paths Paths) []string { 1156 var result []string 1157 for _, path := range paths { 1158 relative := PathRelativeToTop(path) 1159 result = append(result, relative) 1160 } 1161 return result 1162} 1163 1164// StringPathRelativeToTop returns a string representation of the path relative to a notional top 1165// directory. 1166// 1167// See Path.RelativeToTop for more details as to what `relative to top` means. 1168// 1169// This is provided for processing paths that have already been converted into a string, e.g. paths 1170// in AndroidMkEntries structures. As a result it needs to be supplied the soong output dir against 1171// which it can try and relativize paths. PathRelativeToTop must be used for process Path objects. 1172func StringPathRelativeToTop(soongOutDir string, path string) string { 1173 ensureTestOnly() 1174 1175 // A relative path must be a source path so leave it as it is. 1176 if !filepath.IsAbs(path) { 1177 return path 1178 } 1179 1180 // Check to see if the path is relative to the soong out dir. 1181 rel, isRel, err := maybeRelErr(soongOutDir, path) 1182 if err != nil { 1183 panic(err) 1184 } 1185 1186 if isRel { 1187 // The path is in the soong out dir so indicate that in the relative path. 1188 return filepath.Join("out/soong", rel) 1189 } 1190 1191 // Check to see if the path is relative to the top level out dir. 1192 outDir := filepath.Dir(soongOutDir) 1193 rel, isRel, err = maybeRelErr(outDir, path) 1194 if err != nil { 1195 panic(err) 1196 } 1197 1198 if isRel { 1199 // The path is in the out dir so indicate that in the relative path. 1200 return filepath.Join("out", rel) 1201 } 1202 1203 // This should never happen. 1204 panic(fmt.Errorf("internal error: absolute path %s is not relative to the out dir %s", path, outDir)) 1205} 1206 1207// StringPathsRelativeToTop creates a slice of strings where each string is the result of applying 1208// StringPathRelativeToTop to the corresponding string path in the input slice. 1209// 1210// This is provided for processing paths that have already been converted into a string, e.g. paths 1211// in AndroidMkEntries structures. As a result it needs to be supplied the soong output dir against 1212// which it can try and relativize paths. PathsRelativeToTop must be used for process Paths objects. 1213func StringPathsRelativeToTop(soongOutDir string, paths []string) []string { 1214 var result []string 1215 for _, path := range paths { 1216 relative := StringPathRelativeToTop(soongOutDir, path) 1217 result = append(result, relative) 1218 } 1219 return result 1220} 1221 1222// StringRelativeToTop will normalize a string containing paths, e.g. ninja command, by replacing 1223// any references to the test specific temporary build directory that changes with each run to a 1224// fixed path relative to a notional top directory. 1225// 1226// This is similar to StringPathRelativeToTop except that assumes the string is a single path 1227// containing at most one instance of the temporary build directory at the start of the path while 1228// this assumes that there can be any number at any position. 1229func StringRelativeToTop(config Config, command string) string { 1230 return normalizeStringRelativeToTop(config, command) 1231} 1232 1233// StringsRelativeToTop will return a new slice such that each item in the new slice is the result 1234// of calling StringRelativeToTop on the corresponding item in the input slice. 1235func StringsRelativeToTop(config Config, command []string) []string { 1236 return normalizeStringArrayRelativeToTop(config, command) 1237} 1238