diff options
| author | mosimchah <mosimchah@gmail.com> | 2025-12-02 09:27:38 -0500 |
|---|---|---|
| committer | mosimchah <mosimchah@gmail.com> | 2025-12-02 09:27:38 -0500 |
| commit | c7bade461dc55726f62997d13a48582f7c4b4655 (patch) | |
| tree | ea0588da76060a2038f54f67efd046ca77634b10 /android/testing.go | |
| parent | 0f5414d19317805e8bbbe7c4db5f0fd78769bad5 (diff) | |
| parent | 89d78cff8b00d3b20a90074635c3fe5a2ee49474 (diff) | |
Merge branch 'lineage-23.1' of https://github.com/LineageOS/android_build_soong into HEADw16.1
* 'lineage-23.1' of https://github.com/LineageOS/android_build_soong: (528 commits)
Revert "install_symlink: Make symlink target configurable"
Reapply "Clear as much of cc.Module as possible after GenerateBuildActions"
Revert "rust: config: Fix missing CPU variant LD flags in Rust"
Rename build-flag in outdir
Revert^4 "cipd: Default CIPD proxy server to on, add opt-out"
Convert check-vintf-all to phony with actions
Create a partial implementation of check-vintf-all for soong-only
Configure RBE rust pool based on build variant
Revert^3 "Add sdk version check to arr"
Add jdk.internal.invoke to the allowlist
Make droid always depend on symbols zip
Import Device and Odm skus
Don't install gob_gen in Soong
Remove bazel reference from run_integration_tests.sh
Fix bootstrap_test.sh
Don't panic in aconfig libraries when AllowMissingDependencies is set
Avoid returning nil paths from PathForModuleSrc
Revert "Flag controled clang version"
Rework module target dependencies on required deps
Revert^2 "Add sdk version check to arr"
...
Change-Id: I6e9a63fa14fda917a42e426e5dcebbad7f67e1de
Diffstat (limited to 'android/testing.go')
| -rw-r--r-- | android/testing.go | 210 |
1 files changed, 196 insertions, 14 deletions
diff --git a/android/testing.go b/android/testing.go index d2949ec8e..400a7e8de 100644 --- a/android/testing.go +++ b/android/testing.go @@ -17,9 +17,12 @@ package android import ( "bytes" "fmt" + "iter" + "maps" "path/filepath" "regexp" "runtime" + "slices" "sort" "strings" "sync" @@ -238,7 +241,7 @@ func (ctx *TestContext) HardCodedPreArchMutators(f RegisterMutatorFunc) { ctx.PreArchMutators(f) } -func (ctx *TestContext) otherModuleProvider(m blueprint.Module, p blueprint.AnyProviderKey) (any, bool) { +func (ctx *TestContext) otherModuleProvider(m ModuleOrProxy, p blueprint.AnyProviderKey) (any, bool) { return ctx.Context.ModuleProvider(m, p) } @@ -259,15 +262,72 @@ func (ctx *TestContext) FinalDepsMutators(f RegisterMutatorFunc) { } func (ctx *TestContext) OtherModuleProviderAdaptor() OtherModuleProviderContext { - return NewOtherModuleProviderAdaptor(func(module blueprint.Module, provider blueprint.AnyProviderKey) (any, bool) { + return NewOtherModuleProviderAdaptor(func(module ModuleOrProxy, provider blueprint.AnyProviderKey) (any, bool) { return ctx.otherModuleProvider(module, provider) }) } -func (ctx *TestContext) OtherModulePropertyErrorf(module Module, property string, fmt_ string, args ...interface{}) { +func (ctx *TestContext) ModuleDir(module ModuleOrProxy) string { + return ctx.Context.ModuleDir(module) +} + +func (ctx *TestContext) ModuleSubDir(module ModuleOrProxy) string { + return ctx.Context.ModuleSubDir(module) +} + +func (ctx *TestContext) ModuleType(module ModuleOrProxy) string { + return ctx.Context.ModuleType(module) +} + +func (ctx *TestContext) ModuleErrorf(module ModuleOrProxy, fmt string, args ...any) error { + return ctx.Context.ModuleErrorf(module, fmt, args...) +} + +func (ctx *TestContext) OtherModulePropertyErrorf(module ModuleOrProxy, property string, fmt_ string, args ...interface{}) { panic(fmt.Sprintf(fmt_, args...)) } +// VisitAllModules iterates over all modules tracked through the test config. +func (ctx *TestContext) VisitAllModules(visit func(Module)) { + for module := range ctx.config.modulesForTests.Iter() { + visit(module) + } +} + +// VisitAllModulesProxies wraps blueprint.Context.VisitAllModulesProxies, converting blueprint.ModuleProxy to +// android.ModuleProxy. +func (ctx *TestContext) VisitAllModulesProxies(visit func(ModuleProxy)) { + ctx.Context.VisitAllModulesProxies(func(module blueprint.ModuleProxy) { + visit(ModuleProxy{module}) + }) +} + +// VisitDirectDeps wraps blueprint.Context.VisitDirectDepsProxies, converting blueprint.ModuleProxy to android.Module +// using the list of modules in the test config. +func (ctx *TestContext) VisitDirectDeps(module Module, visit func(Module)) { + allModules := slices.Collect(ctx.config.modulesForTests.Iter()) + ctx.VisitDirectDepsProxies(module, func(dep ModuleProxy) { + i := slices.IndexFunc(allModules, func(m Module) bool { return EqualModules(m, dep) }) + if i < 0 { + panic(fmt.Errorf("failed to find Module for ModuleProxy %s", dep)) + } else { + visit(allModules[i]) + } + }) +} + +// VisitDirectDepsProxies wraps blueprint.Context.VisitDirectDepsProxies, converting blueprint.ModuleProxy to +// android.ModuleProxy. +func (ctx *TestContext) VisitDirectDepsProxies(module ModuleOrProxy, visit func(ModuleProxy)) { + ctx.Context.VisitDirectDepsProxies(module, func(dep blueprint.ModuleProxy) { + visit(ModuleProxy{dep}) + }) +} + +func (ctx *TestContext) ModuleToProxy(module ModuleOrProxy) ModuleProxy { + return ModuleProxy{ctx.Context.ModuleToProxy(module)} +} + // registeredComponentOrder defines the order in which a sortableComponent type is registered at // runtime and provides support for reordering the components registered for a test in the same // way. @@ -533,7 +593,7 @@ func (ctx *TestContext) RegisterParallelSingletonType(name string, factory Singl func (ctx *TestContext) ModuleVariantForTests(t *testing.T, name string, matchVariations map[string]string) TestingModule { t.Helper() modules := []Module{} - ctx.VisitAllModules(func(m blueprint.Module) { + ctx.VisitAllModules(func(m Module) { if ctx.ModuleName(m) == name { am := m.(Module) amMut := am.base().commonProperties.DebugMutators @@ -555,7 +615,7 @@ func (ctx *TestContext) ModuleVariantForTests(t *testing.T, name string, matchVa // Show all the modules or module variants that do exist. var allModuleNames []string var allVariants []string - ctx.VisitAllModules(func(m blueprint.Module) { + ctx.VisitAllModules(func(m Module) { allModuleNames = append(allModuleNames, ctx.ModuleName(m)) if ctx.ModuleName(m) == name { allVariants = append(allVariants, m.(Module).String()) @@ -582,15 +642,15 @@ func (ctx *TestContext) ModuleVariantForTests(t *testing.T, name string, matchVa name, matchVariations, strings.Join(moduleStrings, "\n ")) } - return newTestingModule(t, ctx.config, modules[0]) + return newTestingModule(t, ctx.config, modules[0], ctx.ModuleToProxy(modules[0])) } func (ctx *TestContext) ModuleForTests(t *testing.T, name, variant string) TestingModule { t.Helper() var module Module - ctx.VisitAllModules(func(m blueprint.Module) { + ctx.VisitAllModules(func(m Module) { if ctx.ModuleName(m) == name && ctx.ModuleSubDir(m) == variant { - module = m.(Module) + module = m } }) @@ -598,7 +658,7 @@ func (ctx *TestContext) ModuleForTests(t *testing.T, name, variant string) Testi // find all the modules that do exist var allModuleNames []string var allVariants []string - ctx.VisitAllModules(func(m blueprint.Module) { + ctx.VisitAllModules(func(m Module) { allModuleNames = append(allModuleNames, ctx.ModuleName(m)) if ctx.ModuleName(m) == name { allVariants = append(allVariants, ctx.ModuleSubDir(m)) @@ -615,12 +675,12 @@ func (ctx *TestContext) ModuleForTests(t *testing.T, name, variant string) Testi } } - return newTestingModule(t, ctx.config, module) + return newTestingModule(t, ctx.config, module, ctx.ModuleToProxy(module)) } func (ctx *TestContext) ModuleVariantsForTests(name string) []string { var variants []string - ctx.VisitAllModules(func(m blueprint.Module) { + ctx.VisitAllModules(func(m Module) { if ctx.ModuleName(m) == name { variants = append(variants, ctx.ModuleSubDir(m)) } @@ -1053,12 +1113,14 @@ func (b baseTestingComponent) AllOutputs() []string { type TestingModule struct { baseTestingComponent module Module + proxy ModuleProxy } -func newTestingModule(t *testing.T, config Config, module Module) TestingModule { +func newTestingModule(t *testing.T, config Config, module Module, proxy ModuleProxy) TestingModule { return TestingModule{ newBaseTestingComponent(t, config, module), module, + proxy, } } @@ -1067,6 +1129,11 @@ func (m TestingModule) Module() Module { return m.module } +// ModuleProxy returns the ModuleProxy wrapped by the TestingModule. +func (m TestingModule) ModuleProxy() ModuleProxy { + return m.proxy +} + // VariablesForTestsRelativeToTop returns a copy of the Module.VariablesForTests() with every value // having any temporary build dir usages replaced with paths relative to a notional top. func (m TestingModule) VariablesForTestsRelativeToTop() map[string]string { @@ -1167,6 +1234,12 @@ func SetKatiEnabledForTests(config Config) { config.katiEnabled = true } +func SetBuildDateFileEnvVarForTests() FixturePreparer { + return FixtureModifyConfig(func(config Config) { + config.env["BUILD_DATETIME_FILE"] = filepath.Join(config.outDir, "build_date.txt") + }) +} + func AndroidMkEntriesForTest(t *testing.T, ctx *TestContext, mod Module) []AndroidMkEntries { t.Helper() var p AndroidMkEntriesProvider @@ -1378,7 +1451,7 @@ type panickingConfigAndErrorContext struct { ctx *TestContext } -func (ctx *panickingConfigAndErrorContext) OtherModulePropertyErrorf(module Module, property, fmt string, args ...interface{}) { +func (ctx *panickingConfigAndErrorContext) OtherModulePropertyErrorf(module ModuleOrProxy, property, fmt string, args ...interface{}) { panic(ctx.ctx.PropertyErrorf(module, property, fmt, args...).Error()) } @@ -1390,7 +1463,7 @@ func (ctx *panickingConfigAndErrorContext) HasMutatorFinished(mutatorName string return ctx.ctx.HasMutatorFinished(mutatorName) } -func (ctx *panickingConfigAndErrorContext) otherModuleProvider(m blueprint.Module, p blueprint.AnyProviderKey) (any, bool) { +func (ctx *panickingConfigAndErrorContext) otherModuleProvider(m ModuleOrProxy, p blueprint.AnyProviderKey) (any, bool) { return ctx.ctx.otherModuleProvider(m, p) } @@ -1399,3 +1472,112 @@ func PanickingConfigAndErrorContext(ctx *TestContext) ConfigurableEvaluatorConte ctx: ctx, } } + +// modulesForTests stores the list of modules that exist for use during tests. +type modulesForTests struct { + moduleGroups map[string]*moduleGroupForTests + lock sync.Mutex +} + +// moduleGroupForTests stores the list of variants that exist for a single module name. +type moduleGroupForTests struct { + modules []Module + // nextInsertIndex is the position in modules where the last module is inserted. + // It is used when inserting new variants to place them after the variant they + // were created from. + nextInsertIndex int +} + +// Insert inserts a module into modulesForTests. If the Module matches and existing +// Module in the list (either by being the same pointer or by being a clone with +// identical name, namespace and variations) then it replaces the entry currently +// in the list. Otherwise, it is inserted after the most recently updated entry in +// the list. +func (m *modulesForTests) Insert(name string, module Module) { + m.lock.Lock() + defer m.lock.Unlock() + if existing, ok := m.moduleGroups[name]; ok { + // A name that is already present + if i := slices.IndexFunc(existing.modules, func(old Module) bool { + return old == module || + (old.base().commonProperties.DebugName == module.base().commonProperties.DebugName && + old.base().commonProperties.DebugNamespace == module.base().commonProperties.DebugNamespace && + slices.Equal(old.base().commonProperties.DebugVariations, module.base().commonProperties.DebugVariations) && + slices.Equal(old.base().commonProperties.DebugMutators, module.base().commonProperties.DebugMutators)) + }); i >= 0 { + // The module matches an existing module, either by being the same Module or by being a clone. + // Replace the current entry, and set the insertion point to after the current entry. + // This path is reached when TransitionMutator is creating new variants, and relies on the + // Blueprint optimization that the existing variant is reused as the first new variant so that + // the list doesn't collect old obsolete variants. + existing.modules[i] = module + existing.nextInsertIndex = i + 1 + } else { + // The module doesn't match an existing module, insert it at the insertion point and update the + // insertion point to point after it. + existing.modules = slices.Concat(existing.modules[:existing.nextInsertIndex], + []Module{module}, + existing.modules[existing.nextInsertIndex:]) + existing.nextInsertIndex += 1 + } + } else { + // The name is not present, add a new entry for it. + m.moduleGroups[name] = &moduleGroupForTests{ + modules: []Module{module}, + nextInsertIndex: 0, + } + } +} + +// Rename updates the name of a module group. +func (m *modulesForTests) Rename(from, to string) { + m.lock.Lock() + defer m.lock.Unlock() + m.moduleGroups[to] = m.moduleGroups[from] + delete(m.moduleGroups, from) +} + +// Iter returns a Seq of all the modules in a deterministic order (alphabetically by module name, +// and then in variant order). +func (m *modulesForTests) Iter() iter.Seq[Module] { + return func(yield func(Module) bool) { + groups := slices.Collect(maps.Keys(m.moduleGroups)) + slices.Sort(groups) + for _, group := range groups { + for _, module := range m.moduleGroups[group].modules { + if !yield(module) { + return + } + } + } + } +} + +type visitDirectDepsInterface interface { + VisitDirectDepsProxies(ModuleOrProxy, func(dep ModuleProxy)) +} + +// HasDirectDep returns true if wantDep is a direct dependency of m. +func HasDirectDep(ctx visitDirectDepsInterface, m Module, wantDep ModuleOrProxy) bool { + var found bool + ctx.VisitDirectDepsProxies(m, func(dep ModuleProxy) { + if EqualModules(dep, wantDep) { + found = true + } + }) + return found +} + +// AssertHasDirectDep asserts that wantDep is a direct dependency of m. +func AssertHasDirectDep(t *testing.T, ctx visitDirectDepsInterface, m Module, wantDep ModuleOrProxy) { + t.Helper() + found := false + ctx.VisitDirectDepsProxies(m, func(dep ModuleProxy) { + if EqualModules(dep, wantDep) { + found = true + } + }) + if !found { + t.Errorf("Could not find a dependency from %v to %v\n", m, wantDep) + } +} |
