1*333d2b36SAndroid Build Coastguard Worker// Copyright 2024 Google Inc. All rights reserved. 2*333d2b36SAndroid Build Coastguard Worker// 3*333d2b36SAndroid Build Coastguard Worker// Licensed under the Apache License, Version 2.0 (the "License"); 4*333d2b36SAndroid Build Coastguard Worker// you may not use this file except in compliance with the License. 5*333d2b36SAndroid Build Coastguard Worker// You may obtain a copy of the License at 6*333d2b36SAndroid Build Coastguard Worker// 7*333d2b36SAndroid Build Coastguard Worker// http://www.apache.org/licenses/LICENSE-2.0 8*333d2b36SAndroid Build Coastguard Worker// 9*333d2b36SAndroid Build Coastguard Worker// Unless required by applicable law or agreed to in writing, software 10*333d2b36SAndroid Build Coastguard Worker// distributed under the License is distributed on an "AS IS" BASIS, 11*333d2b36SAndroid Build Coastguard Worker// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12*333d2b36SAndroid Build Coastguard Worker// See the License for the specific language governing permissions and 13*333d2b36SAndroid Build Coastguard Worker// limitations under the License. 14*333d2b36SAndroid Build Coastguard Worker 15*333d2b36SAndroid Build Coastguard Workerpackage tradefed_modules 16*333d2b36SAndroid Build Coastguard Worker 17*333d2b36SAndroid Build Coastguard Workerimport ( 18*333d2b36SAndroid Build Coastguard Worker "encoding/json" 19*333d2b36SAndroid Build Coastguard Worker "path" 20*333d2b36SAndroid Build Coastguard Worker "path/filepath" 21*333d2b36SAndroid Build Coastguard Worker 22*333d2b36SAndroid Build Coastguard Worker "android/soong/android" 23*333d2b36SAndroid Build Coastguard Worker "android/soong/tradefed" 24*333d2b36SAndroid Build Coastguard Worker "github.com/google/blueprint" 25*333d2b36SAndroid Build Coastguard Worker) 26*333d2b36SAndroid Build Coastguard Worker 27*333d2b36SAndroid Build Coastguard Workerconst testSuiteModuleType = "test_suite" 28*333d2b36SAndroid Build Coastguard Worker 29*333d2b36SAndroid Build Coastguard Workertype testSuiteTag struct{ 30*333d2b36SAndroid Build Coastguard Worker blueprint.BaseDependencyTag 31*333d2b36SAndroid Build Coastguard Worker} 32*333d2b36SAndroid Build Coastguard Worker 33*333d2b36SAndroid Build Coastguard Workertype testSuiteManifest struct { 34*333d2b36SAndroid Build Coastguard Worker Name string `json:"name"` 35*333d2b36SAndroid Build Coastguard Worker Files []string `json:"files"` 36*333d2b36SAndroid Build Coastguard Worker} 37*333d2b36SAndroid Build Coastguard Worker 38*333d2b36SAndroid Build Coastguard Workerfunc init() { 39*333d2b36SAndroid Build Coastguard Worker RegisterTestSuiteBuildComponents(android.InitRegistrationContext) 40*333d2b36SAndroid Build Coastguard Worker} 41*333d2b36SAndroid Build Coastguard Worker 42*333d2b36SAndroid Build Coastguard Workerfunc RegisterTestSuiteBuildComponents(ctx android.RegistrationContext) { 43*333d2b36SAndroid Build Coastguard Worker ctx.RegisterModuleType(testSuiteModuleType, TestSuiteFactory) 44*333d2b36SAndroid Build Coastguard Worker} 45*333d2b36SAndroid Build Coastguard Worker 46*333d2b36SAndroid Build Coastguard Workervar PrepareForTestWithTestSuiteBuildComponents = android.GroupFixturePreparers( 47*333d2b36SAndroid Build Coastguard Worker android.FixtureRegisterWithContext(RegisterTestSuiteBuildComponents), 48*333d2b36SAndroid Build Coastguard Worker) 49*333d2b36SAndroid Build Coastguard Worker 50*333d2b36SAndroid Build Coastguard Workertype testSuiteProperties struct { 51*333d2b36SAndroid Build Coastguard Worker Description string 52*333d2b36SAndroid Build Coastguard Worker Tests []string `android:"path,arch_variant"` 53*333d2b36SAndroid Build Coastguard Worker} 54*333d2b36SAndroid Build Coastguard Worker 55*333d2b36SAndroid Build Coastguard Workertype testSuiteModule struct { 56*333d2b36SAndroid Build Coastguard Worker android.ModuleBase 57*333d2b36SAndroid Build Coastguard Worker android.DefaultableModuleBase 58*333d2b36SAndroid Build Coastguard Worker testSuiteProperties 59*333d2b36SAndroid Build Coastguard Worker} 60*333d2b36SAndroid Build Coastguard Worker 61*333d2b36SAndroid Build Coastguard Workerfunc (t *testSuiteModule) DepsMutator(ctx android.BottomUpMutatorContext) { 62*333d2b36SAndroid Build Coastguard Worker for _, test := range t.Tests { 63*333d2b36SAndroid Build Coastguard Worker if ctx.OtherModuleDependencyVariantExists(ctx.Config().BuildOSCommonTarget.Variations(), test) { 64*333d2b36SAndroid Build Coastguard Worker // Host tests. 65*333d2b36SAndroid Build Coastguard Worker ctx.AddVariationDependencies(ctx.Config().BuildOSCommonTarget.Variations(), testSuiteTag{}, test) 66*333d2b36SAndroid Build Coastguard Worker } else { 67*333d2b36SAndroid Build Coastguard Worker // Target tests. 68*333d2b36SAndroid Build Coastguard Worker ctx.AddDependency(ctx.Module(), testSuiteTag{}, test) 69*333d2b36SAndroid Build Coastguard Worker } 70*333d2b36SAndroid Build Coastguard Worker } 71*333d2b36SAndroid Build Coastguard Worker} 72*333d2b36SAndroid Build Coastguard Worker 73*333d2b36SAndroid Build Coastguard Workerfunc (t *testSuiteModule) GenerateAndroidBuildActions(ctx android.ModuleContext) { 74*333d2b36SAndroid Build Coastguard Worker suiteName := ctx.ModuleName() 75*333d2b36SAndroid Build Coastguard Worker modulesByName := make(map[string]android.Module) 76*333d2b36SAndroid Build Coastguard Worker ctx.WalkDeps(func(child, parent android.Module) bool { 77*333d2b36SAndroid Build Coastguard Worker // Recurse into test_suite dependencies. 78*333d2b36SAndroid Build Coastguard Worker if ctx.OtherModuleType(child) == testSuiteModuleType { 79*333d2b36SAndroid Build Coastguard Worker ctx.Phony(suiteName, android.PathForPhony(ctx, child.Name())) 80*333d2b36SAndroid Build Coastguard Worker return true 81*333d2b36SAndroid Build Coastguard Worker } 82*333d2b36SAndroid Build Coastguard Worker 83*333d2b36SAndroid Build Coastguard Worker // Only write out top level test suite dependencies here. 84*333d2b36SAndroid Build Coastguard Worker if _, ok := ctx.OtherModuleDependencyTag(child).(testSuiteTag); !ok { 85*333d2b36SAndroid Build Coastguard Worker return false 86*333d2b36SAndroid Build Coastguard Worker } 87*333d2b36SAndroid Build Coastguard Worker 88*333d2b36SAndroid Build Coastguard Worker if !child.InstallInTestcases() { 89*333d2b36SAndroid Build Coastguard Worker ctx.ModuleErrorf("test_suite only supports modules installed in testcases. %q is not installed in testcases.", child.Name()) 90*333d2b36SAndroid Build Coastguard Worker return false 91*333d2b36SAndroid Build Coastguard Worker } 92*333d2b36SAndroid Build Coastguard Worker 93*333d2b36SAndroid Build Coastguard Worker modulesByName[child.Name()] = child 94*333d2b36SAndroid Build Coastguard Worker return false 95*333d2b36SAndroid Build Coastguard Worker }) 96*333d2b36SAndroid Build Coastguard Worker 97*333d2b36SAndroid Build Coastguard Worker var files []string 98*333d2b36SAndroid Build Coastguard Worker for name, module := range modulesByName { 99*333d2b36SAndroid Build Coastguard Worker // Get the test provider data from the child. 100*333d2b36SAndroid Build Coastguard Worker tp, ok := android.OtherModuleProvider(ctx, module, tradefed.BaseTestProviderKey) 101*333d2b36SAndroid Build Coastguard Worker if !ok { 102*333d2b36SAndroid Build Coastguard Worker // TODO: Consider printing out a list of all module types. 103*333d2b36SAndroid Build Coastguard Worker ctx.ModuleErrorf("%q is not a test module.", name) 104*333d2b36SAndroid Build Coastguard Worker continue 105*333d2b36SAndroid Build Coastguard Worker } 106*333d2b36SAndroid Build Coastguard Worker 107*333d2b36SAndroid Build Coastguard Worker files = append(files, packageModuleFiles(ctx, suiteName, module, tp)...) 108*333d2b36SAndroid Build Coastguard Worker ctx.Phony(suiteName, android.PathForPhony(ctx, name)) 109*333d2b36SAndroid Build Coastguard Worker } 110*333d2b36SAndroid Build Coastguard Worker 111*333d2b36SAndroid Build Coastguard Worker manifestPath := android.PathForSuiteInstall(ctx, suiteName, suiteName+".json") 112*333d2b36SAndroid Build Coastguard Worker b, err := json.Marshal(testSuiteManifest{Name: suiteName, Files: files}) 113*333d2b36SAndroid Build Coastguard Worker if err != nil { 114*333d2b36SAndroid Build Coastguard Worker ctx.ModuleErrorf("Failed to marshal manifest: %v", err) 115*333d2b36SAndroid Build Coastguard Worker return 116*333d2b36SAndroid Build Coastguard Worker } 117*333d2b36SAndroid Build Coastguard Worker android.WriteFileRule(ctx, manifestPath, string(b)) 118*333d2b36SAndroid Build Coastguard Worker 119*333d2b36SAndroid Build Coastguard Worker ctx.Phony(suiteName, manifestPath) 120*333d2b36SAndroid Build Coastguard Worker} 121*333d2b36SAndroid Build Coastguard Worker 122*333d2b36SAndroid Build Coastguard Workerfunc TestSuiteFactory() android.Module { 123*333d2b36SAndroid Build Coastguard Worker module := &testSuiteModule{} 124*333d2b36SAndroid Build Coastguard Worker module.AddProperties(&module.testSuiteProperties) 125*333d2b36SAndroid Build Coastguard Worker 126*333d2b36SAndroid Build Coastguard Worker android.InitAndroidArchModule(module, android.HostAndDeviceSupported, android.MultilibCommon) 127*333d2b36SAndroid Build Coastguard Worker android.InitDefaultableModule(module) 128*333d2b36SAndroid Build Coastguard Worker 129*333d2b36SAndroid Build Coastguard Worker return module 130*333d2b36SAndroid Build Coastguard Worker} 131*333d2b36SAndroid Build Coastguard Worker 132*333d2b36SAndroid Build Coastguard Workerfunc packageModuleFiles(ctx android.ModuleContext, suiteName string, module android.Module, tp tradefed.BaseTestProviderData) []string { 133*333d2b36SAndroid Build Coastguard Worker 134*333d2b36SAndroid Build Coastguard Worker hostOrTarget := "target" 135*333d2b36SAndroid Build Coastguard Worker if tp.IsHost { 136*333d2b36SAndroid Build Coastguard Worker hostOrTarget = "host" 137*333d2b36SAndroid Build Coastguard Worker } 138*333d2b36SAndroid Build Coastguard Worker 139*333d2b36SAndroid Build Coastguard Worker // suiteRoot at out/soong/packaging/<suiteName>. 140*333d2b36SAndroid Build Coastguard Worker suiteRoot := android.PathForSuiteInstall(ctx, suiteName) 141*333d2b36SAndroid Build Coastguard Worker 142*333d2b36SAndroid Build Coastguard Worker var installed android.InstallPaths 143*333d2b36SAndroid Build Coastguard Worker // Install links to installed files from the module. 144*333d2b36SAndroid Build Coastguard Worker if installFilesInfo, ok := android.OtherModuleProvider(ctx, module, android.InstallFilesProvider); ok { 145*333d2b36SAndroid Build Coastguard Worker for _, f := range installFilesInfo.InstallFiles { 146*333d2b36SAndroid Build Coastguard Worker // rel is anything under .../<partition>, normally under .../testcases. 147*333d2b36SAndroid Build Coastguard Worker rel := android.Rel(ctx, f.PartitionDir(), f.String()) 148*333d2b36SAndroid Build Coastguard Worker 149*333d2b36SAndroid Build Coastguard Worker // Install the file under <suiteRoot>/<host|target>/<partition>. 150*333d2b36SAndroid Build Coastguard Worker installDir := suiteRoot.Join(ctx, hostOrTarget, f.Partition(), path.Dir(rel)) 151*333d2b36SAndroid Build Coastguard Worker linkTo, err := filepath.Rel(installDir.String(), f.String()) 152*333d2b36SAndroid Build Coastguard Worker if err != nil { 153*333d2b36SAndroid Build Coastguard Worker ctx.ModuleErrorf("Failed to get relative path from %s to %s: %v", installDir.String(), f.String(), err) 154*333d2b36SAndroid Build Coastguard Worker continue 155*333d2b36SAndroid Build Coastguard Worker } 156*333d2b36SAndroid Build Coastguard Worker installed = append(installed, ctx.InstallAbsoluteSymlink(installDir, path.Base(rel), linkTo)) 157*333d2b36SAndroid Build Coastguard Worker } 158*333d2b36SAndroid Build Coastguard Worker } 159*333d2b36SAndroid Build Coastguard Worker 160*333d2b36SAndroid Build Coastguard Worker // Install config file. 161*333d2b36SAndroid Build Coastguard Worker if tp.TestConfig != nil { 162*333d2b36SAndroid Build Coastguard Worker moduleRoot := suiteRoot.Join(ctx, hostOrTarget, "testcases", module.Name()) 163*333d2b36SAndroid Build Coastguard Worker installed = append(installed, ctx.InstallFile(moduleRoot, module.Name() + ".config", tp.TestConfig)) 164*333d2b36SAndroid Build Coastguard Worker } 165*333d2b36SAndroid Build Coastguard Worker 166*333d2b36SAndroid Build Coastguard Worker // Add to phony and manifest, manifestpaths are relative to suiteRoot. 167*333d2b36SAndroid Build Coastguard Worker var manifestEntries []string 168*333d2b36SAndroid Build Coastguard Worker for _, f := range installed { 169*333d2b36SAndroid Build Coastguard Worker manifestEntries = append(manifestEntries, android.Rel(ctx, suiteRoot.String(), f.String())) 170*333d2b36SAndroid Build Coastguard Worker ctx.Phony(suiteName, f) 171*333d2b36SAndroid Build Coastguard Worker } 172*333d2b36SAndroid Build Coastguard Worker return manifestEntries 173*333d2b36SAndroid Build Coastguard Worker} 174