• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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	return &PythonTestModule{PythonBinaryModule: *NewBinary(hod)}
39}
40
41func PythonTestHostFactory() android.Module {
42	return NewTest(android.HostSupportedNoCross).init()
43}
44
45func PythonTestFactory() android.Module {
46	module := NewTest(android.HostAndDeviceSupported)
47	module.multilib = android.MultilibBoth
48	return module.init()
49}
50
51type TestProperties struct {
52	// the name of the test configuration (for example "AndroidTest.xml") that should be
53	// installed with the module.
54	Test_config *string `android:"path,arch_variant"`
55
56	// the name of the test configuration template (for example "AndroidTestTemplate.xml") that
57	// should be installed with the module.
58	Test_config_template *string `android:"path,arch_variant"`
59
60	// list of files or filegroup modules that provide data that should be installed alongside
61	// the test
62	Data []string `android:"path,arch_variant"`
63
64	// list of java modules that provide data that should be installed alongside the test.
65	Java_data []string
66
67	// Test options.
68	Test_options TestOptions
69}
70
71type TestOptions struct {
72	android.CommonTestOptions
73
74	// Runner for the test. Supports "tradefed" and "mobly" (for multi-device tests). Default is "tradefed".
75	Runner *string
76
77	// Metadata to describe the test configuration.
78	Metadata []Metadata
79}
80
81type Metadata struct {
82	Name  string
83	Value string
84}
85
86type PythonTestModule struct {
87	PythonBinaryModule
88
89	testProperties TestProperties
90	testConfig     android.Path
91	data           []android.DataPath
92}
93
94func (p *PythonTestModule) init() android.Module {
95	p.AddProperties(&p.properties, &p.protoProperties)
96	p.AddProperties(&p.binaryProperties)
97	p.AddProperties(&p.testProperties)
98	android.InitAndroidArchModule(p, p.hod, p.multilib)
99	android.InitDefaultableModule(p)
100	android.InitBazelModule(p)
101	if p.hod == android.HostSupportedNoCross && p.testProperties.Test_options.Unit_test == nil {
102		p.testProperties.Test_options.Unit_test = proptools.BoolPtr(true)
103	}
104	return p
105}
106
107func (p *PythonTestModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
108	// We inherit from only the library's GenerateAndroidBuildActions, and then
109	// just use buildBinary() so that the binary is not installed into the location
110	// it would be for regular binaries.
111	p.PythonLibraryModule.GenerateAndroidBuildActions(ctx)
112	p.buildBinary(ctx)
113
114	var configs []tradefed.Option
115	for _, metadata := range p.testProperties.Test_options.Metadata {
116		configs = append(configs, tradefed.Option{Name: "config-descriptor:metadata", Key: metadata.Name, Value: metadata.Value})
117	}
118
119	runner := proptools.StringDefault(p.testProperties.Test_options.Runner, "tradefed")
120	if runner == "tradefed" {
121		p.testConfig = tradefed.AutoGenTestConfig(ctx, tradefed.AutoGenTestConfigOptions{
122			TestConfigProp:          p.testProperties.Test_config,
123			TestConfigTemplateProp:  p.testProperties.Test_config_template,
124			TestSuites:              p.binaryProperties.Test_suites,
125			OptionsForAutogenerated: configs,
126			AutoGenConfig:           p.binaryProperties.Auto_gen_config,
127			DeviceTemplate:          "${PythonBinaryHostTestConfigTemplate}",
128			HostTemplate:            "${PythonBinaryHostTestConfigTemplate}",
129		})
130	} else if runner == "mobly" {
131		if p.testProperties.Test_config != nil || p.testProperties.Test_config_template != nil || p.binaryProperties.Auto_gen_config != nil {
132			panic(fmt.Errorf("cannot set test_config, test_config_template or auto_gen_config for mobly test"))
133		}
134
135		for _, testSuite := range p.binaryProperties.Test_suites {
136			if testSuite == "cts" {
137				configs = append(configs, tradefed.Option{Name: "test-suite-tag", Value: "cts"})
138				break
139			}
140		}
141		p.testConfig = tradefed.AutoGenTestConfig(ctx, tradefed.AutoGenTestConfigOptions{
142			OptionsForAutogenerated: configs,
143			DeviceTemplate:          "${PythonBinaryHostMoblyTestConfigTemplate}",
144			HostTemplate:            "${PythonBinaryHostMoblyTestConfigTemplate}",
145		})
146	} else {
147		panic(fmt.Errorf("unknown python test runner '%s', should be 'tradefed' or 'mobly'", runner))
148	}
149
150	p.installedDest = ctx.InstallFile(installDir(ctx, "nativetest", "nativetest64", ctx.ModuleName()), p.installSource.Base(), p.installSource)
151
152	for _, dataSrcPath := range android.PathsForModuleSrc(ctx, p.testProperties.Data) {
153		p.data = append(p.data, android.DataPath{SrcPath: dataSrcPath})
154	}
155
156	// Emulate the data property for java_data dependencies.
157	for _, javaData := range ctx.GetDirectDepsWithTag(javaDataTag) {
158		for _, javaDataSrcPath := range android.OutputFilesForModule(ctx, javaData, "") {
159			p.data = append(p.data, android.DataPath{SrcPath: javaDataSrcPath})
160		}
161	}
162}
163
164func (p *PythonTestModule) AndroidMkEntries() []android.AndroidMkEntries {
165	entriesList := p.PythonBinaryModule.AndroidMkEntries()
166	if len(entriesList) != 1 {
167		panic("Expected 1 entry")
168	}
169	entries := &entriesList[0]
170
171	entries.Class = "NATIVE_TESTS"
172
173	entries.ExtraEntries = append(entries.ExtraEntries,
174		func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
175			//entries.AddCompatibilityTestSuites(p.binaryProperties.Test_suites...)
176			if p.testConfig != nil {
177				entries.SetString("LOCAL_FULL_TEST_CONFIG", p.testConfig.String())
178			}
179
180			entries.SetBoolIfTrue("LOCAL_DISABLE_AUTO_GENERATE_TEST_CONFIG", !BoolDefault(p.binaryProperties.Auto_gen_config, true))
181
182			entries.AddStrings("LOCAL_TEST_DATA", android.AndroidMkDataPaths(p.data)...)
183
184			p.testProperties.Test_options.SetAndroidMkEntries(entries)
185		})
186
187	return entriesList
188}
189