Merge "Add integration testing infrastructure"

am: dddf50039a

Change-Id: I7e378c07ae859e45ad461545401f69fade6137f0
This commit is contained in:
Colin Cross 2017-07-18 00:07:20 +00:00 committed by android-build-merger
commit daf9154992
12 changed files with 193 additions and 122 deletions

View file

@ -51,6 +51,7 @@ bootstrap_go_package {
"android/paths.go",
"android/prebuilt.go",
"android/register.go",
"android/testing.go",
"android/util.go",
"android/variable.go",

View file

@ -84,6 +84,8 @@ type config struct {
inMake bool
captureBuild bool // true for tests, saves build parameters for each module
OncePer
}
@ -171,7 +173,8 @@ func TestConfig(buildDir string) Config {
DeviceName: stringPtr("test_device"),
},
buildDir: buildDir,
buildDir: buildDir,
captureBuild: true,
}
config.deviceConfig = &deviceConfig{
config: config,

View file

@ -113,6 +113,11 @@ func (defaultable *DefaultableModule) applyDefaults(ctx TopDownMutatorContext,
}
}
func registerDefaultsPreArchMutators(ctx RegisterMutatorsContext) {
ctx.BottomUp("defaults_deps", defaultsDepsMutator).Parallel()
ctx.TopDown("defaults", defaultsMutator).Parallel()
}
func defaultsDepsMutator(ctx BottomUpMutatorContext) {
if defaultable, ok := ctx.Module().(Defaultable); ok {
ctx.AddDependency(ctx.Module(), DefaultsDepTag, defaultable.defaults().Defaults...)

View file

@ -111,6 +111,8 @@ type Module interface {
AddProperties(props ...interface{})
GetProperties() []interface{}
BuildParamsForTests() []ModuleBuildParams
}
type nameProperties struct {
@ -291,6 +293,9 @@ type ModuleBase struct {
hooks hooks
registerProps []interface{}
// For tests
buildParams []ModuleBuildParams
}
func (a *ModuleBase) AddProperties(props ...interface{}) {
@ -301,6 +306,10 @@ func (a *ModuleBase) GetProperties() []interface{} {
return a.registerProps
}
func (a *ModuleBase) BuildParamsForTests() []ModuleBuildParams {
return a.buildParams
}
// Name returns the name of the module. It may be overridden by individual module types, for
// example prebuilts will prepend prebuilt_ to the name.
func (a *ModuleBase) Name() string {
@ -520,6 +529,8 @@ func (a *ModuleBase) GenerateBuildActions(ctx blueprint.ModuleContext) {
return
}
}
a.buildParams = androidCtx.buildParams
}
type androidBaseContextImpl struct {
@ -538,6 +549,9 @@ type androidModuleContext struct {
checkbuildFiles Paths
missingDeps []string
module Module
// For tests
buildParams []ModuleBuildParams
}
func (a *androidModuleContext) ninjaError(desc string, outputs []string, err error) {
@ -566,6 +580,10 @@ func (a *androidModuleContext) Build(pctx blueprint.PackageContext, params bluep
}
func (a *androidModuleContext) ModuleBuild(pctx blueprint.PackageContext, params ModuleBuildParams) {
if a.config.captureBuild {
a.buildParams = append(a.buildParams, params)
}
bparams := blueprint.BuildParams{
Rule: params.Rule,
Deps: params.Deps,

View file

@ -15,8 +15,6 @@
package android
import (
"sync"
"github.com/google/blueprint"
)
@ -27,9 +25,6 @@ import (
// Deps
// PostDeps
var registerMutatorsOnce sync.Once
var registeredMutators []*mutator
func registerMutatorsToContext(ctx *blueprint.Context, mutators []*mutator) {
for _, t := range mutators {
var handle blueprint.MutatorHandle
@ -44,56 +39,24 @@ func registerMutatorsToContext(ctx *blueprint.Context, mutators []*mutator) {
}
}
func registerMutators(ctx *blueprint.Context) {
registerMutatorsOnce.Do(func() {
ctx := &registerMutatorsContext{}
register := func(funcs []RegisterMutatorFunc) {
for _, f := range funcs {
f(ctx)
}
}
ctx.TopDown("load_hooks", loadHookMutator).Parallel()
ctx.BottomUp("prebuilts", prebuiltMutator).Parallel()
ctx.BottomUp("defaults_deps", defaultsDepsMutator).Parallel()
ctx.TopDown("defaults", defaultsMutator).Parallel()
register(preArch)
ctx.BottomUp("arch", archMutator).Parallel()
ctx.TopDown("arch_hooks", archHookMutator).Parallel()
register(preDeps)
ctx.BottomUp("deps", depsMutator).Parallel()
ctx.TopDown("prebuilt_select", PrebuiltSelectModuleMutator).Parallel()
ctx.BottomUp("prebuilt_replace", PrebuiltReplaceMutator).Parallel()
register(postDeps)
registeredMutators = ctx.mutators
})
registerMutatorsToContext(ctx, registeredMutators)
}
func RegisterTestMutators(ctx *blueprint.Context) {
mutators := &registerMutatorsContext{}
func registerMutators(ctx *blueprint.Context, preArch, preDeps, postDeps []RegisterMutatorFunc) {
mctx := &registerMutatorsContext{}
register := func(funcs []RegisterMutatorFunc) {
for _, f := range funcs {
f(mutators)
f(mctx)
}
}
register(testPreDeps)
mutators.BottomUp("deps", depsMutator).Parallel()
register(testPostDeps)
register(preArch)
registerMutatorsToContext(ctx, mutators.mutators)
register(preDeps)
mctx.BottomUp("deps", depsMutator).Parallel()
register(postDeps)
registerMutatorsToContext(ctx, mctx.mutators)
}
type registerMutatorsContext struct {
@ -107,7 +70,24 @@ type RegisterMutatorsContext interface {
type RegisterMutatorFunc func(RegisterMutatorsContext)
var preArch, preDeps, postDeps, testPreDeps, testPostDeps []RegisterMutatorFunc
var preArch = []RegisterMutatorFunc{
func(ctx RegisterMutatorsContext) {
ctx.TopDown("load_hooks", loadHookMutator).Parallel()
},
registerPrebuiltsPreArchMutators,
registerDefaultsPreArchMutators,
}
var preDeps = []RegisterMutatorFunc{
func(ctx RegisterMutatorsContext) {
ctx.BottomUp("arch", archMutator).Parallel()
ctx.TopDown("arch_hooks", archHookMutator).Parallel()
},
}
var postDeps = []RegisterMutatorFunc{
registerPrebuiltsPostDepsMutators,
}
func PreArchMutators(f RegisterMutatorFunc) {
preArch = append(preArch, f)
@ -121,14 +101,6 @@ func PostDepsMutators(f RegisterMutatorFunc) {
postDeps = append(postDeps, f)
}
func TestPreDepsMutators(f RegisterMutatorFunc) {
testPreDeps = append(testPreDeps, f)
}
func TeststPostDepsMutators(f RegisterMutatorFunc) {
testPostDeps = append(testPostDeps, f)
}
type AndroidTopDownMutator func(TopDownMutatorContext)
type TopDownMutatorContext interface {

View file

@ -61,6 +61,15 @@ type PrebuiltInterface interface {
Prebuilt() *Prebuilt
}
func registerPrebuiltsPreArchMutators(ctx RegisterMutatorsContext) {
ctx.BottomUp("prebuilts", prebuiltMutator).Parallel()
}
func registerPrebuiltsPostDepsMutators(ctx RegisterMutatorsContext) {
ctx.TopDown("prebuilt_select", PrebuiltSelectModuleMutator).Parallel()
ctx.BottomUp("prebuilt_replace", PrebuiltReplaceMutator).Parallel()
}
// prebuiltMutator ensures that there is always a module with an undecorated name, and marks
// prebuilt modules that have both a prebuilt and a source module.
func prebuiltMutator(ctx BottomUpMutatorContext) {

View file

@ -122,9 +122,12 @@ func TestPrebuilts(t *testing.T) {
for _, test := range prebuiltsTests {
t.Run(test.name, func(t *testing.T) {
ctx := NewContext()
ctx := NewTestContext()
ctx.PreArchMutators(registerPrebuiltsPreArchMutators)
ctx.PostDepsMutators(registerPrebuiltsPostDepsMutators)
ctx.RegisterModuleType("prebuilt", ModuleFactoryAdaptor(newPrebuiltModule))
ctx.RegisterModuleType("source", ModuleFactoryAdaptor(newSourceModule))
ctx.Register()
ctx.MockFileSystem(map[string][]byte{
"Blueprints": []byte(`
source {
@ -139,13 +142,10 @@ func TestPrebuilts(t *testing.T) {
_, errs = ctx.PrepareBuildActions(config)
fail(t, errs)
foo := findModule(ctx, "foo")
if foo == nil {
t.Fatalf("failed to find module foo")
}
foo := ctx.ModuleForTests("foo", "")
var dependsOnSourceModule, dependsOnPrebuiltModule bool
ctx.VisitDirectDeps(foo, func(m blueprint.Module) {
ctx.VisitDirectDeps(foo.Module(), func(m blueprint.Module) {
if _, ok := m.(*sourceModule); ok {
dependsOnSourceModule = true
}
@ -228,16 +228,6 @@ func (s *sourceModule) DepsMutator(ctx BottomUpMutatorContext) {
func (s *sourceModule) GenerateAndroidBuildActions(ctx ModuleContext) {
}
func findModule(ctx *blueprint.Context, name string) blueprint.Module {
var ret blueprint.Module
ctx.VisitAllModules(func(m blueprint.Module) {
if ctx.ModuleName(m) == name {
ret = m
}
})
return ret
}
func fail(t *testing.T, errs []error) {
if len(errs) > 0 {
for _, err := range errs {

View file

@ -60,9 +60,15 @@ func RegisterSingletonType(name string, factory blueprint.SingletonFactory) {
singletons = append(singletons, singleton{name, factory})
}
func NewContext() *blueprint.Context {
ctx := blueprint.NewContext()
type Context struct {
*blueprint.Context
}
func NewContext() *Context {
return &Context{blueprint.NewContext()}
}
func (ctx *Context) Register() {
for _, t := range moduleTypes {
ctx.RegisterModuleType(t.name, t.factory)
}
@ -71,9 +77,7 @@ func NewContext() *blueprint.Context {
ctx.RegisterSingletonType(t.name, t.factory)
}
registerMutators(ctx)
registerMutators(ctx.Context, preArch, preDeps, postDeps)
ctx.RegisterSingletonType("env", EnvSingleton)
return ctx
}

98
android/testing.go Normal file
View file

@ -0,0 +1,98 @@
// 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 android
import (
"fmt"
"strings"
"github.com/google/blueprint"
)
func NewTestContext() *TestContext {
return &TestContext{
Context: blueprint.NewContext(),
}
}
type TestContext struct {
*blueprint.Context
preArch, preDeps, postDeps []RegisterMutatorFunc
}
func (ctx *TestContext) PreArchMutators(f RegisterMutatorFunc) {
ctx.preArch = append(ctx.preArch, f)
}
func (ctx *TestContext) PreDepsMutators(f RegisterMutatorFunc) {
ctx.preDeps = append(ctx.preDeps, f)
}
func (ctx *TestContext) PostDepsMutators(f RegisterMutatorFunc) {
ctx.postDeps = append(ctx.postDeps, f)
}
func (ctx *TestContext) Register() {
registerMutators(ctx.Context, ctx.preArch, ctx.preDeps, ctx.postDeps)
ctx.RegisterSingletonType("env", EnvSingleton)
}
func (ctx *TestContext) ModuleForTests(name, variant string) TestingModule {
var module Module
ctx.VisitAllModules(func(m blueprint.Module) {
if ctx.ModuleName(m) == name && ctx.ModuleSubDir(m) == variant {
module = m.(Module)
}
})
if module == nil {
panic(fmt.Errorf("failed to find module %q variant %q", name, variant))
}
return TestingModule{module}
}
type TestingModule struct {
module Module
}
func (m TestingModule) Module() Module {
return m.module
}
func (m TestingModule) Rule(rule string) ModuleBuildParams {
for _, p := range m.module.BuildParamsForTests() {
if strings.Contains(p.Rule.String(), rule) {
return p
}
}
panic(fmt.Errorf("couldn't find rule %q", rule))
}
func (m TestingModule) Output(file string) ModuleBuildParams {
for _, p := range m.module.BuildParamsForTests() {
outputs := append(WritablePaths(nil), p.Outputs...)
if p.Output != nil {
outputs = append(outputs, p.Output)
}
for _, f := range outputs {
if f.Base() == file {
return p
}
}
}
panic(fmt.Errorf("couldn't find output %q", file))
}

View file

@ -23,8 +23,6 @@ import (
"android/soong/android"
"android/soong/genrule"
"github.com/google/blueprint"
)
type dataFile struct {
@ -123,8 +121,7 @@ func TestDataTests(t *testing.T) {
for _, test := range testDataTests {
t.Run(test.name, func(t *testing.T) {
ctx := blueprint.NewContext()
android.RegisterTestMutators(ctx)
ctx := android.NewTestContext()
ctx.MockFileSystem(map[string][]byte{
"Blueprints": []byte(`subdirs = ["dir"]`),
"dir/Blueprints": []byte(test.modules),
@ -135,18 +132,16 @@ func TestDataTests(t *testing.T) {
android.ModuleFactoryAdaptor(genrule.FileGroupFactory))
ctx.RegisterModuleType("test",
android.ModuleFactoryAdaptor(newTest))
ctx.Register()
_, errs := ctx.ParseBlueprintsFiles("Blueprints")
fail(t, errs)
_, errs = ctx.PrepareBuildActions(config)
fail(t, errs)
foo := findModule(ctx, "foo")
if foo == nil {
t.Fatalf("failed to find module foo")
}
foo := ctx.ModuleForTests("foo", "")
got := foo.(*testDataTest).data
got := foo.Module().(*testDataTest).data
if len(got) != len(test.data) {
t.Errorf("expected %d data files, got %d",
len(test.data), len(got))
@ -192,16 +187,6 @@ func (test *testDataTest) GenerateAndroidBuildActions(ctx android.ModuleContext)
test.data = ctx.ExpandSources(test.Properties.Data, nil)
}
func findModule(ctx *blueprint.Context, name string) blueprint.Module {
var ret blueprint.Module
ctx.VisitAllModules(func(m blueprint.Module) {
if ctx.ModuleName(m) == name {
ret = m
}
})
return ret
}
func fail(t *testing.T, errs []error) {
if len(errs) > 0 {
for _, err := range errs {

View file

@ -32,6 +32,7 @@ func main() {
srcDir := filepath.Dir(flag.Arg(0))
ctx := android.NewContext()
ctx.Register()
configuration, err := android.NewConfig(srcDir, bootstrap.BuildDir)
if err != nil {
@ -44,5 +45,5 @@ func main() {
ctx.SetAllowMissingDependencies(configuration.AllowMissingDependencies())
bootstrap.Main(ctx, configuration, configuration.ConfigFileName, configuration.ProductVariablesFileName)
bootstrap.Main(ctx.Context, configuration, configuration.ConfigFileName, configuration.ProductVariablesFileName)
}

View file

@ -26,8 +26,6 @@ import (
"testing"
"android/soong/android"
"github.com/google/blueprint"
)
type pyBinary struct {
@ -306,17 +304,17 @@ var (
func TestPythonModule(t *testing.T) {
config, buildDir := setupBuildEnv(t)
defer tearDownBuildEnv(buildDir)
android.TestPreDepsMutators(func(ctx android.RegisterMutatorsContext) {
ctx.BottomUp("version_split", versionSplitMutator()).Parallel()
})
for _, d := range data {
t.Run(d.desc, func(t *testing.T) {
ctx := blueprint.NewContext()
android.RegisterTestMutators(ctx)
ctx := android.NewTestContext()
ctx.PreDepsMutators(func(ctx android.RegisterMutatorsContext) {
ctx.BottomUp("version_split", versionSplitMutator()).Parallel()
})
ctx.RegisterModuleType("python_library_host",
android.ModuleFactoryAdaptor(PythonLibraryHostFactory))
ctx.RegisterModuleType("python_binary_host",
android.ModuleFactoryAdaptor(PythonBinaryHostFactory))
ctx.Register()
ctx.MockFileSystem(d.mockFiles)
_, testErrs := ctx.ParseBlueprintsFiles(bpFile)
fail(t, testErrs)
@ -360,15 +358,12 @@ func expectErrors(t *testing.T, actErrs []error, expErrs []string) (testErrs []e
return
}
func expectModule(t *testing.T, ctx *blueprint.Context, buildDir, name, variant string,
func expectModule(t *testing.T, ctx *android.TestContext, buildDir, name, variant string,
expPyRunfiles, expDepsPyRunfiles []string,
expParSpec string, expDepsParSpecs []string) (testErrs []error) {
module := findModule(ctx, name, variant)
if module == nil {
t.Fatalf("failed to find module %s!", name)
}
module := ctx.ModuleForTests(name, variant)
base, baseOk := module.(*pythonBaseModule)
base, baseOk := module.Module().(*pythonBaseModule)
if !baseOk {
t.Fatalf("%s is not Python module!", name)
}
@ -438,16 +433,6 @@ func tearDownBuildEnv(buildDir string) {
os.RemoveAll(buildDir)
}
func findModule(ctx *blueprint.Context, name, variant string) blueprint.Module {
var ret blueprint.Module
ctx.VisitAllModules(func(m blueprint.Module) {
if ctx.ModuleName(m) == name && ctx.ModuleSubDir(m) == variant {
ret = m
}
})
return ret
}
func fail(t *testing.T, errs []error) {
if len(errs) > 0 {
for _, err := range errs {