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",
|
"soong-ui-metrics_proto",
|
||||||
"golang-protobuf-proto",
|
"golang-protobuf-proto",
|
||||||
"golang-protobuf-encoding-prototext",
|
"golang-protobuf-encoding-prototext",
|
||||||
|
|
||||||
|
// Only used for tests.
|
||||||
|
"androidmk-parser",
|
||||||
],
|
],
|
||||||
srcs: [
|
srcs: [
|
||||||
"androidmk.go",
|
"androidmk.go",
|
||||||
|
@@ -142,15 +142,19 @@ type SingletonMakeVarsProvider interface {
|
|||||||
|
|
||||||
var singletonMakeVarsProvidersKey = NewOnceKey("singletonMakeVarsProvidersKey")
|
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
|
// registerSingletonMakeVarsProvider adds a singleton that implements SingletonMakeVarsProvider to
|
||||||
// the list of MakeVarsProviders to run.
|
// the list of MakeVarsProviders to run.
|
||||||
func registerSingletonMakeVarsProvider(config Config, singleton SingletonMakeVarsProvider) {
|
func registerSingletonMakeVarsProvider(config Config, singleton SingletonMakeVarsProvider) {
|
||||||
// Singletons are registered on the Context and may be different between different Contexts,
|
// Singletons are registered on the Context and may be different between different Contexts,
|
||||||
// for example when running multiple tests. Store the SingletonMakeVarsProviders in the
|
// for example when running multiple tests. Store the SingletonMakeVarsProviders in the
|
||||||
// Config so they are attached to the Context.
|
// Config so they are attached to the Context.
|
||||||
singletonMakeVarsProviders := config.Once(singletonMakeVarsProvidersKey, func() interface{} {
|
singletonMakeVarsProviders := getSingletonMakevarsProviders(config)
|
||||||
return &[]makeVarsProvider{}
|
|
||||||
}).(*[]makeVarsProvider)
|
|
||||||
|
|
||||||
*singletonMakeVarsProviders = append(*singletonMakeVarsProviders,
|
*singletonMakeVarsProviders = append(*singletonMakeVarsProviders,
|
||||||
makeVarsProvider{pctx, singletonMakeVarsProviderAdapter(singleton)})
|
makeVarsProvider{pctx, singletonMakeVarsProviderAdapter(singleton)})
|
||||||
@@ -175,7 +179,9 @@ func makeVarsSingletonFunc() Singleton {
|
|||||||
return &makeVarsSingleton{}
|
return &makeVarsSingleton{}
|
||||||
}
|
}
|
||||||
|
|
||||||
type makeVarsSingleton struct{}
|
type makeVarsSingleton struct {
|
||||||
|
installsForTesting []byte
|
||||||
|
}
|
||||||
|
|
||||||
type makeVarsProvider struct {
|
type makeVarsProvider struct {
|
||||||
pctx PackageContext
|
pctx PackageContext
|
||||||
@@ -238,7 +244,7 @@ func (s *makeVarsSingleton) GenerateBuildActions(ctx SingletonContext) {
|
|||||||
var katiSymlinks []katiInstall
|
var katiSymlinks []katiInstall
|
||||||
|
|
||||||
providers := append([]makeVarsProvider(nil), makeVarsInitProviders...)
|
providers := append([]makeVarsProvider(nil), makeVarsInitProviders...)
|
||||||
providers = append(providers, *ctx.Config().Get(singletonMakeVarsProvidersKey).(*[]makeVarsProvider)...)
|
providers = append(providers, *getSingletonMakevarsProviders(ctx.Config())...)
|
||||||
|
|
||||||
for _, provider := range providers {
|
for _, provider := range providers {
|
||||||
mctx := &makeVarsContext{
|
mctx := &makeVarsContext{
|
||||||
@@ -313,6 +319,8 @@ func (s *makeVarsSingleton) GenerateBuildActions(ctx SingletonContext) {
|
|||||||
if err := pathtools.WriteFileIfChanged(installsFile, installsBytes, 0666); err != nil {
|
if err := pathtools.WriteFileIfChanged(installsFile, installsBytes, 0666); err != nil {
|
||||||
ctx.Errorf(err.Error())
|
ctx.Errorf(err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
s.installsForTesting = installsBytes
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *makeVarsSingleton) writeVars(vars []makeVarsVariable) []byte {
|
func (s *makeVarsSingleton) writeVars(vars []makeVarsVariable) []byte {
|
||||||
|
@@ -15,7 +15,12 @@
|
|||||||
package android
|
package android
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
|
"path/filepath"
|
||||||
|
"runtime"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
mkparser "android/soong/androidmk/parser"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestSrcIsModule(t *testing.T) {
|
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) {
|
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) {
|
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 {
|
func depsModuleFactory() Module {
|
||||||
m := &depsModule{}
|
m := &depsModule{}
|
||||||
m.AddProperties(&m.props)
|
m.AddProperties(&m.props)
|
||||||
InitAndroidModule(m)
|
InitAndroidArchModule(m, HostAndDeviceDefault, MultilibCommon)
|
||||||
return m
|
return m
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -320,3 +336,282 @@ func TestDistErrorChecking(t *testing.T) {
|
|||||||
ExtendWithErrorHandler(FixtureExpectsAllErrorsToMatchAPattern(expectedErrs)).
|
ExtendWithErrorHandler(FixtureExpectsAllErrorsToMatchAPattern(expectedErrs)).
|
||||||
RunTestWithBp(t, bp)
|
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