// Copyright 2017 Google Inc. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package python import ( "fmt" "android/soong/testing" "github.com/google/blueprint/proptools" "android/soong/android" "android/soong/tradefed" ) // This file contains the module types for building Python test. func init() { registerPythonTestComponents(android.InitRegistrationContext) } func registerPythonTestComponents(ctx android.RegistrationContext) { ctx.RegisterModuleType("python_test_host", PythonTestHostFactory) ctx.RegisterModuleType("python_test", PythonTestFactory) } func NewTest(hod android.HostOrDeviceSupported) *PythonTestModule { p := &PythonTestModule{PythonBinaryModule: *NewBinary(hod)} p.sourceProperties = android.SourceProperties{Test_only: proptools.BoolPtr(true), Top_level_test_target: true} return p } func PythonTestHostFactory() android.Module { return NewTest(android.HostSupported).init() } func PythonTestFactory() android.Module { module := NewTest(android.HostAndDeviceSupported) module.multilib = android.MultilibBoth return module.init() } type TestProperties struct { // the name of the test configuration (for example "AndroidTest.xml") that should be // installed with the module. Test_config *string `android:"path,arch_variant"` // the name of the test configuration template (for example "AndroidTestTemplate.xml") that // should be installed with the module. Test_config_template *string `android:"path,arch_variant"` // list of files or filegroup modules that provide data that should be installed alongside // the test Data []string `android:"path,arch_variant"` // list of java modules that provide data that should be installed alongside the test. Java_data []string // Test options. Test_options TestOptions // list of device binary modules that should be installed alongside the test // This property adds 64bit AND 32bit variants of the dependency Data_device_bins_both []string `android:"arch_variant"` } type TestOptions struct { android.CommonTestOptions // Runner for the test. Supports "tradefed" and "mobly" (for multi-device tests). Default is "tradefed". Runner *string // Metadata to describe the test configuration. Metadata []Metadata } type Metadata struct { Name string Value string } type PythonTestModule struct { PythonBinaryModule testProperties TestProperties testConfig android.Path data []android.DataPath } func (p *PythonTestModule) init() android.Module { p.AddProperties(&p.properties, &p.protoProperties) p.AddProperties(&p.binaryProperties) p.AddProperties(&p.testProperties) android.InitAndroidArchModule(p, p.hod, p.multilib) android.InitDefaultableModule(p) if p.isTestHost() && p.testProperties.Test_options.Unit_test == nil { p.testProperties.Test_options.Unit_test = proptools.BoolPtr(true) } return p } func (p *PythonTestModule) isTestHost() bool { return p.hod == android.HostSupported } var dataDeviceBinsTag = dependencyTag{name: "dataDeviceBins"} // python_test_host DepsMutator uses this method to add multilib dependencies of // data_device_bin_both func (p *PythonTestModule) addDataDeviceBinsDeps(ctx android.BottomUpMutatorContext, filter string) { if len(p.testProperties.Data_device_bins_both) < 1 { return } var maybeAndroidTarget *android.Target androidTargetList := android.FirstTarget(ctx.Config().Targets[android.Android], filter) if len(androidTargetList) > 0 { maybeAndroidTarget = &androidTargetList[0] } if maybeAndroidTarget != nil { ctx.AddFarVariationDependencies( maybeAndroidTarget.Variations(), dataDeviceBinsTag, p.testProperties.Data_device_bins_both..., ) } } func (p *PythonTestModule) DepsMutator(ctx android.BottomUpMutatorContext) { p.PythonBinaryModule.DepsMutator(ctx) if p.isTestHost() { p.addDataDeviceBinsDeps(ctx, "lib32") p.addDataDeviceBinsDeps(ctx, "lib64") } } func (p *PythonTestModule) GenerateAndroidBuildActions(ctx android.ModuleContext) { // We inherit from only the library's GenerateAndroidBuildActions, and then // just use buildBinary() so that the binary is not installed into the location // it would be for regular binaries. p.PythonLibraryModule.GenerateAndroidBuildActions(ctx) p.buildBinary(ctx) var configs []tradefed.Option for _, metadata := range p.testProperties.Test_options.Metadata { configs = append(configs, tradefed.Option{Name: "config-descriptor:metadata", Key: metadata.Name, Value: metadata.Value}) } runner := proptools.StringDefault(p.testProperties.Test_options.Runner, "tradefed") template := "${PythonBinaryHostTestConfigTemplate}" if runner == "mobly" { // Add tag to enable Atest mobly runner if !android.InList("mobly", p.testProperties.Test_options.Tags) { p.testProperties.Test_options.Tags = append(p.testProperties.Test_options.Tags, "mobly") } template = "${PythonBinaryHostMoblyTestConfigTemplate}" } else if runner != "tradefed" { panic(fmt.Errorf("unknown python test runner '%s', should be 'tradefed' or 'mobly'", runner)) } p.testConfig = tradefed.AutoGenTestConfig(ctx, tradefed.AutoGenTestConfigOptions{ TestConfigProp: p.testProperties.Test_config, TestConfigTemplateProp: p.testProperties.Test_config_template, TestSuites: p.binaryProperties.Test_suites, OptionsForAutogenerated: configs, AutoGenConfig: p.binaryProperties.Auto_gen_config, DeviceTemplate: template, HostTemplate: template, }) for _, dataSrcPath := range android.PathsForModuleSrc(ctx, p.testProperties.Data) { p.data = append(p.data, android.DataPath{SrcPath: dataSrcPath}) } if p.isTestHost() && len(p.testProperties.Data_device_bins_both) > 0 { ctx.VisitDirectDepsWithTag(dataDeviceBinsTag, func(dep android.Module) { p.data = append(p.data, android.DataPath{SrcPath: android.OutputFileForModule(ctx, dep, "")}) }) } // Emulate the data property for java_data dependencies. for _, javaData := range ctx.GetDirectDepsWithTag(javaDataTag) { for _, javaDataSrcPath := range android.OutputFilesForModule(ctx, javaData, "") { p.data = append(p.data, android.DataPath{SrcPath: javaDataSrcPath}) } } installDir := installDir(ctx, "nativetest", "nativetest64", ctx.ModuleName()) installedData := ctx.InstallTestData(installDir, p.data) p.installedDest = ctx.InstallFile(installDir, p.installSource.Base(), p.installSource, installedData...) android.SetProvider(ctx, testing.TestModuleProviderKey, testing.TestModuleProviderData{}) } func (p *PythonTestModule) AndroidMkEntries() []android.AndroidMkEntries { entriesList := p.PythonBinaryModule.AndroidMkEntries() if len(entriesList) != 1 { panic("Expected 1 entry") } entries := &entriesList[0] entries.Class = "NATIVE_TESTS" entries.ExtraEntries = append(entries.ExtraEntries, func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) { //entries.AddCompatibilityTestSuites(p.binaryProperties.Test_suites...) if p.testConfig != nil { entries.SetString("LOCAL_FULL_TEST_CONFIG", p.testConfig.String()) } // ATS 2.0 is the test harness for mobly tests and the test config is for ATS 2.0. // Add "v2" suffix to test config name to distinguish it from the config for TF. if proptools.String(p.testProperties.Test_options.Runner) == "mobly" { entries.SetString("LOCAL_TEST_CONFIG_SUFFIX", "v2") } entries.SetBoolIfTrue("LOCAL_DISABLE_AUTO_GENERATE_TEST_CONFIG", !BoolDefault(p.binaryProperties.Auto_gen_config, true)) p.testProperties.Test_options.SetAndroidMkEntries(entries) }) return entriesList }