Add support for android_test modules
android_test module are APKs that can be run as tests, either as standalone unit tests or as instrumentation tests for another APK. Test: m checkbuild Change-Id: I16661701637e4048fd99442029c3e195ebf373a4
This commit is contained in:
parent
e467f44f9b
commit
ae5caf554c
|
@ -376,6 +376,33 @@ include $(BUILD_NATIVE_TEST)
|
|||
expected: `
|
||||
cc_test {
|
||||
}
|
||||
`,
|
||||
},
|
||||
{
|
||||
desc: "Convert LOCAL_MODULE_TAGS tests to java_test",
|
||||
in: `
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE_TAGS := tests
|
||||
include $(BUILD_JAVA_LIBRARY)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE_TAGS := tests
|
||||
include $(BUILD_PACKAGE)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE_TAGS := tests
|
||||
include $(BUILD_HOST_JAVA_LIBRARY)
|
||||
`,
|
||||
|
||||
expected: `
|
||||
java_test {
|
||||
}
|
||||
|
||||
android_test {
|
||||
}
|
||||
|
||||
java_test_host {
|
||||
}
|
||||
`,
|
||||
},
|
||||
|
||||
|
|
|
@ -66,6 +66,10 @@ var fixSteps = []fixStep{
|
|||
name: "rewriteIncorrectAndroidmkAndroidLibraries",
|
||||
fix: rewriteIncorrectAndroidmkAndroidLibraries,
|
||||
},
|
||||
{
|
||||
name: "rewriteTestModuleTypes",
|
||||
fix: rewriteTestModuleTypes,
|
||||
},
|
||||
{
|
||||
name: "mergeMatchingModuleProperties",
|
||||
fix: runPatchListMod(mergeMatchingModuleProperties),
|
||||
|
@ -256,6 +260,46 @@ func rewriteIncorrectAndroidmkAndroidLibraries(f *Fixer) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// rewriteTestModuleTypes looks for modules that are identifiable as tests but for which Make doesn't have a separate
|
||||
// module class, and moves them to the appropriate Soong module type.
|
||||
func rewriteTestModuleTypes(f *Fixer) error {
|
||||
for _, def := range f.tree.Defs {
|
||||
mod, ok := def.(*parser.Module)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
if !strings.HasPrefix(mod.Type, "java_") && !strings.HasPrefix(mod.Type, "android_") {
|
||||
continue
|
||||
}
|
||||
|
||||
hasInstrumentationFor := hasNonEmptyLiteralStringProperty(mod, "instrumentation_for")
|
||||
tags, _ := getLiteralListPropertyValue(mod, "tags")
|
||||
|
||||
var hasTestsTag bool
|
||||
for _, tag := range tags {
|
||||
if tag == "tests" {
|
||||
hasTestsTag = true
|
||||
}
|
||||
}
|
||||
|
||||
isTest := hasInstrumentationFor || hasTestsTag
|
||||
|
||||
if isTest {
|
||||
switch mod.Type {
|
||||
case "android_app":
|
||||
mod.Type = "android_test"
|
||||
case "java_library":
|
||||
mod.Type = "java_test"
|
||||
case "java_library_host":
|
||||
mod.Type = "java_test_host"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func runPatchListMod(modFunc func(mod *parser.Module, buf []byte, patchlist *parser.PatchList) error) func(*Fixer) error {
|
||||
return func(f *Fixer) error {
|
||||
// Make sure all the offsets are accurate
|
||||
|
@ -383,26 +427,34 @@ func removeTags(mod *parser.Module, buf []byte, patchlist *parser.PatchList) err
|
|||
// force installation for -eng builds.
|
||||
`
|
||||
case "tests":
|
||||
if strings.Contains(mod.Type, "cc_test") || strings.Contains(mod.Type, "cc_library_static") {
|
||||
switch {
|
||||
case strings.Contains(mod.Type, "cc_test"),
|
||||
strings.Contains(mod.Type, "cc_library_static"),
|
||||
strings.Contains(mod.Type, "java_test"),
|
||||
mod.Type == "android_test":
|
||||
continue
|
||||
} else if strings.Contains(mod.Type, "cc_lib") {
|
||||
case strings.Contains(mod.Type, "cc_lib"):
|
||||
replaceStr += `// WARNING: Module tags are not supported in Soong.
|
||||
// To make a shared library only for tests, use the "cc_test_library" module
|
||||
// type. If you don't use gtest, set "gtest: false".
|
||||
`
|
||||
} else if strings.Contains(mod.Type, "cc_bin") {
|
||||
case strings.Contains(mod.Type, "cc_bin"):
|
||||
replaceStr += `// WARNING: Module tags are not supported in Soong.
|
||||
// For native test binaries, use the "cc_test" module type. Some differences:
|
||||
// - If you don't use gtest, set "gtest: false"
|
||||
// - Binaries will be installed into /data/nativetest[64]/<name>/<name>
|
||||
// - Both 32 & 64 bit versions will be built (as appropriate)
|
||||
`
|
||||
} else if strings.Contains(mod.Type, "java_lib") {
|
||||
case strings.Contains(mod.Type, "java_lib"):
|
||||
replaceStr += `// WARNING: Module tags are not supported in Soong.
|
||||
// For JUnit or similar tests, use the "java_test" module type. A dependency on
|
||||
// Junit will be added by default, if it is using some other runner, set "junit: false".
|
||||
`
|
||||
} else {
|
||||
case mod.Type == "android_app":
|
||||
replaceStr += `// WARNING: Module tags are not supported in Soong.
|
||||
// For JUnit or instrumentataion app tests, use the "android_test" module type.
|
||||
`
|
||||
default:
|
||||
replaceStr += `// WARNING: Module tags are not supported in Soong.
|
||||
// In most cases, tests are now identified by their module type:
|
||||
// cc_test, java_test, python_test
|
||||
|
@ -552,6 +604,11 @@ func hasNonEmptyLiteralListProperty(mod *parser.Module, name string) bool {
|
|||
return found && len(list.Values) > 0
|
||||
}
|
||||
|
||||
func hasNonEmptyLiteralStringProperty(mod *parser.Module, name string) bool {
|
||||
s, found := getLiteralStringPropertyValue(mod, name)
|
||||
return found && len(s) > 0
|
||||
}
|
||||
|
||||
func getLiteralListProperty(mod *parser.Module, name string) (list *parser.List, found bool) {
|
||||
prop, ok := mod.GetProperty(name)
|
||||
if !ok {
|
||||
|
@ -561,6 +618,40 @@ func getLiteralListProperty(mod *parser.Module, name string) (list *parser.List,
|
|||
return list, ok
|
||||
}
|
||||
|
||||
func getLiteralListPropertyValue(mod *parser.Module, name string) (list []string, found bool) {
|
||||
listValue, ok := getLiteralListProperty(mod, name)
|
||||
if !ok {
|
||||
return nil, false
|
||||
}
|
||||
for _, v := range listValue.Values {
|
||||
stringValue, ok := v.(*parser.String)
|
||||
if !ok {
|
||||
return nil, false
|
||||
}
|
||||
list = append(list, stringValue.Value)
|
||||
}
|
||||
|
||||
return list, true
|
||||
}
|
||||
|
||||
func getLiteralStringProperty(mod *parser.Module, name string) (s *parser.String, found bool) {
|
||||
prop, ok := mod.GetProperty(name)
|
||||
if !ok {
|
||||
return nil, false
|
||||
}
|
||||
s, ok = prop.Value.(*parser.String)
|
||||
return s, ok
|
||||
}
|
||||
|
||||
func getLiteralStringPropertyValue(mod *parser.Module, name string) (s string, found bool) {
|
||||
stringValue, ok := getLiteralStringProperty(mod, name)
|
||||
if !ok {
|
||||
return "", false
|
||||
}
|
||||
|
||||
return stringValue.Value, true
|
||||
}
|
||||
|
||||
func propertyIndex(props []*parser.Property, propertyName string) int {
|
||||
for i, prop := range props {
|
||||
if prop.Name == propertyName {
|
||||
|
|
|
@ -228,6 +228,19 @@ func (app *AndroidApp) AndroidMk() android.AndroidMkData {
|
|||
}
|
||||
}
|
||||
|
||||
func (a *AndroidTest) AndroidMk() android.AndroidMkData {
|
||||
data := a.AndroidApp.AndroidMk()
|
||||
data.Extra = append(data.Extra, func(w io.Writer, outputFile android.Path) {
|
||||
fmt.Fprintln(w, "LOCAL_MODULE_TAGS := tests")
|
||||
if len(a.testProperties.Test_suites) > 0 {
|
||||
fmt.Fprintln(w, "LOCAL_COMPATIBILITY_SUITE :=",
|
||||
strings.Join(a.testProperties.Test_suites, " "))
|
||||
}
|
||||
})
|
||||
|
||||
return data
|
||||
}
|
||||
|
||||
func (a *AndroidLibrary) AndroidMk() android.AndroidMkData {
|
||||
data := a.Library.AndroidMk()
|
||||
|
||||
|
|
60
java/app.go
60
java/app.go
|
@ -26,6 +26,7 @@ import (
|
|||
|
||||
func init() {
|
||||
android.RegisterModuleType("android_app", AndroidAppFactory)
|
||||
android.RegisterModuleType("android_test", AndroidTestFactory)
|
||||
}
|
||||
|
||||
// AndroidManifest.xml merging
|
||||
|
@ -50,8 +51,6 @@ type appProperties struct {
|
|||
|
||||
// list of resource labels to generate individual resource packages
|
||||
Package_splits []string
|
||||
|
||||
Instrumentation_for *string
|
||||
}
|
||||
|
||||
type AndroidApp struct {
|
||||
|
@ -61,6 +60,8 @@ type AndroidApp struct {
|
|||
certificate certificate
|
||||
|
||||
appProperties appProperties
|
||||
|
||||
extraLinkFlags []string
|
||||
}
|
||||
|
||||
func (a *AndroidApp) ExportedProguardFlagFiles() android.Paths {
|
||||
|
@ -85,14 +86,11 @@ func (a *AndroidApp) DepsMutator(ctx android.BottomUpMutatorContext) {
|
|||
}
|
||||
|
||||
func (a *AndroidApp) GenerateAndroidBuildActions(ctx android.ModuleContext) {
|
||||
var linkFlags []string
|
||||
if String(a.appProperties.Instrumentation_for) != "" {
|
||||
linkFlags = append(linkFlags,
|
||||
"--rename-instrumentation-target-package",
|
||||
String(a.appProperties.Instrumentation_for))
|
||||
} else {
|
||||
a.properties.Instrument = true
|
||||
}
|
||||
a.generateAndroidBuildActions(ctx)
|
||||
}
|
||||
|
||||
func (a *AndroidApp) generateAndroidBuildActions(ctx android.ModuleContext) {
|
||||
linkFlags := append([]string(nil), a.extraLinkFlags...)
|
||||
|
||||
hasProduct := false
|
||||
for _, f := range a.aaptProperties.Aaptflags {
|
||||
|
@ -188,6 +186,8 @@ func AndroidAppFactory() android.Module {
|
|||
module.Module.deviceProperties.Optimize.Enabled = proptools.BoolPtr(true)
|
||||
module.Module.deviceProperties.Optimize.Shrink = proptools.BoolPtr(true)
|
||||
|
||||
module.Module.properties.Instrument = true
|
||||
|
||||
module.AddProperties(
|
||||
&module.Module.properties,
|
||||
&module.Module.deviceProperties,
|
||||
|
@ -198,3 +198,43 @@ func AndroidAppFactory() android.Module {
|
|||
android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon)
|
||||
return module
|
||||
}
|
||||
|
||||
type appTestProperties struct {
|
||||
Instrumentation_for *string
|
||||
}
|
||||
|
||||
type AndroidTest struct {
|
||||
AndroidApp
|
||||
|
||||
appTestProperties appTestProperties
|
||||
|
||||
testProperties testProperties
|
||||
}
|
||||
|
||||
func (a *AndroidTest) GenerateAndroidBuildActions(ctx android.ModuleContext) {
|
||||
if String(a.appTestProperties.Instrumentation_for) != "" {
|
||||
a.AndroidApp.extraLinkFlags = append(a.AndroidApp.extraLinkFlags,
|
||||
"--rename-instrumentation-target-package",
|
||||
String(a.appTestProperties.Instrumentation_for))
|
||||
}
|
||||
|
||||
a.generateAndroidBuildActions(ctx)
|
||||
}
|
||||
|
||||
func AndroidTestFactory() android.Module {
|
||||
module := &AndroidTest{}
|
||||
|
||||
module.Module.deviceProperties.Optimize.Enabled = proptools.BoolPtr(true)
|
||||
|
||||
module.AddProperties(
|
||||
&module.Module.properties,
|
||||
&module.Module.deviceProperties,
|
||||
&module.Module.protoProperties,
|
||||
&module.aaptProperties,
|
||||
&module.appProperties,
|
||||
&module.appTestProperties)
|
||||
|
||||
android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon)
|
||||
|
||||
return module
|
||||
}
|
||||
|
|
|
@ -212,8 +212,8 @@ type CompilerDeviceProperties struct {
|
|||
}
|
||||
|
||||
Optimize struct {
|
||||
// If false, disable all optimization. Defaults to true for apps, false for
|
||||
// libraries and tests.
|
||||
// If false, disable all optimization. Defaults to true for android_app and android_test
|
||||
// modules, false for java_library and java_test modules.
|
||||
Enabled *bool
|
||||
|
||||
// If true, optimize for size by removing unused code. Defaults to true for apps,
|
||||
|
|
Loading…
Reference in New Issue