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