blob: cc35ce72cb89ce8fbb7f25b8b19431e2b4a76a93 [file] [log] [blame]
Weijia He32282f62024-11-05 22:21:04 +00001// Copyright 2024 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 tradefed_modules
16
17import (
Weijia He0c79e262024-11-06 19:57:25 +000018 "encoding/json"
19 "path"
20 "path/filepath"
Weijia Heaa37c162024-11-06 19:46:03 +000021
Weijia He32282f62024-11-05 22:21:04 +000022 "android/soong/android"
Weijia He0c79e262024-11-06 19:57:25 +000023 "android/soong/tradefed"
24 "github.com/google/blueprint"
Weijia He32282f62024-11-05 22:21:04 +000025)
26
Weijia He0c79e262024-11-06 19:57:25 +000027type testSuiteTag struct{
28 blueprint.BaseDependencyTag
29}
30
31type testSuiteManifest struct {
32 Name string `json:"name"`
33 Files []string `json:"files"`
34}
35
Weijia He32282f62024-11-05 22:21:04 +000036func init() {
37 RegisterTestSuiteBuildComponents(android.InitRegistrationContext)
38}
39
40func RegisterTestSuiteBuildComponents(ctx android.RegistrationContext) {
41 ctx.RegisterModuleType("test_suite", TestSuiteFactory)
42}
43
44var PrepareForTestWithTestSuiteBuildComponents = android.GroupFixturePreparers(
45 android.FixtureRegisterWithContext(RegisterTestSuiteBuildComponents),
46)
47
48type testSuiteProperties struct {
49 Description string
50 Tests []string `android:"path,arch_variant"`
51}
52
53type testSuiteModule struct {
54 android.ModuleBase
55 android.DefaultableModuleBase
56 testSuiteProperties
57}
58
Weijia He0c79e262024-11-06 19:57:25 +000059func (t *testSuiteModule) DepsMutator(ctx android.BottomUpMutatorContext) {
60 for _, test := range t.Tests {
61 if ctx.OtherModuleDependencyVariantExists(ctx.Config().BuildOSCommonTarget.Variations(), test) {
62 // Host tests.
63 ctx.AddVariationDependencies(ctx.Config().BuildOSCommonTarget.Variations(), testSuiteTag{}, test)
64 } else {
65 // Target tests.
66 ctx.AddDependency(ctx.Module(), testSuiteTag{}, test)
67 }
68 }
69}
70
Weijia He32282f62024-11-05 22:21:04 +000071func (t *testSuiteModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
Weijia He0c79e262024-11-06 19:57:25 +000072 modulesByName := make(map[string]android.Module)
73 ctx.WalkDeps(func(child, parent android.Module) bool {
74 // Only write out top level test suite dependencies here.
75 if _, ok := ctx.OtherModuleDependencyTag(child).(testSuiteTag); !ok {
76 return false
77 }
78
79 if !child.InstallInTestcases() {
80 ctx.ModuleErrorf("test_suite only supports modules installed in testcases. %q is not installed in testcases.", child.Name())
81 return false
82 }
83
84 modulesByName[child.Name()] = child
85 return false
86 })
87
Weijia Heaa37c162024-11-06 19:46:03 +000088 suiteName := ctx.ModuleName()
Weijia He0c79e262024-11-06 19:57:25 +000089 var files []string
90 for name, module := range modulesByName {
91 // Get the test provider data from the child.
92 tp, ok := android.OtherModuleProvider(ctx, module, tradefed.BaseTestProviderKey)
93 if !ok {
94 // TODO: Consider printing out a list of all module types.
95 ctx.ModuleErrorf("%q is not a test module.", name)
96 continue
97 }
98
99 files = append(files, packageModuleFiles(ctx, suiteName, module, tp)...)
100 ctx.Phony(suiteName, android.PathForPhony(ctx, name))
101 }
102
Weijia Heaa37c162024-11-06 19:46:03 +0000103 manifestPath := android.PathForSuiteInstall(ctx, suiteName, suiteName+".json")
Weijia He0c79e262024-11-06 19:57:25 +0000104 b, err := json.Marshal(testSuiteManifest{Name: suiteName, Files: files})
105 if err != nil {
106 ctx.ModuleErrorf("Failed to marshal manifest: %v", err)
107 return
108 }
109 android.WriteFileRule(ctx, manifestPath, string(b))
110
Weijia Heaa37c162024-11-06 19:46:03 +0000111 ctx.Phony(suiteName, manifestPath)
Weijia He32282f62024-11-05 22:21:04 +0000112}
113
114func TestSuiteFactory() android.Module {
115 module := &testSuiteModule{}
116 module.AddProperties(&module.testSuiteProperties)
117
118 android.InitAndroidModule(module)
119 android.InitDefaultableModule(module)
120
121 return module
122}
Weijia He0c79e262024-11-06 19:57:25 +0000123
124func packageModuleFiles(ctx android.ModuleContext, suiteName string, module android.Module, tp tradefed.BaseTestProviderData) []string {
125
126 hostOrTarget := "target"
127 if tp.IsHost {
128 hostOrTarget = "host"
129 }
130
131 // suiteRoot at out/soong/packaging/<suiteName>.
132 suiteRoot := android.PathForSuiteInstall(ctx, suiteName)
133
134 var installed android.InstallPaths
135 // Install links to installed files from the module.
136 if installFilesInfo, ok := android.OtherModuleProvider(ctx, module, android.InstallFilesProvider); ok {
137 for _, f := range installFilesInfo.InstallFiles {
138 // rel is anything under .../<partition>, normally under .../testcases.
139 rel := android.Rel(ctx, f.PartitionDir(), f.String())
140
141 // Install the file under <suiteRoot>/<host|target>/<partition>.
142 installDir := suiteRoot.Join(ctx, hostOrTarget, f.Partition(), path.Dir(rel))
143 linkTo, err := filepath.Rel(installDir.String(), f.String())
144 if err != nil {
145 ctx.ModuleErrorf("Failed to get relative path from %s to %s: %v", installDir.String(), f.String(), err)
146 continue
147 }
148 installed = append(installed, ctx.InstallAbsoluteSymlink(installDir, path.Base(rel), linkTo))
149 }
150 }
151
152 // Install config file.
153 if tp.TestConfig != nil {
154 moduleRoot := suiteRoot.Join(ctx, hostOrTarget, "testcases", module.Name())
155 installed = append(installed, ctx.InstallFile(moduleRoot, module.Name() + ".config", tp.TestConfig))
156 }
157
158 // Add to phony and manifest, manifestpaths are relative to suiteRoot.
159 var manifestEntries []string
160 for _, f := range installed {
161 manifestEntries = append(manifestEntries, android.Rel(ctx, suiteRoot.String(), f.String()))
162 ctx.Phony(suiteName, f)
163 }
164 return manifestEntries
165}