xref: /aosp_15_r20/build/soong/tradefed_modules/test_suite.go (revision 333d2b3687b3a337dbcca9d65000bca186795e39)
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