Add tests for ctx.InstallFile
Add tests that cover Soong-only installation as well as installation with InstallBypassMake. Bug: 204136549 Test: TestInstall Test: TestInstallBypassMake Change-Id: Iac22c9fdf99994e06b419623ee5fa399ef6957fb
This commit is contained in:
@@ -19,6 +19,9 @@ bootstrap_go_package {
|
||||
"soong-ui-metrics_proto",
|
||||
"golang-protobuf-proto",
|
||||
"golang-protobuf-encoding-prototext",
|
||||
|
||||
// Only used for tests.
|
||||
"androidmk-parser",
|
||||
],
|
||||
srcs: [
|
||||
"androidmk.go",
|
||||
|
@@ -142,15 +142,19 @@ type SingletonMakeVarsProvider interface {
|
||||
|
||||
var singletonMakeVarsProvidersKey = NewOnceKey("singletonMakeVarsProvidersKey")
|
||||
|
||||
func getSingletonMakevarsProviders(config Config) *[]makeVarsProvider {
|
||||
return config.Once(singletonMakeVarsProvidersKey, func() interface{} {
|
||||
return &[]makeVarsProvider{}
|
||||
}).(*[]makeVarsProvider)
|
||||
}
|
||||
|
||||
// registerSingletonMakeVarsProvider adds a singleton that implements SingletonMakeVarsProvider to
|
||||
// the list of MakeVarsProviders to run.
|
||||
func registerSingletonMakeVarsProvider(config Config, singleton SingletonMakeVarsProvider) {
|
||||
// Singletons are registered on the Context and may be different between different Contexts,
|
||||
// for example when running multiple tests. Store the SingletonMakeVarsProviders in the
|
||||
// Config so they are attached to the Context.
|
||||
singletonMakeVarsProviders := config.Once(singletonMakeVarsProvidersKey, func() interface{} {
|
||||
return &[]makeVarsProvider{}
|
||||
}).(*[]makeVarsProvider)
|
||||
singletonMakeVarsProviders := getSingletonMakevarsProviders(config)
|
||||
|
||||
*singletonMakeVarsProviders = append(*singletonMakeVarsProviders,
|
||||
makeVarsProvider{pctx, singletonMakeVarsProviderAdapter(singleton)})
|
||||
@@ -175,7 +179,9 @@ func makeVarsSingletonFunc() Singleton {
|
||||
return &makeVarsSingleton{}
|
||||
}
|
||||
|
||||
type makeVarsSingleton struct{}
|
||||
type makeVarsSingleton struct {
|
||||
installsForTesting []byte
|
||||
}
|
||||
|
||||
type makeVarsProvider struct {
|
||||
pctx PackageContext
|
||||
@@ -238,7 +244,7 @@ func (s *makeVarsSingleton) GenerateBuildActions(ctx SingletonContext) {
|
||||
var katiSymlinks []katiInstall
|
||||
|
||||
providers := append([]makeVarsProvider(nil), makeVarsInitProviders...)
|
||||
providers = append(providers, *ctx.Config().Get(singletonMakeVarsProvidersKey).(*[]makeVarsProvider)...)
|
||||
providers = append(providers, *getSingletonMakevarsProviders(ctx.Config())...)
|
||||
|
||||
for _, provider := range providers {
|
||||
mctx := &makeVarsContext{
|
||||
@@ -313,6 +319,8 @@ func (s *makeVarsSingleton) GenerateBuildActions(ctx SingletonContext) {
|
||||
if err := pathtools.WriteFileIfChanged(installsFile, installsBytes, 0666); err != nil {
|
||||
ctx.Errorf(err.Error())
|
||||
}
|
||||
|
||||
s.installsForTesting = installsBytes
|
||||
}
|
||||
|
||||
func (s *makeVarsSingleton) writeVars(vars []makeVarsVariable) []byte {
|
||||
|
@@ -15,7 +15,12 @@
|
||||
package android
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"testing"
|
||||
|
||||
mkparser "android/soong/androidmk/parser"
|
||||
)
|
||||
|
||||
func TestSrcIsModule(t *testing.T) {
|
||||
@@ -199,17 +204,28 @@ type depsModule struct {
|
||||
}
|
||||
}
|
||||
|
||||
func (m *depsModule) InstallBypassMake() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (m *depsModule) GenerateAndroidBuildActions(ctx ModuleContext) {
|
||||
outputFile := PathForModuleOut(ctx, ctx.ModuleName())
|
||||
ctx.Build(pctx, BuildParams{
|
||||
Rule: Touch,
|
||||
Output: outputFile,
|
||||
})
|
||||
installFile := ctx.InstallFile(PathForModuleInstall(ctx), ctx.ModuleName(), outputFile)
|
||||
ctx.InstallSymlink(PathForModuleInstall(ctx, "symlinks"), ctx.ModuleName(), installFile)
|
||||
}
|
||||
|
||||
func (m *depsModule) DepsMutator(ctx BottomUpMutatorContext) {
|
||||
ctx.AddDependency(ctx.Module(), nil, m.props.Deps...)
|
||||
ctx.AddDependency(ctx.Module(), installDepTag{}, m.props.Deps...)
|
||||
}
|
||||
|
||||
func depsModuleFactory() Module {
|
||||
m := &depsModule{}
|
||||
m.AddProperties(&m.props)
|
||||
InitAndroidModule(m)
|
||||
InitAndroidArchModule(m, HostAndDeviceDefault, MultilibCommon)
|
||||
return m
|
||||
}
|
||||
|
||||
@@ -320,3 +336,282 @@ func TestDistErrorChecking(t *testing.T) {
|
||||
ExtendWithErrorHandler(FixtureExpectsAllErrorsToMatchAPattern(expectedErrs)).
|
||||
RunTestWithBp(t, bp)
|
||||
}
|
||||
|
||||
func TestInstall(t *testing.T) {
|
||||
if runtime.GOOS != "linux" {
|
||||
t.Skip("requires linux")
|
||||
}
|
||||
bp := `
|
||||
deps {
|
||||
name: "foo",
|
||||
deps: ["bar"],
|
||||
}
|
||||
|
||||
deps {
|
||||
name: "bar",
|
||||
deps: ["baz", "qux"],
|
||||
}
|
||||
|
||||
deps {
|
||||
name: "baz",
|
||||
deps: ["qux"],
|
||||
}
|
||||
|
||||
deps {
|
||||
name: "qux",
|
||||
}
|
||||
`
|
||||
|
||||
result := GroupFixturePreparers(
|
||||
prepareForModuleTests,
|
||||
PrepareForTestWithArchMutator,
|
||||
).RunTestWithBp(t, bp)
|
||||
|
||||
module := func(name string, host bool) TestingModule {
|
||||
variant := "android_common"
|
||||
if host {
|
||||
variant = result.Config.BuildOSCommonTarget.String()
|
||||
}
|
||||
return result.ModuleForTests(name, variant)
|
||||
}
|
||||
|
||||
outputRule := func(name string) TestingBuildParams { return module(name, false).Output(name) }
|
||||
|
||||
installRule := func(name string) TestingBuildParams {
|
||||
return module(name, false).Output(filepath.Join("out/soong/target/product/test_device/system", name))
|
||||
}
|
||||
|
||||
symlinkRule := func(name string) TestingBuildParams {
|
||||
return module(name, false).Output(filepath.Join("out/soong/target/product/test_device/system/symlinks", name))
|
||||
}
|
||||
|
||||
hostOutputRule := func(name string) TestingBuildParams { return module(name, true).Output(name) }
|
||||
|
||||
hostInstallRule := func(name string) TestingBuildParams {
|
||||
return module(name, true).Output(filepath.Join("out/soong/host/linux-x86", name))
|
||||
}
|
||||
|
||||
hostSymlinkRule := func(name string) TestingBuildParams {
|
||||
return module(name, true).Output(filepath.Join("out/soong/host/linux-x86/symlinks", name))
|
||||
}
|
||||
|
||||
assertInputs := func(params TestingBuildParams, inputs ...Path) {
|
||||
t.Helper()
|
||||
AssertArrayString(t, "expected inputs", Paths(inputs).Strings(),
|
||||
append(PathsIfNonNil(params.Input), params.Inputs...).Strings())
|
||||
}
|
||||
|
||||
assertImplicits := func(params TestingBuildParams, implicits ...Path) {
|
||||
t.Helper()
|
||||
AssertArrayString(t, "expected implicit dependencies", Paths(implicits).Strings(),
|
||||
append(PathsIfNonNil(params.Implicit), params.Implicits...).Strings())
|
||||
}
|
||||
|
||||
assertOrderOnlys := func(params TestingBuildParams, orderonlys ...Path) {
|
||||
t.Helper()
|
||||
AssertArrayString(t, "expected orderonly dependencies", Paths(orderonlys).Strings(),
|
||||
params.OrderOnly.Strings())
|
||||
}
|
||||
|
||||
// Check host install rule dependencies
|
||||
assertInputs(hostInstallRule("foo"), hostOutputRule("foo").Output)
|
||||
assertImplicits(hostInstallRule("foo"),
|
||||
hostInstallRule("bar").Output,
|
||||
hostSymlinkRule("bar").Output,
|
||||
hostInstallRule("baz").Output,
|
||||
hostSymlinkRule("baz").Output,
|
||||
hostInstallRule("qux").Output,
|
||||
hostSymlinkRule("qux").Output,
|
||||
)
|
||||
assertOrderOnlys(hostInstallRule("foo"))
|
||||
|
||||
// Check host symlink rule dependencies
|
||||
assertInputs(hostSymlinkRule("foo"), hostInstallRule("foo").Output)
|
||||
assertImplicits(hostSymlinkRule("foo"))
|
||||
assertOrderOnlys(hostSymlinkRule("foo"))
|
||||
|
||||
// Check device install rule dependencies
|
||||
assertInputs(installRule("foo"), outputRule("foo").Output)
|
||||
assertImplicits(installRule("foo"))
|
||||
assertOrderOnlys(installRule("foo"),
|
||||
installRule("bar").Output,
|
||||
symlinkRule("bar").Output,
|
||||
installRule("baz").Output,
|
||||
symlinkRule("baz").Output,
|
||||
installRule("qux").Output,
|
||||
symlinkRule("qux").Output,
|
||||
)
|
||||
|
||||
// Check device symlink rule dependencies
|
||||
assertInputs(symlinkRule("foo"), installRule("foo").Output)
|
||||
assertImplicits(symlinkRule("foo"))
|
||||
assertOrderOnlys(symlinkRule("foo"))
|
||||
}
|
||||
|
||||
func TestInstallBypassMake(t *testing.T) {
|
||||
if runtime.GOOS != "linux" {
|
||||
t.Skip("requires linux")
|
||||
}
|
||||
bp := `
|
||||
deps {
|
||||
name: "foo",
|
||||
deps: ["bar"],
|
||||
}
|
||||
|
||||
deps {
|
||||
name: "bar",
|
||||
deps: ["baz", "qux"],
|
||||
}
|
||||
|
||||
deps {
|
||||
name: "baz",
|
||||
deps: ["qux"],
|
||||
}
|
||||
|
||||
deps {
|
||||
name: "qux",
|
||||
}
|
||||
`
|
||||
|
||||
result := GroupFixturePreparers(
|
||||
prepareForModuleTests,
|
||||
PrepareForTestWithArchMutator,
|
||||
FixtureModifyConfig(SetKatiEnabledForTests),
|
||||
FixtureRegisterWithContext(func(ctx RegistrationContext) {
|
||||
ctx.RegisterSingletonType("makevars", makeVarsSingletonFunc)
|
||||
}),
|
||||
).RunTestWithBp(t, bp)
|
||||
|
||||
installs := result.SingletonForTests("makevars").Singleton().(*makeVarsSingleton).installsForTesting
|
||||
buf := bytes.NewBuffer(append([]byte(nil), installs...))
|
||||
parser := mkparser.NewParser("makevars", buf)
|
||||
|
||||
nodes, errs := parser.Parse()
|
||||
if len(errs) > 0 {
|
||||
t.Fatalf("error parsing install rules: %s", errs[0])
|
||||
}
|
||||
|
||||
rules := parseMkRules(t, result.Config, nodes)
|
||||
|
||||
module := func(name string, host bool) TestingModule {
|
||||
variant := "android_common"
|
||||
if host {
|
||||
variant = result.Config.BuildOSCommonTarget.String()
|
||||
}
|
||||
return result.ModuleForTests(name, variant)
|
||||
}
|
||||
|
||||
outputRule := func(name string) TestingBuildParams { return module(name, false).Output(name) }
|
||||
|
||||
ruleForOutput := func(output string) installMakeRule {
|
||||
for _, rule := range rules {
|
||||
if rule.target == output {
|
||||
return rule
|
||||
}
|
||||
}
|
||||
t.Fatalf("no make install rule for %s", output)
|
||||
return installMakeRule{}
|
||||
}
|
||||
|
||||
installRule := func(name string) installMakeRule {
|
||||
return ruleForOutput(filepath.Join("out/target/product/test_device/system", name))
|
||||
}
|
||||
|
||||
symlinkRule := func(name string) installMakeRule {
|
||||
return ruleForOutput(filepath.Join("out/target/product/test_device/system/symlinks", name))
|
||||
}
|
||||
|
||||
hostOutputRule := func(name string) TestingBuildParams { return module(name, true).Output(name) }
|
||||
|
||||
hostInstallRule := func(name string) installMakeRule {
|
||||
return ruleForOutput(filepath.Join("out/host/linux-x86", name))
|
||||
}
|
||||
|
||||
hostSymlinkRule := func(name string) installMakeRule {
|
||||
return ruleForOutput(filepath.Join("out/host/linux-x86/symlinks", name))
|
||||
}
|
||||
|
||||
assertDeps := func(rule installMakeRule, deps ...string) {
|
||||
t.Helper()
|
||||
AssertArrayString(t, "expected inputs", deps, rule.deps)
|
||||
}
|
||||
|
||||
assertOrderOnlys := func(rule installMakeRule, orderonlys ...string) {
|
||||
t.Helper()
|
||||
AssertArrayString(t, "expected orderonly dependencies", orderonlys, rule.orderOnlyDeps)
|
||||
}
|
||||
|
||||
// Check host install rule dependencies
|
||||
assertDeps(hostInstallRule("foo"),
|
||||
hostOutputRule("foo").Output.String(),
|
||||
hostInstallRule("bar").target,
|
||||
hostSymlinkRule("bar").target,
|
||||
hostInstallRule("baz").target,
|
||||
hostSymlinkRule("baz").target,
|
||||
hostInstallRule("qux").target,
|
||||
hostSymlinkRule("qux").target,
|
||||
)
|
||||
assertOrderOnlys(hostInstallRule("foo"))
|
||||
|
||||
// Check host symlink rule dependencies
|
||||
assertDeps(hostSymlinkRule("foo"))
|
||||
assertOrderOnlys(hostSymlinkRule("foo"), hostInstallRule("foo").target)
|
||||
|
||||
// Check device install rule dependencies
|
||||
assertDeps(installRule("foo"), outputRule("foo").Output.String())
|
||||
assertOrderOnlys(installRule("foo"),
|
||||
installRule("bar").target,
|
||||
symlinkRule("bar").target,
|
||||
installRule("baz").target,
|
||||
symlinkRule("baz").target,
|
||||
installRule("qux").target,
|
||||
symlinkRule("qux").target,
|
||||
)
|
||||
|
||||
// Check device symlink rule dependencies
|
||||
assertDeps(symlinkRule("foo"))
|
||||
assertOrderOnlys(symlinkRule("foo"), installRule("foo").target)
|
||||
}
|
||||
|
||||
type installMakeRule struct {
|
||||
target string
|
||||
deps []string
|
||||
orderOnlyDeps []string
|
||||
}
|
||||
|
||||
func parseMkRules(t *testing.T, config Config, nodes []mkparser.Node) []installMakeRule {
|
||||
var rules []installMakeRule
|
||||
for _, node := range nodes {
|
||||
if mkParserRule, ok := node.(*mkparser.Rule); ok {
|
||||
var rule installMakeRule
|
||||
|
||||
if targets := mkParserRule.Target.Words(); len(targets) == 0 {
|
||||
t.Fatalf("no targets for rule %s", mkParserRule.Dump())
|
||||
} else if len(targets) > 1 {
|
||||
t.Fatalf("unsupported multiple targets for rule %s", mkParserRule.Dump())
|
||||
} else if !targets[0].Const() {
|
||||
t.Fatalf("unsupported non-const target for rule %s", mkParserRule.Dump())
|
||||
} else {
|
||||
rule.target = normalizeStringRelativeToTop(config, targets[0].Value(nil))
|
||||
}
|
||||
|
||||
prereqList := &rule.deps
|
||||
for _, prereq := range mkParserRule.Prerequisites.Words() {
|
||||
if !prereq.Const() {
|
||||
t.Fatalf("unsupported non-const prerequisite for rule %s", mkParserRule.Dump())
|
||||
}
|
||||
|
||||
if prereq.Value(nil) == "|" {
|
||||
prereqList = &rule.orderOnlyDeps
|
||||
continue
|
||||
}
|
||||
|
||||
*prereqList = append(*prereqList, normalizeStringRelativeToTop(config, prereq.Value(nil)))
|
||||
}
|
||||
|
||||
rules = append(rules, rule)
|
||||
}
|
||||
}
|
||||
|
||||
return rules
|
||||
}
|
||||
|
Reference in New Issue
Block a user