Some tests need to add custom tradefed options, but still want to keep most of the soong autogenerated tradefed xml file. Expose a test_options: { tradefed_options: [...] } property that will allow tests to add more options to the autogenerated xml file. Fixes: 184895128 Test: go test, and verified that the ninja files did not change for aosp_arm64 Change-Id: I75f7eb002c8325ce7cdc76e12e76e16195320620
302 lines
10 KiB
Go
302 lines
10 KiB
Go
// Copyright 2018 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 tradefed
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
|
|
"github.com/google/blueprint"
|
|
"github.com/google/blueprint/proptools"
|
|
|
|
"android/soong/android"
|
|
)
|
|
|
|
const test_xml_indent = " "
|
|
|
|
func getTestConfigTemplate(ctx android.ModuleContext, prop *string) android.OptionalPath {
|
|
return ctx.ExpandOptionalSource(prop, "test_config_template")
|
|
}
|
|
|
|
func getTestConfig(ctx android.ModuleContext, prop *string) android.Path {
|
|
if p := ctx.ExpandOptionalSource(prop, "test_config"); p.Valid() {
|
|
return p.Path()
|
|
} else if p := android.ExistentPathForSource(ctx, ctx.ModuleDir(), "AndroidTest.xml"); p.Valid() {
|
|
return p.Path()
|
|
}
|
|
return nil
|
|
}
|
|
|
|
var autogenTestConfig = pctx.StaticRule("autogenTestConfig", blueprint.RuleParams{
|
|
Command: "sed 's&{MODULE}&${name}&g;s&{EXTRA_CONFIGS}&'${extraConfigs}'&g;s&{OUTPUT_FILENAME}&'${outputFileName}'&g;s&{TEST_INSTALL_BASE}&'${testInstallBase}'&g' $template > $out",
|
|
CommandDeps: []string{"$template"},
|
|
}, "name", "template", "extraConfigs", "outputFileName", "testInstallBase")
|
|
|
|
func testConfigPath(ctx android.ModuleContext, prop *string, testSuites []string, autoGenConfig *bool, testConfigTemplateProp *string) (path android.Path, autogenPath android.WritablePath) {
|
|
p := getTestConfig(ctx, prop)
|
|
if !Bool(autoGenConfig) && p != nil {
|
|
return p, nil
|
|
} else if BoolDefault(autoGenConfig, true) && (!android.InList("cts", testSuites) || testConfigTemplateProp != nil) {
|
|
outputFile := android.PathForModuleOut(ctx, ctx.ModuleName()+".config")
|
|
return nil, outputFile
|
|
} else {
|
|
// CTS modules can be used for test data, so test config files must be
|
|
// explicitly created using AndroidTest.xml or test_config_template.
|
|
return nil, nil
|
|
}
|
|
}
|
|
|
|
type Config interface {
|
|
Config() string
|
|
}
|
|
|
|
type Option struct {
|
|
Name string
|
|
Key string
|
|
Value string
|
|
}
|
|
|
|
var _ Config = Option{}
|
|
|
|
func (o Option) Config() string {
|
|
if o.Key != "" {
|
|
return fmt.Sprintf(`<option name="%s" key="%s" value="%s" />`, o.Name, o.Key, o.Value)
|
|
}
|
|
return fmt.Sprintf(`<option name="%s" value="%s" />`, o.Name, o.Value)
|
|
}
|
|
|
|
// It can be a template of object or target_preparer.
|
|
type Object struct {
|
|
// Set it as a target_preparer if object type == "target_preparer".
|
|
Type string
|
|
Class string
|
|
Options []Option
|
|
}
|
|
|
|
var _ Config = Object{}
|
|
|
|
func (ob Object) Config() string {
|
|
var optionStrings []string
|
|
for _, option := range ob.Options {
|
|
optionStrings = append(optionStrings, option.Config())
|
|
}
|
|
var options string
|
|
if len(ob.Options) == 0 {
|
|
options = ""
|
|
} else {
|
|
optionDelimiter := fmt.Sprintf("\\n%s%s", test_xml_indent, test_xml_indent)
|
|
options = optionDelimiter + strings.Join(optionStrings, optionDelimiter)
|
|
}
|
|
if ob.Type == "target_preparer" {
|
|
return fmt.Sprintf(`<target_preparer class="%s">%s\n%s</target_preparer>`, ob.Class, options, test_xml_indent)
|
|
} else {
|
|
return fmt.Sprintf(`<object type="%s" class="%s">%s\n%s</object>`, ob.Type, ob.Class, options, test_xml_indent)
|
|
}
|
|
|
|
}
|
|
|
|
// MaybeAutoGenTestConfigBuilder provides a Build() method that will either
|
|
// generate a AndroidTest.xml file, or use an existing user-supplied one.
|
|
// It used to be a bunch of separate functions for each language, but was
|
|
// converted to this builder pattern to have one function that accepts many
|
|
// optional arguments.
|
|
type MaybeAutoGenTestConfigBuilder struct {
|
|
ctx android.ModuleContext
|
|
name string
|
|
outputFileName string
|
|
testConfigProp *string
|
|
testConfigTemplateProp *string
|
|
testSuites []string
|
|
config []Config
|
|
configsForAutogenerated []Config
|
|
autoGenConfig *bool
|
|
unitTest *bool
|
|
testInstallBase string
|
|
deviceTemplate string
|
|
hostTemplate string
|
|
hostUnitTestTemplate string
|
|
}
|
|
|
|
func NewMaybeAutoGenTestConfigBuilder(ctx android.ModuleContext) *MaybeAutoGenTestConfigBuilder {
|
|
return &MaybeAutoGenTestConfigBuilder{
|
|
ctx: ctx,
|
|
name: ctx.ModuleName(),
|
|
}
|
|
}
|
|
|
|
func (b *MaybeAutoGenTestConfigBuilder) SetName(name string) *MaybeAutoGenTestConfigBuilder {
|
|
b.name = name
|
|
return b
|
|
}
|
|
|
|
func (b *MaybeAutoGenTestConfigBuilder) SetOutputFileName(outputFileName string) *MaybeAutoGenTestConfigBuilder {
|
|
b.outputFileName = outputFileName
|
|
return b
|
|
}
|
|
|
|
func (b *MaybeAutoGenTestConfigBuilder) SetTestConfigProp(testConfigProp *string) *MaybeAutoGenTestConfigBuilder {
|
|
b.testConfigProp = testConfigProp
|
|
return b
|
|
}
|
|
|
|
func (b *MaybeAutoGenTestConfigBuilder) SetTestTemplateConfigProp(testConfigTemplateProp *string) *MaybeAutoGenTestConfigBuilder {
|
|
b.testConfigTemplateProp = testConfigTemplateProp
|
|
return b
|
|
}
|
|
|
|
func (b *MaybeAutoGenTestConfigBuilder) SetTestSuites(testSuites []string) *MaybeAutoGenTestConfigBuilder {
|
|
b.testSuites = testSuites
|
|
return b
|
|
}
|
|
|
|
func (b *MaybeAutoGenTestConfigBuilder) SetConfig(config []Config) *MaybeAutoGenTestConfigBuilder {
|
|
b.config = config
|
|
return b
|
|
}
|
|
|
|
func (b *MaybeAutoGenTestConfigBuilder) SetOptionsForAutogenerated(configsForAutogenerated []Option) *MaybeAutoGenTestConfigBuilder {
|
|
configs := make([]Config, 0, len(configsForAutogenerated))
|
|
for _, c := range configsForAutogenerated {
|
|
configs = append(configs, c)
|
|
}
|
|
b.configsForAutogenerated = configs
|
|
return b
|
|
}
|
|
|
|
func (b *MaybeAutoGenTestConfigBuilder) SetUnitTest(unitTest *bool) *MaybeAutoGenTestConfigBuilder {
|
|
b.unitTest = unitTest
|
|
return b
|
|
}
|
|
|
|
func (b *MaybeAutoGenTestConfigBuilder) SetAutoGenConfig(autoGenConfig *bool) *MaybeAutoGenTestConfigBuilder {
|
|
b.autoGenConfig = autoGenConfig
|
|
return b
|
|
}
|
|
|
|
func (b *MaybeAutoGenTestConfigBuilder) SetTestInstallBase(testInstallBase string) *MaybeAutoGenTestConfigBuilder {
|
|
b.testInstallBase = testInstallBase
|
|
return b
|
|
}
|
|
|
|
func (b *MaybeAutoGenTestConfigBuilder) SetDeviceTemplate(deviceTemplate string) *MaybeAutoGenTestConfigBuilder {
|
|
b.deviceTemplate = deviceTemplate
|
|
return b
|
|
}
|
|
|
|
func (b *MaybeAutoGenTestConfigBuilder) SetHostTemplate(hostTemplate string) *MaybeAutoGenTestConfigBuilder {
|
|
b.hostTemplate = hostTemplate
|
|
return b
|
|
}
|
|
|
|
func (b *MaybeAutoGenTestConfigBuilder) SetHostUnitTestTemplate(hostUnitTestTemplate string) *MaybeAutoGenTestConfigBuilder {
|
|
b.hostUnitTestTemplate = hostUnitTestTemplate
|
|
return b
|
|
}
|
|
|
|
func (b *MaybeAutoGenTestConfigBuilder) Build() android.Path {
|
|
config := append(b.config, b.configsForAutogenerated...)
|
|
path, autogenPath := testConfigPath(b.ctx, b.testConfigProp, b.testSuites, b.autoGenConfig, b.testConfigTemplateProp)
|
|
if autogenPath != nil {
|
|
templatePath := getTestConfigTemplate(b.ctx, b.testConfigTemplateProp)
|
|
if templatePath.Valid() {
|
|
autogenTemplate(b.ctx, b.name, autogenPath, templatePath.String(), config, b.outputFileName, b.testInstallBase)
|
|
} else {
|
|
if b.ctx.Device() {
|
|
autogenTemplate(b.ctx, b.name, autogenPath, b.deviceTemplate, config, b.outputFileName, b.testInstallBase)
|
|
} else {
|
|
if Bool(b.unitTest) {
|
|
autogenTemplate(b.ctx, b.name, autogenPath, b.hostUnitTestTemplate, config, b.outputFileName, b.testInstallBase)
|
|
} else {
|
|
autogenTemplate(b.ctx, b.name, autogenPath, b.hostTemplate, config, b.outputFileName, b.testInstallBase)
|
|
}
|
|
}
|
|
}
|
|
return autogenPath
|
|
}
|
|
if len(b.configsForAutogenerated) > 0 {
|
|
b.ctx.ModuleErrorf("Extra tradefed configurations were provided for an autogenerated xml file, but the autogenerated xml file was not used.")
|
|
}
|
|
return path
|
|
}
|
|
|
|
func autogenTemplate(ctx android.ModuleContext, name string, output android.WritablePath, template string, configs []Config, outputFileName string, testInstallBase string) {
|
|
if template == "" {
|
|
ctx.ModuleErrorf("Empty template")
|
|
}
|
|
var configStrings []string
|
|
for _, config := range configs {
|
|
configStrings = append(configStrings, config.Config())
|
|
}
|
|
extraConfigs := strings.Join(configStrings, fmt.Sprintf("\\n%s", test_xml_indent))
|
|
extraConfigs = proptools.NinjaAndShellEscape(extraConfigs)
|
|
|
|
ctx.Build(pctx, android.BuildParams{
|
|
Rule: autogenTestConfig,
|
|
Description: "test config",
|
|
Output: output,
|
|
Args: map[string]string{
|
|
"name": name,
|
|
"template": template,
|
|
"extraConfigs": extraConfigs,
|
|
"outputFileName": outputFileName,
|
|
"testInstallBase": testInstallBase,
|
|
},
|
|
})
|
|
}
|
|
|
|
var autogenInstrumentationTest = pctx.StaticRule("autogenInstrumentationTest", blueprint.RuleParams{
|
|
Command: "${AutoGenTestConfigScript} $out $in ${EmptyTestConfig} $template ${extraConfigs}",
|
|
CommandDeps: []string{
|
|
"${AutoGenTestConfigScript}",
|
|
"${EmptyTestConfig}",
|
|
"$template",
|
|
},
|
|
}, "name", "template", "extraConfigs")
|
|
|
|
func AutoGenInstrumentationTestConfig(ctx android.ModuleContext, testConfigProp *string,
|
|
testConfigTemplateProp *string, manifest android.Path, testSuites []string, autoGenConfig *bool, configs []Config) android.Path {
|
|
path, autogenPath := testConfigPath(ctx, testConfigProp, testSuites, autoGenConfig, testConfigTemplateProp)
|
|
var configStrings []string
|
|
if autogenPath != nil {
|
|
template := "${InstrumentationTestConfigTemplate}"
|
|
moduleTemplate := getTestConfigTemplate(ctx, testConfigTemplateProp)
|
|
if moduleTemplate.Valid() {
|
|
template = moduleTemplate.String()
|
|
}
|
|
for _, config := range configs {
|
|
configStrings = append(configStrings, config.Config())
|
|
}
|
|
extraConfigs := strings.Join(configStrings, fmt.Sprintf("\\n%s", test_xml_indent))
|
|
extraConfigs = fmt.Sprintf("--extra-configs '%s'", extraConfigs)
|
|
|
|
ctx.Build(pctx, android.BuildParams{
|
|
Rule: autogenInstrumentationTest,
|
|
Description: "test config",
|
|
Input: manifest,
|
|
Output: autogenPath,
|
|
Args: map[string]string{
|
|
"name": ctx.ModuleName(),
|
|
"template": template,
|
|
"extraConfigs": extraConfigs,
|
|
},
|
|
})
|
|
return autogenPath
|
|
}
|
|
return path
|
|
}
|
|
|
|
var Bool = proptools.Bool
|
|
var BoolDefault = proptools.BoolDefault
|