1// Copyright 2016 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 cc 16 17import ( 18 "path/filepath" 19 "strconv" 20 "strings" 21 22 "android/soong/android" 23 "android/soong/tradefed" 24) 25 26type TestProperties struct { 27 // if set, build against the gtest library. Defaults to true. 28 Gtest *bool 29 30 // if set, use the isolated gtest runner. Defaults to false. 31 Isolated *bool 32 33 // List of APEXes that this module tests. The module has access to 34 // the private part of the listed APEXes even when it is not included in the 35 // APEXes. 36 Test_for []string 37} 38 39// Test option struct. 40type TestOptions struct { 41 // The UID that you want to run the test as on a device. 42 Run_test_as *string 43 // A list of free-formed strings without spaces that categorize the test. 44 Test_suite_tag []string 45} 46 47type TestBinaryProperties struct { 48 // Create a separate binary for each source file. Useful when there is 49 // global state that can not be torn down and reset between each test suite. 50 Test_per_src *bool 51 52 // Disables the creation of a test-specific directory when used with 53 // relative_install_path. Useful if several tests need to be in the same 54 // directory, but test_per_src doesn't work. 55 No_named_install_directory *bool 56 57 // list of files or filegroup modules that provide data that should be installed alongside 58 // the test 59 Data []string `android:"path,arch_variant"` 60 61 // list of shared library modules that should be installed alongside the test 62 Data_libs []string `android:"arch_variant"` 63 64 // list of compatibility suites (for example "cts", "vts") that the module should be 65 // installed into. 66 Test_suites []string `android:"arch_variant"` 67 68 // the name of the test configuration (for example "AndroidTest.xml") that should be 69 // installed with the module. 70 Test_config *string `android:"path,arch_variant"` 71 72 // the name of the test configuration template (for example "AndroidTestTemplate.xml") that 73 // should be installed with the module. 74 Test_config_template *string `android:"path,arch_variant"` 75 76 // Test options. 77 Test_options TestOptions 78 79 // Add RootTargetPreparer to auto generated test config. This guarantees the test to run 80 // with root permission. 81 Require_root *bool 82 83 // Add RunCommandTargetPreparer to stop framework before the test and start it after the test. 84 Disable_framework *bool 85 86 // Add MinApiLevelModuleController to auto generated test config. If the device property of 87 // "ro.product.first_api_level" < Test_min_api_level, then skip this module. 88 Test_min_api_level *int64 89 90 // Add MinApiLevelModuleController to auto generated test config. If the device property of 91 // "ro.build.version.sdk" < Test_min_sdk_version, then skip this module. 92 Test_min_sdk_version *int64 93 94 // Flag to indicate whether or not to create test config automatically. If AndroidTest.xml 95 // doesn't exist next to the Android.bp, this attribute doesn't need to be set to true 96 // explicitly. 97 Auto_gen_config *bool 98 99 // Add parameterized mainline modules to auto generated test config. The options will be 100 // handled by TradeFed to download and install the specified modules on the device. 101 Test_mainline_modules []string 102} 103 104func init() { 105 android.RegisterModuleType("cc_test", TestFactory) 106 android.RegisterModuleType("cc_test_library", TestLibraryFactory) 107 android.RegisterModuleType("cc_benchmark", BenchmarkFactory) 108 android.RegisterModuleType("cc_test_host", TestHostFactory) 109 android.RegisterModuleType("cc_benchmark_host", BenchmarkHostFactory) 110} 111 112// cc_test generates a test config file and an executable binary file to test 113// specific functionality on a device. The executable binary gets an implicit 114// static_libs dependency on libgtests unless the gtest flag is set to false. 115func TestFactory() android.Module { 116 module := NewTest(android.HostAndDeviceSupported) 117 return module.Init() 118} 119 120// cc_test_library creates an archive of files (i.e. .o files) which is later 121// referenced by another module (such as cc_test, cc_defaults or cc_test_library) 122// for archiving or linking. 123func TestLibraryFactory() android.Module { 124 module := NewTestLibrary(android.HostAndDeviceSupported) 125 return module.Init() 126} 127 128// cc_benchmark compiles an executable binary that performs benchmark testing 129// of a specific component in a device. Additional files such as test suites 130// and test configuration are installed on the side of the compiled executed 131// binary. 132func BenchmarkFactory() android.Module { 133 module := NewBenchmark(android.HostAndDeviceSupported) 134 return module.Init() 135} 136 137// cc_test_host compiles a test host binary. 138func TestHostFactory() android.Module { 139 module := NewTest(android.HostSupported) 140 return module.Init() 141} 142 143// cc_benchmark_host compiles an executable binary that performs benchmark 144// testing of a specific component in the host. Additional files such as 145// test suites and test configuration are installed on the side of the 146// compiled executed binary. 147func BenchmarkHostFactory() android.Module { 148 module := NewBenchmark(android.HostSupported) 149 return module.Init() 150} 151 152type testPerSrc interface { 153 testPerSrc() bool 154 srcs() []string 155 isAllTestsVariation() bool 156 setSrc(string, string) 157 unsetSrc() 158} 159 160func (test *testBinary) testPerSrc() bool { 161 return Bool(test.Properties.Test_per_src) 162} 163 164func (test *testBinary) srcs() []string { 165 return test.baseCompiler.Properties.Srcs 166} 167 168func (test *testBinary) dataPaths() []android.DataPath { 169 return test.data 170} 171 172func (test *testBinary) isAllTestsVariation() bool { 173 stem := test.binaryDecorator.Properties.Stem 174 return stem != nil && *stem == "" 175} 176 177func (test *testBinary) setSrc(name, src string) { 178 test.baseCompiler.Properties.Srcs = []string{src} 179 test.binaryDecorator.Properties.Stem = StringPtr(name) 180} 181 182func (test *testBinary) unsetSrc() { 183 test.baseCompiler.Properties.Srcs = nil 184 test.binaryDecorator.Properties.Stem = StringPtr("") 185} 186 187var _ testPerSrc = (*testBinary)(nil) 188 189func TestPerSrcMutator(mctx android.BottomUpMutatorContext) { 190 if m, ok := mctx.Module().(*Module); ok { 191 if test, ok := m.linker.(testPerSrc); ok { 192 numTests := len(test.srcs()) 193 if test.testPerSrc() && numTests > 0 { 194 if duplicate, found := android.CheckDuplicate(test.srcs()); found { 195 mctx.PropertyErrorf("srcs", "found a duplicate entry %q", duplicate) 196 return 197 } 198 testNames := make([]string, numTests) 199 for i, src := range test.srcs() { 200 testNames[i] = strings.TrimSuffix(filepath.Base(src), filepath.Ext(src)) 201 } 202 // In addition to creating one variation per test source file, 203 // create an additional "all tests" variation named "", and have it 204 // depends on all other test_per_src variations. This is useful to 205 // create subsequent dependencies of a given module on all 206 // test_per_src variations created above: by depending on 207 // variation "", that module will transitively depend on all the 208 // other test_per_src variations without the need to know their 209 // name or even their number. 210 testNames = append(testNames, "") 211 tests := mctx.CreateLocalVariations(testNames...) 212 all_tests := tests[numTests] 213 all_tests.(*Module).linker.(testPerSrc).unsetSrc() 214 // Prevent the "all tests" variation from being installable nor 215 // exporting to Make, as it won't create any output file. 216 all_tests.(*Module).Properties.PreventInstall = true 217 all_tests.(*Module).Properties.HideFromMake = true 218 for i, src := range test.srcs() { 219 tests[i].(*Module).linker.(testPerSrc).setSrc(testNames[i], src) 220 mctx.AddInterVariantDependency(testPerSrcDepTag, all_tests, tests[i]) 221 } 222 } 223 } 224 } 225} 226 227type testDecorator struct { 228 Properties TestProperties 229 linker *baseLinker 230} 231 232func (test *testDecorator) gtest() bool { 233 return BoolDefault(test.Properties.Gtest, true) 234} 235 236func (test *testDecorator) testFor() []string { 237 return test.Properties.Test_for 238} 239 240func (test *testDecorator) linkerFlags(ctx ModuleContext, flags Flags) Flags { 241 if !test.gtest() { 242 return flags 243 } 244 245 flags.Local.CFlags = append(flags.Local.CFlags, "-DGTEST_HAS_STD_STRING") 246 if ctx.Host() { 247 flags.Local.CFlags = append(flags.Local.CFlags, "-O0", "-g") 248 249 switch ctx.Os() { 250 case android.Windows: 251 flags.Local.CFlags = append(flags.Local.CFlags, "-DGTEST_OS_WINDOWS") 252 case android.Linux: 253 flags.Local.CFlags = append(flags.Local.CFlags, "-DGTEST_OS_LINUX") 254 case android.Darwin: 255 flags.Local.CFlags = append(flags.Local.CFlags, "-DGTEST_OS_MAC") 256 } 257 } else { 258 flags.Local.CFlags = append(flags.Local.CFlags, "-DGTEST_OS_LINUX_ANDROID") 259 } 260 261 return flags 262} 263 264func (test *testDecorator) linkerDeps(ctx BaseModuleContext, deps Deps) Deps { 265 if test.gtest() { 266 if ctx.useSdk() && ctx.Device() { 267 deps.StaticLibs = append(deps.StaticLibs, "libgtest_main_ndk_c++", "libgtest_ndk_c++") 268 } else if BoolDefault(test.Properties.Isolated, false) { 269 deps.StaticLibs = append(deps.StaticLibs, "libgtest_isolated_main") 270 // The isolated library requires liblog, but adding it 271 // as a static library means unit tests cannot override 272 // liblog functions. Instead make it a shared library 273 // dependency. 274 deps.SharedLibs = append(deps.SharedLibs, "liblog") 275 } else { 276 deps.StaticLibs = append(deps.StaticLibs, "libgtest_main", "libgtest") 277 } 278 } 279 280 return deps 281} 282 283func (test *testDecorator) linkerInit(ctx BaseModuleContext, linker *baseLinker) { 284 // 1. Add ../../lib[64] to rpath so that out/host/linux-x86/nativetest/<test dir>/<test> can 285 // find out/host/linux-x86/lib[64]/library.so 286 // 2. Add ../../../lib[64] to rpath so that out/host/linux-x86/testcases/<test dir>/<CPU>/<test> can 287 // also find out/host/linux-x86/lib[64]/library.so 288 runpaths := []string{"../../lib", "../../../lib"} 289 for _, runpath := range runpaths { 290 if ctx.toolchain().Is64Bit() { 291 runpath += "64" 292 } 293 linker.dynamicProperties.RunPaths = append(linker.dynamicProperties.RunPaths, runpath) 294 } 295 296 // add "" to rpath so that test binaries can find libraries in their own test directory 297 linker.dynamicProperties.RunPaths = append(linker.dynamicProperties.RunPaths, "") 298} 299 300func (test *testDecorator) linkerProps() []interface{} { 301 return []interface{}{&test.Properties} 302} 303 304func NewTestInstaller() *baseInstaller { 305 return NewBaseInstaller("nativetest", "nativetest64", InstallInData) 306} 307 308type testBinary struct { 309 testDecorator 310 *binaryDecorator 311 *baseCompiler 312 Properties TestBinaryProperties 313 data []android.DataPath 314 testConfig android.Path 315} 316 317func (test *testBinary) linkerProps() []interface{} { 318 props := append(test.testDecorator.linkerProps(), test.binaryDecorator.linkerProps()...) 319 props = append(props, &test.Properties) 320 return props 321} 322 323func (test *testBinary) linkerInit(ctx BaseModuleContext) { 324 test.testDecorator.linkerInit(ctx, test.binaryDecorator.baseLinker) 325 test.binaryDecorator.linkerInit(ctx) 326} 327 328func (test *testBinary) linkerDeps(ctx DepsContext, deps Deps) Deps { 329 deps = test.testDecorator.linkerDeps(ctx, deps) 330 deps = test.binaryDecorator.linkerDeps(ctx, deps) 331 deps.DataLibs = append(deps.DataLibs, test.Properties.Data_libs...) 332 return deps 333} 334 335func (test *testBinary) linkerFlags(ctx ModuleContext, flags Flags) Flags { 336 flags = test.binaryDecorator.linkerFlags(ctx, flags) 337 flags = test.testDecorator.linkerFlags(ctx, flags) 338 return flags 339} 340 341func (test *testBinary) install(ctx ModuleContext, file android.Path) { 342 dataSrcPaths := android.PathsForModuleSrc(ctx, test.Properties.Data) 343 344 for _, dataSrcPath := range dataSrcPaths { 345 test.data = append(test.data, android.DataPath{SrcPath: dataSrcPath}) 346 } 347 348 ctx.VisitDirectDepsWithTag(dataLibDepTag, func(dep android.Module) { 349 depName := ctx.OtherModuleName(dep) 350 ccDep, ok := dep.(LinkableInterface) 351 352 if !ok { 353 ctx.ModuleErrorf("data_lib %q is not a linkable cc module", depName) 354 } 355 ccModule, ok := dep.(*Module) 356 if !ok { 357 ctx.ModuleErrorf("data_lib %q is not a cc module", depName) 358 } 359 if ccDep.OutputFile().Valid() { 360 test.data = append(test.data, 361 android.DataPath{SrcPath: ccDep.OutputFile().Path(), 362 RelativeInstallPath: ccModule.installer.relativeInstallPath()}) 363 } 364 }) 365 366 var api_level_prop string 367 var configs []tradefed.Config 368 var min_level string 369 for _, module := range test.Properties.Test_mainline_modules { 370 configs = append(configs, tradefed.Option{Name: "config-descriptor:metadata", Key: "mainline-param", Value: module}) 371 } 372 if Bool(test.Properties.Require_root) { 373 configs = append(configs, tradefed.Object{"target_preparer", "com.android.tradefed.targetprep.RootTargetPreparer", nil}) 374 } else { 375 var options []tradefed.Option 376 options = append(options, tradefed.Option{Name: "force-root", Value: "false"}) 377 configs = append(configs, tradefed.Object{"target_preparer", "com.android.tradefed.targetprep.RootTargetPreparer", options}) 378 } 379 if Bool(test.Properties.Disable_framework) { 380 var options []tradefed.Option 381 configs = append(configs, tradefed.Object{"target_preparer", "com.android.tradefed.targetprep.StopServicesSetup", options}) 382 } 383 if Bool(test.testDecorator.Properties.Isolated) { 384 configs = append(configs, tradefed.Option{Name: "not-shardable", Value: "true"}) 385 } 386 if test.Properties.Test_options.Run_test_as != nil { 387 configs = append(configs, tradefed.Option{Name: "run-test-as", Value: String(test.Properties.Test_options.Run_test_as)}) 388 } 389 for _, tag := range test.Properties.Test_options.Test_suite_tag { 390 configs = append(configs, tradefed.Option{Name: "test-suite-tag", Value: tag}) 391 } 392 if test.Properties.Test_min_api_level != nil && test.Properties.Test_min_sdk_version != nil { 393 ctx.PropertyErrorf("test_min_api_level", "'test_min_api_level' and 'test_min_sdk_version' should not be set at the same time.") 394 } else if test.Properties.Test_min_api_level != nil { 395 api_level_prop = "ro.product.first_api_level" 396 min_level = strconv.FormatInt(int64(*test.Properties.Test_min_api_level), 10) 397 } else if test.Properties.Test_min_sdk_version != nil { 398 api_level_prop = "ro.build.version.sdk" 399 min_level = strconv.FormatInt(int64(*test.Properties.Test_min_sdk_version), 10) 400 } 401 if api_level_prop != "" { 402 var options []tradefed.Option 403 options = append(options, tradefed.Option{Name: "min-api-level", Value: min_level}) 404 options = append(options, tradefed.Option{Name: "api-level-prop", Value: api_level_prop}) 405 configs = append(configs, tradefed.Object{"module_controller", "com.android.tradefed.testtype.suite.module.MinApiLevelModuleController", options}) 406 } 407 408 test.testConfig = tradefed.AutoGenNativeTestConfig(ctx, test.Properties.Test_config, 409 test.Properties.Test_config_template, test.Properties.Test_suites, configs, test.Properties.Auto_gen_config) 410 411 test.binaryDecorator.baseInstaller.dir = "nativetest" 412 test.binaryDecorator.baseInstaller.dir64 = "nativetest64" 413 414 if !Bool(test.Properties.No_named_install_directory) { 415 test.binaryDecorator.baseInstaller.relative = ctx.ModuleName() 416 } else if String(test.binaryDecorator.baseInstaller.Properties.Relative_install_path) == "" { 417 ctx.PropertyErrorf("no_named_install_directory", "Module install directory may only be disabled if relative_install_path is set") 418 } 419 420 test.binaryDecorator.baseInstaller.install(ctx, file) 421} 422 423func NewTest(hod android.HostOrDeviceSupported) *Module { 424 module, binary := NewBinary(hod) 425 module.multilib = android.MultilibBoth 426 binary.baseInstaller = NewTestInstaller() 427 428 test := &testBinary{ 429 testDecorator: testDecorator{ 430 linker: binary.baseLinker, 431 }, 432 binaryDecorator: binary, 433 baseCompiler: NewBaseCompiler(), 434 } 435 module.compiler = test 436 module.linker = test 437 module.installer = test 438 return module 439} 440 441type testLibrary struct { 442 testDecorator 443 *libraryDecorator 444} 445 446func (test *testLibrary) linkerProps() []interface{} { 447 return append(test.testDecorator.linkerProps(), test.libraryDecorator.linkerProps()...) 448} 449 450func (test *testLibrary) linkerInit(ctx BaseModuleContext) { 451 test.testDecorator.linkerInit(ctx, test.libraryDecorator.baseLinker) 452 test.libraryDecorator.linkerInit(ctx) 453} 454 455func (test *testLibrary) linkerDeps(ctx DepsContext, deps Deps) Deps { 456 deps = test.testDecorator.linkerDeps(ctx, deps) 457 deps = test.libraryDecorator.linkerDeps(ctx, deps) 458 return deps 459} 460 461func (test *testLibrary) linkerFlags(ctx ModuleContext, flags Flags) Flags { 462 flags = test.libraryDecorator.linkerFlags(ctx, flags) 463 flags = test.testDecorator.linkerFlags(ctx, flags) 464 return flags 465} 466 467func NewTestLibrary(hod android.HostOrDeviceSupported) *Module { 468 module, library := NewLibrary(android.HostAndDeviceSupported) 469 library.baseInstaller = NewTestInstaller() 470 test := &testLibrary{ 471 testDecorator: testDecorator{ 472 linker: library.baseLinker, 473 }, 474 libraryDecorator: library, 475 } 476 module.linker = test 477 return module 478} 479 480type BenchmarkProperties struct { 481 // list of files or filegroup modules that provide data that should be installed alongside 482 // the test 483 Data []string `android:"path"` 484 485 // list of compatibility suites (for example "cts", "vts") that the module should be 486 // installed into. 487 Test_suites []string `android:"arch_variant"` 488 489 // the name of the test configuration (for example "AndroidTest.xml") that should be 490 // installed with the module. 491 Test_config *string `android:"path,arch_variant"` 492 493 // the name of the test configuration template (for example "AndroidTestTemplate.xml") that 494 // should be installed with the module. 495 Test_config_template *string `android:"path,arch_variant"` 496 497 // Add RootTargetPreparer to auto generated test config. This guarantees the test to run 498 // with root permission. 499 Require_root *bool 500 501 // Flag to indicate whether or not to create test config automatically. If AndroidTest.xml 502 // doesn't exist next to the Android.bp, this attribute doesn't need to be set to true 503 // explicitly. 504 Auto_gen_config *bool 505} 506 507type benchmarkDecorator struct { 508 *binaryDecorator 509 Properties BenchmarkProperties 510 data android.Paths 511 testConfig android.Path 512} 513 514func (benchmark *benchmarkDecorator) linkerInit(ctx BaseModuleContext) { 515 runpath := "../../lib" 516 if ctx.toolchain().Is64Bit() { 517 runpath += "64" 518 } 519 benchmark.baseLinker.dynamicProperties.RunPaths = append(benchmark.baseLinker.dynamicProperties.RunPaths, runpath) 520 benchmark.binaryDecorator.linkerInit(ctx) 521} 522 523func (benchmark *benchmarkDecorator) linkerProps() []interface{} { 524 props := benchmark.binaryDecorator.linkerProps() 525 props = append(props, &benchmark.Properties) 526 return props 527} 528 529func (benchmark *benchmarkDecorator) linkerDeps(ctx DepsContext, deps Deps) Deps { 530 deps = benchmark.binaryDecorator.linkerDeps(ctx, deps) 531 deps.StaticLibs = append(deps.StaticLibs, "libgoogle-benchmark") 532 return deps 533} 534 535func (benchmark *benchmarkDecorator) install(ctx ModuleContext, file android.Path) { 536 benchmark.data = android.PathsForModuleSrc(ctx, benchmark.Properties.Data) 537 538 var configs []tradefed.Config 539 if Bool(benchmark.Properties.Require_root) { 540 configs = append(configs, tradefed.Object{"target_preparer", "com.android.tradefed.targetprep.RootTargetPreparer", nil}) 541 } 542 benchmark.testConfig = tradefed.AutoGenNativeBenchmarkTestConfig(ctx, benchmark.Properties.Test_config, 543 benchmark.Properties.Test_config_template, benchmark.Properties.Test_suites, configs, benchmark.Properties.Auto_gen_config) 544 545 benchmark.binaryDecorator.baseInstaller.dir = filepath.Join("benchmarktest", ctx.ModuleName()) 546 benchmark.binaryDecorator.baseInstaller.dir64 = filepath.Join("benchmarktest64", ctx.ModuleName()) 547 benchmark.binaryDecorator.baseInstaller.install(ctx, file) 548} 549 550func NewBenchmark(hod android.HostOrDeviceSupported) *Module { 551 module, binary := NewBinary(hod) 552 module.multilib = android.MultilibBoth 553 binary.baseInstaller = NewBaseInstaller("benchmarktest", "benchmarktest64", InstallInData) 554 555 benchmark := &benchmarkDecorator{ 556 binaryDecorator: binary, 557 } 558 module.linker = benchmark 559 module.installer = benchmark 560 return module 561} 562