|  | // 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 | 
|  | } |