1// Copyright 2017 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 python 16 17import ( 18 "fmt" 19 20 "github.com/google/blueprint/proptools" 21 22 "android/soong/android" 23 "android/soong/tradefed" 24) 25 26// This file contains the module types for building Python test. 27 28func init() { 29 registerPythonTestComponents(android.InitRegistrationContext) 30} 31 32func registerPythonTestComponents(ctx android.RegistrationContext) { 33 ctx.RegisterModuleType("python_test_host", PythonTestHostFactory) 34 ctx.RegisterModuleType("python_test", PythonTestFactory) 35} 36 37func NewTest(hod android.HostOrDeviceSupported) *PythonTestModule { 38 p := &PythonTestModule{PythonBinaryModule: *NewBinary(hod)} 39 p.sourceProperties = android.SourceProperties{Test_only: proptools.BoolPtr(true), Top_level_test_target: true} 40 return p 41} 42 43func PythonTestHostFactory() android.Module { 44 return NewTest(android.HostSupported).init() 45} 46 47func PythonTestFactory() android.Module { 48 module := NewTest(android.HostAndDeviceSupported) 49 module.multilib = android.MultilibBoth 50 return module.init() 51} 52 53type TestProperties struct { 54 // the name of the test configuration (for example "AndroidTest.xml") that should be 55 // installed with the module. 56 Test_config *string `android:"path,arch_variant"` 57 58 // the name of the test configuration template (for example "AndroidTestTemplate.xml") that 59 // should be installed with the module. 60 Test_config_template *string `android:"path,arch_variant"` 61 62 // list of files or filegroup modules that provide data that should be installed alongside 63 // the test 64 Data []string `android:"path,arch_variant"` 65 66 // Same as data, but will add dependencies on modules using the device's os variation and 67 // the common arch variation. Useful for a host test that wants to embed a module built for 68 // device. 69 Device_common_data []string `android:"path_device_common"` 70 71 // list of java modules that provide data that should be installed alongside the test. 72 Java_data []string 73 74 // Test options. 75 Test_options TestOptions 76 77 // list of device binary modules that should be installed alongside the test 78 // This property adds 64bit AND 32bit variants of the dependency 79 Data_device_bins_both []string `android:"arch_variant"` 80} 81 82type TestOptions struct { 83 android.CommonTestOptions 84 85 // Runner for the test. Supports "tradefed" and "mobly" (for multi-device tests). Default is "tradefed". 86 Runner *string 87 88 // Metadata to describe the test configuration. 89 Metadata []Metadata 90} 91 92type Metadata struct { 93 Name string 94 Value string 95} 96 97type PythonTestModule struct { 98 PythonBinaryModule 99 100 testProperties TestProperties 101 testConfig android.Path 102 data []android.DataPath 103} 104 105func (p *PythonTestModule) init() android.Module { 106 p.AddProperties(&p.properties, &p.protoProperties) 107 p.AddProperties(&p.binaryProperties) 108 p.AddProperties(&p.testProperties) 109 android.InitAndroidArchModule(p, p.hod, p.multilib) 110 android.InitDefaultableModule(p) 111 if p.isTestHost() && p.testProperties.Test_options.Unit_test == nil { 112 p.testProperties.Test_options.Unit_test = proptools.BoolPtr(true) 113 } 114 return p 115} 116 117func (p *PythonTestModule) isTestHost() bool { 118 return p.hod == android.HostSupported 119} 120 121var dataDeviceBinsTag = dependencyTag{name: "dataDeviceBins"} 122 123// python_test_host DepsMutator uses this method to add multilib dependencies of 124// data_device_bin_both 125func (p *PythonTestModule) addDataDeviceBinsDeps(ctx android.BottomUpMutatorContext, filter string) { 126 if len(p.testProperties.Data_device_bins_both) < 1 { 127 return 128 } 129 130 var maybeAndroidTarget *android.Target 131 androidTargetList := android.FirstTarget(ctx.Config().Targets[android.Android], filter) 132 if len(androidTargetList) > 0 { 133 maybeAndroidTarget = &androidTargetList[0] 134 } 135 136 if maybeAndroidTarget != nil { 137 ctx.AddFarVariationDependencies( 138 maybeAndroidTarget.Variations(), 139 dataDeviceBinsTag, 140 p.testProperties.Data_device_bins_both..., 141 ) 142 } 143} 144 145func (p *PythonTestModule) DepsMutator(ctx android.BottomUpMutatorContext) { 146 p.PythonBinaryModule.DepsMutator(ctx) 147 if p.isTestHost() { 148 p.addDataDeviceBinsDeps(ctx, "lib32") 149 p.addDataDeviceBinsDeps(ctx, "lib64") 150 } 151} 152 153func (p *PythonTestModule) GenerateAndroidBuildActions(ctx android.ModuleContext) { 154 // We inherit from only the library's GenerateAndroidBuildActions, and then 155 // just use buildBinary() so that the binary is not installed into the location 156 // it would be for regular binaries. 157 p.PythonLibraryModule.GenerateAndroidBuildActions(ctx) 158 p.buildBinary(ctx) 159 160 var configs []tradefed.Option 161 for _, metadata := range p.testProperties.Test_options.Metadata { 162 configs = append(configs, tradefed.Option{Name: "config-descriptor:metadata", Key: metadata.Name, Value: metadata.Value}) 163 } 164 165 runner := proptools.StringDefault(p.testProperties.Test_options.Runner, "tradefed") 166 template := "${PythonBinaryHostTestConfigTemplate}" 167 if runner == "mobly" { 168 // Add tag to enable Atest mobly runner 169 if !android.InList("mobly", p.testProperties.Test_options.Tags) { 170 p.testProperties.Test_options.Tags = append(p.testProperties.Test_options.Tags, "mobly") 171 } 172 template = "${PythonBinaryHostMoblyTestConfigTemplate}" 173 } else if runner != "tradefed" { 174 panic(fmt.Errorf("unknown python test runner '%s', should be 'tradefed' or 'mobly'", runner)) 175 } 176 p.testConfig = tradefed.AutoGenTestConfig(ctx, tradefed.AutoGenTestConfigOptions{ 177 TestConfigProp: p.testProperties.Test_config, 178 TestConfigTemplateProp: p.testProperties.Test_config_template, 179 TestSuites: p.binaryProperties.Test_suites, 180 OptionsForAutogenerated: configs, 181 AutoGenConfig: p.binaryProperties.Auto_gen_config, 182 DeviceTemplate: template, 183 HostTemplate: template, 184 }) 185 186 for _, dataSrcPath := range android.PathsForModuleSrc(ctx, p.testProperties.Data) { 187 p.data = append(p.data, android.DataPath{SrcPath: dataSrcPath}) 188 } 189 for _, dataSrcPath := range android.PathsForModuleSrc(ctx, p.testProperties.Device_common_data) { 190 p.data = append(p.data, android.DataPath{SrcPath: dataSrcPath}) 191 } 192 193 if p.isTestHost() && len(p.testProperties.Data_device_bins_both) > 0 { 194 ctx.VisitDirectDepsWithTag(dataDeviceBinsTag, func(dep android.Module) { 195 p.data = append(p.data, android.DataPath{SrcPath: android.OutputFileForModule(ctx, dep, "")}) 196 }) 197 } 198 199 // Emulate the data property for java_data dependencies. 200 for _, javaData := range ctx.GetDirectDepsWithTag(javaDataTag) { 201 for _, javaDataSrcPath := range android.OutputFilesForModule(ctx, javaData, "") { 202 p.data = append(p.data, android.DataPath{SrcPath: javaDataSrcPath}) 203 } 204 } 205 206 installDir := installDir(ctx, "nativetest", "nativetest64", ctx.ModuleName()) 207 installedData := ctx.InstallTestData(installDir, p.data) 208 p.installedDest = ctx.InstallFile(installDir, p.installSource.Base(), p.installSource, installedData...) 209} 210 211func (p *PythonTestModule) AndroidMkEntries() []android.AndroidMkEntries { 212 entriesList := p.PythonBinaryModule.AndroidMkEntries() 213 if len(entriesList) != 1 { 214 panic("Expected 1 entry") 215 } 216 entries := &entriesList[0] 217 218 entries.Class = "NATIVE_TESTS" 219 220 entries.ExtraEntries = append(entries.ExtraEntries, 221 func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) { 222 //entries.AddCompatibilityTestSuites(p.binaryProperties.Test_suites...) 223 if p.testConfig != nil { 224 entries.SetString("LOCAL_FULL_TEST_CONFIG", p.testConfig.String()) 225 } 226 227 // ATS 2.0 is the test harness for mobly tests and the test config is for ATS 2.0. 228 // Add "v2" suffix to test config name to distinguish it from the config for TF. 229 if proptools.String(p.testProperties.Test_options.Runner) == "mobly" { 230 entries.SetString("LOCAL_TEST_CONFIG_SUFFIX", "v2") 231 } 232 233 entries.SetBoolIfTrue("LOCAL_DISABLE_AUTO_GENERATE_TEST_CONFIG", !BoolDefault(p.binaryProperties.Auto_gen_config, true)) 234 235 p.testProperties.Test_options.SetAndroidMkEntries(entries) 236 }) 237 238 return entriesList 239} 240