blob: cedced2601d7654eaf10935bb5df776fd0ad7d5b [file] [log] [blame]
Chih-Hung Hsieha5f22ed2019-10-24 20:47:54 -07001// Copyright 2019 The Android Open Source Project
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 rust
16
17import (
Jooyung Han10bea7d2022-04-29 02:04:30 +090018 "path/filepath"
19
Julien Desprez84c94942021-01-15 15:10:01 -080020 "github.com/google/blueprint/proptools"
21
Chih-Hung Hsieha5f22ed2019-10-24 20:47:54 -070022 "android/soong/android"
Ivan Lozano4e5f07d2021-11-04 14:09:38 -040023 "android/soong/cc"
Chih-Hung Hsieh41805be2019-10-31 20:56:47 -070024 "android/soong/tradefed"
Chih-Hung Hsieha5f22ed2019-10-24 20:47:54 -070025)
26
Chih-Hung Hsieh41805be2019-10-31 20:56:47 -070027type TestProperties struct {
Ivan Lozanofc80fe72020-06-11 13:25:36 -040028 // Disables the creation of a test-specific directory when used with
29 // relative_install_path. Useful if several tests need to be in the same
Colin Cross3a02c7b2024-05-21 13:46:22 -070030 // directory.
Ivan Lozanofc80fe72020-06-11 13:25:36 -040031 No_named_install_directory *bool
32
Chih-Hung Hsieh41805be2019-10-31 20:56:47 -070033 // the name of the test configuration (for example "AndroidTest.xml") that should be
34 // installed with the module.
Colin Crossa6384822020-06-09 15:09:22 -070035 Test_config *string `android:"path,arch_variant"`
Chih-Hung Hsieh41805be2019-10-31 20:56:47 -070036
37 // the name of the test configuration template (for example "AndroidTestTemplate.xml") that
38 // should be installed with the module.
Colin Crossa6384822020-06-09 15:09:22 -070039 Test_config_template *string `android:"path,arch_variant"`
Chih-Hung Hsieh41805be2019-10-31 20:56:47 -070040
41 // list of compatibility suites (for example "cts", "vts") that the module should be
42 // installed into.
43 Test_suites []string `android:"arch_variant"`
44
Ivan Lozano9da4aa82021-01-29 12:48:05 -050045 // list of files or filegroup modules that provide data that should be installed alongside
46 // the test
47 Data []string `android:"path,arch_variant"`
48
Colin Crossb3614422025-02-18 15:18:18 -080049 // Same as data, but adds dependencies on modules using the device's os variant, and common
50 // architecture's variant. Can be useful to add device-built apps to the data of a host
51 // test.
Cole Faust65cb40a2024-10-21 15:41:42 -070052 Device_common_data []string `android:"path_device_common"`
53
Colin Crossb3614422025-02-18 15:18:18 -080054 // Same as data, but will add dependencies on modules using the host's os variation and
55 // the common arch variation. Useful for a device test that wants to depend on a host
56 // module, for example to include a custom Tradefed test runner.
57 Host_common_data []string `android:"path_host_common"`
58
Ivan Lozano4e5f07d2021-11-04 14:09:38 -040059 // list of shared library modules that should be installed alongside the test
60 Data_libs []string `android:"arch_variant"`
61
62 // list of binary modules that should be installed alongside the test
63 Data_bins []string `android:"arch_variant"`
64
Chih-Hung Hsieh41805be2019-10-31 20:56:47 -070065 // Flag to indicate whether or not to create test config automatically. If AndroidTest.xml
66 // doesn't exist next to the Android.bp, this attribute doesn't need to be set to true
67 // explicitly.
68 Auto_gen_config *bool
Stephen Crane02a623d2020-04-25 21:40:35 -070069
70 // if set, build with the standard Rust test harness. Defaults to true.
71 Test_harness *bool
Dan Shid79572f2020-11-13 14:33:46 -080072
73 // Test options.
Zhenhuang Wang0ac5a432022-08-12 18:49:20 +080074 Test_options android.CommonTestOptions
Ivan Lozanoba222612021-09-21 10:49:13 -040075
76 // Add RootTargetPreparer to auto generated test config. This guarantees the test to run
77 // with root permission.
78 Require_root *bool
Chih-Hung Hsieh41805be2019-10-31 20:56:47 -070079}
80
Chih-Hung Hsieha5f22ed2019-10-24 20:47:54 -070081// A test module is a binary module with extra --test compiler flag
82// and different default installation directory.
83// In golang, inheriance is written as a component.
Chih-Hung Hsieh41805be2019-10-31 20:56:47 -070084type testDecorator struct {
Chih-Hung Hsieha5f22ed2019-10-24 20:47:54 -070085 *binaryDecorator
Chih-Hung Hsieh41805be2019-10-31 20:56:47 -070086 Properties TestProperties
87 testConfig android.Path
Ivan Lozano9da4aa82021-01-29 12:48:05 -050088
89 data []android.DataPath
90}
91
92func (test *testDecorator) dataPaths() []android.DataPath {
93 return test.data
Chih-Hung Hsieha5f22ed2019-10-24 20:47:54 -070094}
95
Ivan Lozanoa0cd8f92020-04-09 09:56:02 -040096func (test *testDecorator) nativeCoverage() bool {
97 return true
98}
99
Stephen Crane02a623d2020-04-25 21:40:35 -0700100func (test *testDecorator) testHarness() bool {
101 return BoolDefault(test.Properties.Test_harness, true)
102}
103
Chih-Hung Hsieh41805be2019-10-31 20:56:47 -0700104func NewRustTest(hod android.HostOrDeviceSupported) (*Module, *testDecorator) {
Chih-Hung Hsiehe728a892020-06-16 01:25:27 -0700105 // Build both 32 and 64 targets for device tests.
106 // Cannot build both for host tests yet if the test depends on
107 // something like proc-macro2 that cannot be built for both.
108 multilib := android.MultilibBoth
109 if hod != android.DeviceSupported && hod != android.HostAndDeviceSupported {
110 multilib = android.MultilibFirst
111 }
112 module := newModule(hod, multilib)
Chih-Hung Hsieha5f22ed2019-10-24 20:47:54 -0700113
Chih-Hung Hsieh41805be2019-10-31 20:56:47 -0700114 test := &testDecorator{
Chih-Hung Hsieha5f22ed2019-10-24 20:47:54 -0700115 binaryDecorator: &binaryDecorator{
Chih-Hung Hsieh9a4a7ba2019-12-12 19:36:05 -0800116 baseCompiler: NewBaseCompiler("nativetest", "nativetest64", InstallInData),
Chih-Hung Hsieha5f22ed2019-10-24 20:47:54 -0700117 },
118 }
119
120 module.compiler = test
Chih-Hung Hsieha5f22ed2019-10-24 20:47:54 -0700121 return module, test
122}
123
Chih-Hung Hsieh41805be2019-10-31 20:56:47 -0700124func (test *testDecorator) compilerProps() []interface{} {
125 return append(test.binaryDecorator.compilerProps(), &test.Properties)
126}
127
ThiƩbaud Weksteenfabaff62020-08-27 13:48:36 +0200128func (test *testDecorator) install(ctx ModuleContext) {
Nikita Putikhin5f23bc92024-07-05 15:08:01 +0200129 // TODO: (b/167308193) Switch to /data/local/tests/unrestricted as the default install base.
130 testInstallBase := "/data/local/tmp"
Kiyoung Kimaa394802024-01-08 12:55:45 +0900131 if ctx.RustModule().InVendorOrProduct() {
Ivan Lozanoba222612021-09-21 10:49:13 -0400132 testInstallBase = "/data/local/tests/vendor"
133 }
134
135 var configs []tradefed.Config
136 if Bool(test.Properties.Require_root) {
137 configs = append(configs, tradefed.Object{"target_preparer", "com.android.tradefed.targetprep.RootTargetPreparer", nil})
138 } else {
139 var options []tradefed.Option
140 options = append(options, tradefed.Option{Name: "force-root", Value: "false"})
141 configs = append(configs, tradefed.Object{"target_preparer", "com.android.tradefed.targetprep.RootTargetPreparer", options})
142 }
143
Cole Faust21680542022-12-07 18:18:37 -0800144 test.testConfig = tradefed.AutoGenTestConfig(ctx, tradefed.AutoGenTestConfigOptions{
145 TestConfigProp: test.Properties.Test_config,
146 TestConfigTemplateProp: test.Properties.Test_config_template,
147 TestSuites: test.Properties.Test_suites,
148 Config: configs,
149 AutoGenConfig: test.Properties.Auto_gen_config,
150 TestInstallBase: testInstallBase,
151 DeviceTemplate: "${RustDeviceTestConfigTemplate}",
152 HostTemplate: "${RustHostTestConfigTemplate}",
153 })
Ivan Lozanofc80fe72020-06-11 13:25:36 -0400154
Ivan Lozano9da4aa82021-01-29 12:48:05 -0500155 dataSrcPaths := android.PathsForModuleSrc(ctx, test.Properties.Data)
Cole Faust65cb40a2024-10-21 15:41:42 -0700156 dataSrcPaths = append(dataSrcPaths, android.PathsForModuleSrc(ctx, test.Properties.Device_common_data)...)
Colin Crossb3614422025-02-18 15:18:18 -0800157 dataSrcPaths = append(dataSrcPaths, android.PathsForModuleSrc(ctx, test.Properties.Host_common_data)...)
Ivan Lozano9da4aa82021-01-29 12:48:05 -0500158
Yu Liu727204c2025-01-23 20:58:32 +0000159 ctx.VisitDirectDepsProxyWithTag(dataLibDepTag, func(dep android.ModuleProxy) {
Ivan Lozano4e5f07d2021-11-04 14:09:38 -0400160 depName := ctx.OtherModuleName(dep)
Yu Liu727204c2025-01-23 20:58:32 +0000161 linkableDep, ok := android.OtherModuleProvider(ctx, dep, cc.LinkableInfoProvider)
Ivan Lozano4e5f07d2021-11-04 14:09:38 -0400162 if !ok {
163 ctx.ModuleErrorf("data_lib %q is not a linkable module", depName)
164 }
Yu Liu727204c2025-01-23 20:58:32 +0000165 if linkableDep.OutputFile.Valid() {
Jooyung Han10bea7d2022-04-29 02:04:30 +0900166 // Copy the output in "lib[64]" so that it's compatible with
167 // the default rpath values.
Yu Liuf22120f2025-03-13 18:36:35 +0000168 commonInfo := android.OtherModulePointerProviderOrDefault(ctx, dep, android.CommonModuleInfoProvider)
Jooyung Han10bea7d2022-04-29 02:04:30 +0900169 libDir := "lib"
Yu Liu727204c2025-01-23 20:58:32 +0000170 if commonInfo.Target.Arch.ArchType.Multilib == "lib64" {
Jooyung Han10bea7d2022-04-29 02:04:30 +0900171 libDir = "lib64"
172 }
Ivan Lozano4e5f07d2021-11-04 14:09:38 -0400173 test.data = append(test.data,
Yu Liu727204c2025-01-23 20:58:32 +0000174 android.DataPath{SrcPath: linkableDep.OutputFile.Path(),
175 RelativeInstallPath: filepath.Join(libDir, linkableDep.RelativeInstallPath)})
Ivan Lozano4e5f07d2021-11-04 14:09:38 -0400176 }
177 })
178
Yu Liu727204c2025-01-23 20:58:32 +0000179 ctx.VisitDirectDepsProxyWithTag(dataBinDepTag, func(dep android.ModuleProxy) {
Ivan Lozano4e5f07d2021-11-04 14:09:38 -0400180 depName := ctx.OtherModuleName(dep)
Yu Liu727204c2025-01-23 20:58:32 +0000181 linkableDep, ok := android.OtherModuleProvider(ctx, dep, cc.LinkableInfoProvider)
Ivan Lozano4e5f07d2021-11-04 14:09:38 -0400182 if !ok {
183 ctx.ModuleErrorf("data_bin %q is not a linkable module", depName)
184 }
Yu Liu727204c2025-01-23 20:58:32 +0000185 if linkableDep.OutputFile.Valid() {
Ivan Lozano4e5f07d2021-11-04 14:09:38 -0400186 test.data = append(test.data,
Yu Liu727204c2025-01-23 20:58:32 +0000187 android.DataPath{SrcPath: linkableDep.OutputFile.Path(),
188 RelativeInstallPath: linkableDep.RelativeInstallPath})
Ivan Lozano4e5f07d2021-11-04 14:09:38 -0400189 }
190 })
191
Ivan Lozano9da4aa82021-01-29 12:48:05 -0500192 for _, dataSrcPath := range dataSrcPaths {
193 test.data = append(test.data, android.DataPath{SrcPath: dataSrcPath})
194 }
195
Chih-Hung Hsieh9a4a7ba2019-12-12 19:36:05 -0800196 // default relative install path is module name
Ivan Lozanofc80fe72020-06-11 13:25:36 -0400197 if !Bool(test.Properties.No_named_install_directory) {
Chih-Hung Hsieh9a4a7ba2019-12-12 19:36:05 -0800198 test.baseCompiler.relative = ctx.ModuleName()
Ivan Lozanofc80fe72020-06-11 13:25:36 -0400199 } else if String(test.baseCompiler.Properties.Relative_install_path) == "" {
200 ctx.PropertyErrorf("no_named_install_directory", "Module install directory may only be disabled if relative_install_path is set")
Chih-Hung Hsieh9a4a7ba2019-12-12 19:36:05 -0800201 }
Ivan Lozanofc80fe72020-06-11 13:25:36 -0400202
Julien Desprez84c94942021-01-15 15:10:01 -0800203 if ctx.Host() && test.Properties.Test_options.Unit_test == nil {
204 test.Properties.Test_options.Unit_test = proptools.BoolPtr(true)
205 }
Spandan Das3094ba02025-01-29 20:57:02 +0000206
207 if !ctx.Config().KatiEnabled() { // TODO(spandandas): Remove the special case for kati
208 // Install the test config in testcases/ directory for atest.
209 r, ok := ctx.Module().(*Module)
210 if !ok {
211 ctx.ModuleErrorf("Not a rust test module")
212 }
213 // Install configs in the root of $PRODUCT_OUT/testcases/$module
214 testCases := android.PathForModuleInPartitionInstall(ctx, "testcases", ctx.ModuleName()+r.SubName())
215 if ctx.PrimaryArch() {
216 if test.testConfig != nil {
217 ctx.InstallFile(testCases, ctx.ModuleName()+".config", test.testConfig)
218 }
Cole Faustec71dfb2025-02-18 13:31:12 -0800219 dynamicConfig := android.ExistentPathForSource(ctx, ctx.ModuleDir(), "DynamicConfig.xml")
220 if dynamicConfig.Valid() {
221 ctx.InstallFile(testCases, ctx.ModuleName()+".dynamic", dynamicConfig.Path())
222 }
Spandan Das3094ba02025-01-29 20:57:02 +0000223 }
224 // Install tests and data in arch specific subdir $PRODUCT_OUT/testcases/$module/$arch
225 testCases = testCases.Join(ctx, ctx.Target().Arch.ArchType.String())
226 ctx.InstallTestData(testCases, test.data)
227 testPath := ctx.RustModule().OutputFile().Path()
228 ctx.InstallFile(testCases, testPath.Base(), testPath)
229 }
230
Colin Cross5c1d5fb2023-11-15 12:39:40 -0800231 test.binaryDecorator.installTestData(ctx, test.data)
ThiƩbaud Weksteenfabaff62020-08-27 13:48:36 +0200232 test.binaryDecorator.install(ctx)
Chih-Hung Hsieh41805be2019-10-31 20:56:47 -0700233}
234
235func (test *testDecorator) compilerFlags(ctx ModuleContext, flags Flags) Flags {
Chih-Hung Hsieha5f22ed2019-10-24 20:47:54 -0700236 flags = test.binaryDecorator.compilerFlags(ctx, flags)
Stephen Crane02a623d2020-04-25 21:40:35 -0700237 if test.testHarness() {
238 flags.RustFlags = append(flags.RustFlags, "--test")
Chris Wailes9da6e892025-01-27 13:46:43 -0800239 flags.RustFlags = append(flags.RustFlags, "-A missing-docs")
Stephen Crane02a623d2020-04-25 21:40:35 -0700240 }
Jeff Vander Stoepbf7a9022021-01-26 14:35:38 +0100241 if ctx.Device() {
242 flags.RustFlags = append(flags.RustFlags, "-Z panic_abort_tests")
243 }
Colin Cross225a37a2023-01-11 14:17:39 -0800244
Ivan Lozano9bdb4af2025-03-06 21:28:38 +0000245 // Add a default rpath to allow tests to dlopen libraries specified in data_libs.
246 flags.GlobalLinkFlags = append(flags.GlobalLinkFlags, `-Wl,-rpath,\$$ORIGIN/lib64`)
247 flags.GlobalLinkFlags = append(flags.GlobalLinkFlags, `-Wl,-rpath,\$$ORIGIN/lib`)
248
Chih-Hung Hsieha5f22ed2019-10-24 20:47:54 -0700249 return flags
250}
251
Liz Kammer356f7d42021-01-26 09:18:53 -0500252func (test *testDecorator) autoDep(ctx android.BottomUpMutatorContext) autoDep {
Matthew Maurer0f003b12020-06-29 14:34:06 -0700253 return rlibAutoDep
254}
255
Chih-Hung Hsieha5f22ed2019-10-24 20:47:54 -0700256func init() {
257 // Rust tests are binary files built with --test.
258 android.RegisterModuleType("rust_test", RustTestFactory)
259 android.RegisterModuleType("rust_test_host", RustTestHostFactory)
260}
261
262func RustTestFactory() android.Module {
263 module, _ := NewRustTest(android.HostAndDeviceSupported)
Ivan Lozanof5c98a22021-12-07 10:17:00 -0500264
265 // NewRustTest will set MultilibBoth true, however the host variant
266 // cannot produce the non-primary target. Therefore, add the
267 // rustTestHostMultilib load hook to set MultilibFirst for the
268 // host target.
269 android.AddLoadHook(module, rustTestHostMultilib)
Aditya Choudhary87b2ab22023-11-17 15:27:06 +0000270 module.testModule = true
Chih-Hung Hsieha5f22ed2019-10-24 20:47:54 -0700271 return module.Init()
272}
273
274func RustTestHostFactory() android.Module {
275 module, _ := NewRustTest(android.HostSupported)
Aditya Choudhary87b2ab22023-11-17 15:27:06 +0000276 module.testModule = true
Chih-Hung Hsieha5f22ed2019-10-24 20:47:54 -0700277 return module.Init()
278}
Ivan Lozano2b081132020-09-08 12:46:52 -0400279
Ivan Lozano806efd32024-12-11 21:38:53 +0000280func (test *testDecorator) stdLinkage(device bool) RustLinkage {
Ivan Lozanodd055472020-09-28 13:22:45 -0400281 return RlibLinkage
Ivan Lozano2b081132020-09-08 12:46:52 -0400282}
Ivan Lozano3ee74c82021-07-15 15:44:10 -0400283
284func (test *testDecorator) compilerDeps(ctx DepsContext, deps Deps) Deps {
285 deps = test.binaryDecorator.compilerDeps(ctx, deps)
286
287 deps.Rustlibs = append(deps.Rustlibs, "libtest")
288
Ivan Lozano4e5f07d2021-11-04 14:09:38 -0400289 deps.DataLibs = append(deps.DataLibs, test.Properties.Data_libs...)
290 deps.DataBins = append(deps.DataBins, test.Properties.Data_bins...)
291
Ivan Lozano3ee74c82021-07-15 15:44:10 -0400292 return deps
293}
Ivan Lozano62cd0382021-11-01 10:27:54 -0400294
295func (test *testDecorator) testBinary() bool {
296 return true
297}
Ivan Lozanof5c98a22021-12-07 10:17:00 -0500298
Cole Faust58eef4f2025-01-29 15:14:17 -0800299func (test *testDecorator) moduleInfoJSON(ctx ModuleContext, moduleInfoJSON *android.ModuleInfoJSON) {
300 test.binaryDecorator.moduleInfoJSON(ctx, moduleInfoJSON)
301 moduleInfoJSON.Class = []string{"NATIVE_TESTS"}
302 if Bool(test.Properties.Test_options.Unit_test) {
303 moduleInfoJSON.IsUnitTest = "true"
304 if ctx.Host() {
305 moduleInfoJSON.CompatibilitySuites = append(moduleInfoJSON.CompatibilitySuites, "host-unit-tests")
306 }
307 }
308 moduleInfoJSON.TestOptionsTags = append(moduleInfoJSON.TestOptionsTags, test.Properties.Test_options.Tags...)
309 if test.testConfig != nil {
310 if _, ok := test.testConfig.(android.WritablePath); ok {
311 moduleInfoJSON.AutoTestConfig = []string{"true"}
312 }
313 moduleInfoJSON.TestConfig = append(moduleInfoJSON.TestConfig, test.testConfig.String())
314 }
315
316 moduleInfoJSON.DataDependencies = append(moduleInfoJSON.DataDependencies, test.Properties.Data_bins...)
317
318 if len(test.Properties.Test_suites) > 0 {
319 moduleInfoJSON.CompatibilitySuites = append(moduleInfoJSON.CompatibilitySuites, test.Properties.Test_suites...)
320 } else {
321 moduleInfoJSON.CompatibilitySuites = append(moduleInfoJSON.CompatibilitySuites, "null-suite")
322 }
Cole Faust5e1454a2025-03-11 15:55:59 -0700323
324 android.SetProvider(ctx, android.TestSuiteInfoProvider, android.TestSuiteInfo{
325 TestSuites: test.Properties.Test_suites,
326 })
Cole Faust58eef4f2025-01-29 15:14:17 -0800327}
328
Ivan Lozanof5c98a22021-12-07 10:17:00 -0500329func rustTestHostMultilib(ctx android.LoadHookContext) {
330 type props struct {
331 Target struct {
332 Host struct {
333 Compile_multilib *string
334 }
335 }
336 }
337 p := &props{}
338 p.Target.Host.Compile_multilib = proptools.StringPtr("first")
339 ctx.AppendProperties(p)
340}