diff options
72 files changed, 1996 insertions, 1127 deletions
diff --git a/android/androidmk.go b/android/androidmk.go index 32d771200..93175670f 100644 --- a/android/androidmk.go +++ b/android/androidmk.go @@ -44,6 +44,14 @@ func RegisterAndroidMkBuildComponents(ctx RegistrationContext) { ctx.RegisterSingletonType("androidmk", AndroidMkSingleton) } +// Enable androidmk support. +// * Register the singleton +// * Configure that we are inside make +var PrepareForTestWithAndroidMk = GroupFixturePreparers( + FixtureRegisterWithContext(RegisterAndroidMkBuildComponents), + FixtureModifyConfig(SetKatiEnabledForTests), +) + // Deprecated: Use AndroidMkEntriesProvider instead, especially if you're not going to use the // Custom function. It's easier to use and test. type AndroidMkDataProvider interface { diff --git a/android/bazel_handler.go b/android/bazel_handler.go index 9cd9fadfe..667584072 100644 --- a/android/bazel_handler.go +++ b/android/bazel_handler.go @@ -37,6 +37,7 @@ type CqueryRequestType int const ( getAllFiles CqueryRequestType = iota getCcObjectFiles + getAllFilesAndCcObjectFiles ) // Map key to describe bazel cquery requests. @@ -58,7 +59,9 @@ type BazelContext interface { // Retrieves these files from Bazel's CcInfo provider. GetCcObjectFiles(label string, archType ArchType) ([]string, bool) - // TODO(cparsons): Other cquery-related methods should be added here. + // Returns the results of GetAllFiles and GetCcObjectFiles in a single query (in that order). + GetAllFilesAndCcObjectFiles(label string, archType ArchType) ([]string, []string, bool) + // ** End cquery methods // Issues commands to Bazel to receive results for all cquery requests @@ -116,6 +119,11 @@ func (m MockBazelContext) GetCcObjectFiles(label string, archType ArchType) ([]s return result, ok } +func (m MockBazelContext) GetAllFilesAndCcObjectFiles(label string, archType ArchType) ([]string, []string, bool) { + result, ok := m.AllFiles[label] + return result, result, ok +} + func (m MockBazelContext) InvokeBazel() error { panic("unimplemented") } @@ -154,6 +162,22 @@ func (bazelCtx *bazelContext) GetCcObjectFiles(label string, archType ArchType) } } +func (bazelCtx *bazelContext) GetAllFilesAndCcObjectFiles(label string, archType ArchType) ([]string, []string, bool) { + var allFiles []string + var ccObjects []string + + result, ok := bazelCtx.cquery(label, getAllFilesAndCcObjectFiles, archType) + if ok { + bazelOutput := strings.TrimSpace(result) + splitString := strings.Split(bazelOutput, "|") + allFilesString := splitString[0] + ccObjectsString := splitString[1] + allFiles = strings.Split(allFilesString, ", ") + ccObjects = strings.Split(ccObjectsString, ", ") + } + return allFiles, ccObjects, ok +} + func (n noopBazelContext) GetAllFiles(label string, archType ArchType) ([]string, bool) { panic("unimplemented") } @@ -162,6 +186,10 @@ func (n noopBazelContext) GetCcObjectFiles(label string, archType ArchType) ([]s panic("unimplemented") } +func (n noopBazelContext) GetAllFilesAndCcObjectFiles(label string, archType ArchType) ([]string, []string, bool) { + panic("unimplemented") +} + func (n noopBazelContext) InvokeBazel() error { panic("unimplemented") } @@ -253,8 +281,12 @@ func pwdPrefix() string { return "" } +// Issues the given bazel command with given build label and additional flags. +// Returns (stdout, stderr, error). The first and second return values are strings +// containing the stdout and stderr of the run command, and an error is returned if +// the invocation returned an error code. func (context *bazelContext) issueBazelCommand(runName bazel.RunName, command string, labels []string, - extraFlags ...string) (string, error) { + extraFlags ...string) (string, string, error) { cmdFlags := []string{"--output_base=" + context.outputBase, command} cmdFlags = append(cmdFlags, labels...) @@ -281,9 +313,10 @@ func (context *bazelContext) issueBazelCommand(runName bazel.RunName, command st bazelCmd.Stderr = stderr if output, err := bazelCmd.Output(); err != nil { - return "", fmt.Errorf("bazel command failed. command: [%s], env: [%s], error [%s]", bazelCmd, bazelCmd.Env, stderr) + return "", string(stderr.Bytes()), + fmt.Errorf("bazel command failed. command: [%s], env: [%s], error [%s]", bazelCmd, bazelCmd.Env, stderr) } else { - return string(output), nil + return string(output), string(stderr.Bytes()), nil } } @@ -452,6 +485,11 @@ phony_root(name = "phonyroot", strings.Join(deps_arm, ",\n "))) } +// Returns the file contents of the buildroot.cquery file that should be used for the cquery +// expression in order to obtain information about buildroot and its dependencies. +// The contents of this file depend on the bazelContext's requests; requests are enumerated +// and grouped by their request type. The data retrieved for each label depends on its +// request type. func (context *bazelContext) cqueryStarlarkFileContents() []byte { formatString := ` # This file is generated by soong_build. Do not edit. @@ -463,6 +501,13 @@ getCcObjectFilesLabels = { %s } +getAllFilesAndCcObjectFilesLabels = { + %s +} + +def get_all_files(target): + return [f.path for f in target.files.to_list()] + def get_cc_object_files(target): result = [] linker_inputs = providers(target)["CcInfo"].linking_context.linker_inputs.to_list() @@ -492,9 +537,11 @@ def get_arch(target): def format(target): id_string = str(target.label) + "|" + get_arch(target) if id_string in getAllFilesLabels: - return id_string + ">>" + ', '.join([f.path for f in target.files.to_list()]) + return id_string + ">>" + ', '.join(get_all_files(target)) elif id_string in getCcObjectFilesLabels: return id_string + ">>" + ', '.join(get_cc_object_files(target)) + elif id_string in getAllFilesAndCcObjectFilesLabels: + return id_string + ">>" + ', '.join(get_all_files(target)) + "|" + ', '.join(get_cc_object_files(target)) else: # This target was not requested via cquery, and thus must be a dependency # of a requested target. @@ -502,6 +549,7 @@ def format(target): ` var getAllFilesDeps []string = nil var getCcObjectFilesDeps []string = nil + var getAllFilesAndCcObjectFilesDeps []string = nil for val, _ := range context.requests { labelWithArch := getCqueryId(val) @@ -511,12 +559,16 @@ def format(target): getAllFilesDeps = append(getAllFilesDeps, mapEntryString) case getCcObjectFiles: getCcObjectFilesDeps = append(getCcObjectFilesDeps, mapEntryString) + case getAllFilesAndCcObjectFiles: + getAllFilesAndCcObjectFilesDeps = append(getAllFilesAndCcObjectFilesDeps, mapEntryString) } } getAllFilesDepsString := strings.Join(getAllFilesDeps, ",\n ") getCcObjectFilesDepsString := strings.Join(getCcObjectFilesDeps, ",\n ") + getAllFilesAndCcObjectFilesDepsString := strings.Join(getAllFilesAndCcObjectFilesDeps, ",\n ") - return []byte(fmt.Sprintf(formatString, getAllFilesDepsString, getCcObjectFilesDepsString)) + return []byte(fmt.Sprintf(formatString, getAllFilesDepsString, getCcObjectFilesDepsString, + getAllFilesAndCcObjectFilesDepsString)) } // Returns a workspace-relative path containing build-related metadata required @@ -531,6 +583,7 @@ func (context *bazelContext) InvokeBazel() error { context.results = make(map[cqueryKey]string) var cqueryOutput string + var cqueryErr string var err error intermediatesDirPath := absolutePath(context.intermediatesDir()) @@ -568,7 +621,7 @@ func (context *bazelContext) InvokeBazel() error { return err } buildrootLabel := "//:buildroot" - cqueryOutput, err = context.issueBazelCommand(bazel.CqueryBuildRootRunName, "cquery", + cqueryOutput, cqueryErr, err = context.issueBazelCommand(bazel.CqueryBuildRootRunName, "cquery", []string{fmt.Sprintf("kind(rule, deps(%s))", buildrootLabel)}, "--output=starlark", "--starlark:file="+cqueryFileRelpath) @@ -595,7 +648,8 @@ func (context *bazelContext) InvokeBazel() error { if cqueryResult, ok := cqueryResults[getCqueryId(val)]; ok { context.results[val] = string(cqueryResult) } else { - return fmt.Errorf("missing result for bazel target %s. query output: [%s]", getCqueryId(val), cqueryOutput) + return fmt.Errorf("missing result for bazel target %s. query output: [%s], cquery err: [%s]", + getCqueryId(val), cqueryOutput, cqueryErr) } } @@ -603,7 +657,7 @@ func (context *bazelContext) InvokeBazel() error { // // TODO(cparsons): Use --target_pattern_file to avoid command line limits. var aqueryOutput string - aqueryOutput, err = context.issueBazelCommand(bazel.AqueryBuildRootRunName, "aquery", + aqueryOutput, _, err = context.issueBazelCommand(bazel.AqueryBuildRootRunName, "aquery", []string{fmt.Sprintf("deps(%s)", buildrootLabel), // Use jsonproto instead of proto; actual proto parsing would require a dependency on Bazel's // proto sources, which would add a number of unnecessary dependencies. @@ -621,7 +675,7 @@ func (context *bazelContext) InvokeBazel() error { // Issue a build command of the phony root to generate symlink forests for dependencies of the // Bazel build. This is necessary because aquery invocations do not generate this symlink forest, // but some of symlinks may be required to resolve source dependencies of the build. - _, err = context.issueBazelCommand(bazel.BazelBuildPhonyRootRunName, "build", + _, _, err = context.issueBazelCommand(bazel.BazelBuildPhonyRootRunName, "build", []string{"//:phonyroot"}) if err != nil { diff --git a/android/config.go b/android/config.go index c10ad09ae..bc1aa3a4d 100644 --- a/android/config.go +++ b/android/config.go @@ -287,24 +287,21 @@ func TestArchConfigNativeBridge(buildDir string, env map[string]string, bp strin return testConfig } -// TestArchConfigFuchsia returns a Config object suitable for using for -// tests that need to run the arch mutator for the Fuchsia arch. -func TestArchConfigFuchsia(buildDir string, env map[string]string, bp string, fs map[string][]byte) Config { - testConfig := TestConfig(buildDir, env, bp, fs) - config := testConfig.config - - config.Targets = map[OsType][]Target{ - Fuchsia: []Target{ +func fuchsiaTargets() map[OsType][]Target { + return map[OsType][]Target{ + Fuchsia: { {Fuchsia, Arch{ArchType: Arm64, ArchVariant: "", Abi: []string{"arm64-v8a"}}, NativeBridgeDisabled, "", "", false}, }, - BuildOs: []Target{ + BuildOs: { {BuildOs, Arch{ArchType: X86_64}, NativeBridgeDisabled, "", "", false}, }, } - - return testConfig } +var PrepareForTestSetDeviceToFuchsia = FixtureModifyConfig(func(config Config) { + config.Targets = fuchsiaTargets() +}) + func modifyTestConfigToSupportArchMutator(testConfig Config) { config := testConfig.config @@ -527,26 +524,6 @@ func (c *config) HostJavaToolPath(ctx PathContext, path string) Path { return PathForOutput(ctx, "host", c.PrebuiltOS(), "framework", path) } -// NonHermeticHostSystemTool looks for non-hermetic tools from the system we're -// running on. These tools are not checked-in to AOSP, and therefore could lead -// to reproducibility problems. Should not be used for other than finding the -// XCode SDK (xcrun, sw_vers), etc. See ui/build/paths/config.go for the -// allowlist of host system tools. -func (c *config) NonHermeticHostSystemTool(name string) string { - for _, dir := range filepath.SplitList(c.Getenv("PATH")) { - path := filepath.Join(dir, name) - if s, err := os.Stat(path); err != nil { - continue - } else if m := s.Mode(); !s.IsDir() && m&0111 != 0 { - return path - } - } - panic(fmt.Errorf( - "Unable to use '%s' as a host system tool for build system "+ - "hermeticity reasons. See build/soong/ui/build/paths/config.go "+ - "for the full list of allowed host tools on your system.", name)) -} - // PrebuiltOS returns the name of the host OS used in prebuilts directories. func (c *config) PrebuiltOS() string { switch runtime.GOOS { diff --git a/android/fixture.go b/android/fixture.go index 2c8997bd2..552c8f569 100644 --- a/android/fixture.go +++ b/android/fixture.go @@ -15,6 +15,7 @@ package android import ( + "fmt" "reflect" "strings" "testing" @@ -182,12 +183,12 @@ type FixtureFactory interface { // Create a Fixture. Fixture(t *testing.T, preparers ...FixturePreparer) Fixture - // SetErrorHandler creates a new FixtureFactory that will use the supplied error handler to check - // the errors (may be 0) reported by the test. + // ExtendWithErrorHandler creates a new FixtureFactory that will use the supplied error handler + // to check the errors (may be 0) reported by the test. // // The default handlers is FixtureExpectsNoErrors which will fail the go test immediately if any // errors are reported. - SetErrorHandler(errorHandler FixtureErrorHandler) FixtureFactory + ExtendWithErrorHandler(errorHandler FixtureErrorHandler) FixtureFactory // Run the test, checking any errors reported and returning a TestResult instance. // @@ -198,6 +199,24 @@ type FixtureFactory interface { // // Shorthand for RunTest(t, android.FixtureWithRootAndroidBp(bp)) RunTestWithBp(t *testing.T, bp string) *TestResult + + // RunTestWithConfig is a temporary method added to help ease the migration of existing tests to + // the test fixture. + // + // In order to allow the Config object to be customized separately to the TestContext a lot of + // existing test code has `test...WithConfig` funcs that allow the Config object to be supplied + // from the test and then have the TestContext created and configured automatically. e.g. + // testCcWithConfig, testCcErrorWithConfig, testJavaWithConfig, etc. + // + // This method allows those methods to be migrated to use the test fixture pattern without + // requiring that every test that uses those methods be migrated at the same time. That allows + // those tests to benefit from correctness in the order of registration quickly. + // + // This method discards the config (along with its mock file system, product variables, + // environment, etc.) that may have been set up by FixturePreparers. + // + // deprecated + RunTestWithConfig(t *testing.T, config Config) *TestResult } // Create a new FixtureFactory that will apply the supplied preparers. @@ -286,6 +305,45 @@ func FixtureWithRootAndroidBp(contents string) FixturePreparer { return FixtureAddTextFile("Android.bp", contents) } +// Merge some environment variables into the fixture. +func FixtureMergeEnv(env map[string]string) FixturePreparer { + return FixtureModifyConfig(func(config Config) { + for k, v := range env { + if k == "PATH" { + panic("Cannot set PATH environment variable") + } + config.env[k] = v + } + }) +} + +// Modify the env. +// +// Will panic if the mutator changes the PATH environment variable. +func FixtureModifyEnv(mutator func(env map[string]string)) FixturePreparer { + return FixtureModifyConfig(func(config Config) { + oldPath := config.env["PATH"] + mutator(config.env) + newPath := config.env["PATH"] + if newPath != oldPath { + panic(fmt.Errorf("Cannot change PATH environment variable from %q to %q", oldPath, newPath)) + } + }) +} + +// Allow access to the product variables when preparing the fixture. +type FixtureProductVariables struct { + *productVariables +} + +// Modify product variables. +func FixtureModifyProductVariables(mutator func(variables FixtureProductVariables)) FixturePreparer { + return FixtureModifyConfig(func(config Config) { + productVariables := FixtureProductVariables{&config.productVariables} + mutator(productVariables) + }) +} + // GroupFixturePreparers creates a composite FixturePreparer that is equivalent to applying each of // the supplied FixturePreparer instances in order. // @@ -484,6 +542,18 @@ func (h *TestHelper) AssertStringEquals(message string, expected string, actual } } +// AssertErrorMessageEquals checks if the error is not nil and has the expected message. If it does +// not then this reports an error prefixed with the supplied message and including a reason for why +// it failed. +func (h *TestHelper) AssertErrorMessageEquals(message string, expected string, actual error) { + h.Helper() + if actual == nil { + h.Errorf("Expected error but was nil") + } else if actual.Error() != expected { + h.Errorf("%s: expected %s, actual %s", message, expected, actual.Error()) + } +} + // AssertTrimmedStringEquals checks if the expected and actual values are the same after trimming // leading and trailing spaces from them both. If they are not then it reports an error prefixed // with the supplied message and including a reason for why it failed. @@ -511,6 +581,16 @@ func (h *TestHelper) AssertStringDoesNotContain(message string, s string, unexpe } } +// AssertStringListContains checks if the list of strings contains the expected string. If it does +// not then it reports an error prefixed with the supplied message and including a reason for why it +// failed. +func (h *TestHelper) AssertStringListContains(message string, list []string, expected string) { + h.Helper() + if !InList(expected, list) { + h.Errorf("%s: could not find %q within %q", message, expected, list) + } +} + // AssertArrayString checks if the expected and actual values are equal and if they are not then it // reports an error prefixed with the supplied message and including a reason for why it failed. func (h *TestHelper) AssertArrayString(message string, expected, actual []string) { @@ -528,7 +608,7 @@ func (h *TestHelper) AssertArrayString(message string, expected, actual []string } } -// AssertArrayString checks if the expected and actual values are equal using reflect.DeepEqual and +// AssertDeepEquals checks if the expected and actual values are equal using reflect.DeepEqual and // if they are not then it reports an error prefixed with the supplied message and including a // reason for why it failed. func (h *TestHelper) AssertDeepEquals(message string, expected interface{}, actual interface{}) { @@ -538,6 +618,23 @@ func (h *TestHelper) AssertDeepEquals(message string, expected interface{}, actu } } +// AssertPanic checks that the supplied function panics as expected. +func (h *TestHelper) AssertPanic(message string, funcThatShouldPanic func()) { + h.Helper() + panicked := false + func() { + defer func() { + if x := recover(); x != nil { + panicked = true + } + }() + funcThatShouldPanic() + }() + if !panicked { + h.Error(message) + } +} + // Struct to allow TestResult to embed a *TestContext and allow call forwarding to its methods. type testContext struct { *TestContext @@ -564,7 +661,11 @@ type fixtureFactory struct { } func (f *fixtureFactory) Extend(preparers ...FixturePreparer) FixtureFactory { - all := append(f.preparers, dedupAndFlattenPreparers(f.preparers, preparers)...) + // Create a new slice to avoid accidentally sharing the preparers slice from this factory with + // the extending factories. + var all []*simpleFixturePreparer + all = append(all, f.preparers...) + all = append(all, dedupAndFlattenPreparers(f.preparers, preparers)...) // Copy the existing factory. extendedFactory := &fixtureFactory{} *extendedFactory = *f @@ -596,7 +697,7 @@ func (f *fixtureFactory) Fixture(t *testing.T, preparers ...FixturePreparer) Fix return fixture } -func (f *fixtureFactory) SetErrorHandler(errorHandler FixtureErrorHandler) FixtureFactory { +func (f *fixtureFactory) ExtendWithErrorHandler(errorHandler FixtureErrorHandler) FixtureFactory { newFactory := &fixtureFactory{} *newFactory = *f newFactory.errorHandler = errorHandler @@ -614,6 +715,28 @@ func (f *fixtureFactory) RunTestWithBp(t *testing.T, bp string) *TestResult { return f.RunTest(t, FixtureWithRootAndroidBp(bp)) } +func (f *fixtureFactory) RunTestWithConfig(t *testing.T, config Config) *TestResult { + t.Helper() + // Create the fixture as normal. + fixture := f.Fixture(t).(*fixture) + + // Discard the mock filesystem as otherwise that will override the one in the config. + fixture.mockFS = nil + + // Replace the config with the supplied one in the fixture. + fixture.config = config + + // Ditto with config derived information in the TestContext. + ctx := fixture.ctx + ctx.config = config + ctx.SetFs(ctx.config.fs) + if ctx.config.mockBpList != "" { + ctx.SetModuleListFile(ctx.config.mockBpList) + } + + return fixture.RunTest() +} + type fixture struct { // The factory used to create this fixture. factory *fixtureFactory @@ -639,17 +762,22 @@ func (f *fixture) RunTest() *TestResult { ctx := f.ctx - // The TestConfig() method assumes that the mock filesystem is available when creating so creates - // the mock file system immediately. Similarly, the NewTestContext(Config) method assumes that the - // supplied Config's FileSystem has been properly initialized before it is called and so it takes - // its own reference to the filesystem. However, fixtures create the Config and TestContext early - // so they can be modified by preparers at which time the mockFS has not been populated (because - // it too is modified by preparers). So, this reinitializes the Config and TestContext's - // FileSystem using the now populated mockFS. - f.config.mockFileSystem("", f.mockFS) - ctx.SetFs(ctx.config.fs) - if ctx.config.mockBpList != "" { - ctx.SetModuleListFile(ctx.config.mockBpList) + // Do not use the fixture's mockFS to initialize the config's mock file system if it has been + // cleared by RunTestWithConfig. + if f.mockFS != nil { + // The TestConfig() method assumes that the mock filesystem is available when creating so + // creates the mock file system immediately. Similarly, the NewTestContext(Config) method + // assumes that the supplied Config's FileSystem has been properly initialized before it is + // called and so it takes its own reference to the filesystem. However, fixtures create the + // Config and TestContext early so they can be modified by preparers at which time the mockFS + // has not been populated (because it too is modified by preparers). So, this reinitializes the + // Config and TestContext's FileSystem using the now populated mockFS. + f.config.mockFileSystem("", f.mockFS) + + ctx.SetFs(ctx.config.fs) + if ctx.config.mockBpList != "" { + ctx.SetModuleListFile(ctx.config.mockBpList) + } } ctx.Register() diff --git a/android/license_kind_test.go b/android/license_kind_test.go index 767b64e82..83e83cef8 100644 --- a/android/license_kind_test.go +++ b/android/license_kind_test.go @@ -8,7 +8,7 @@ import ( var licenseKindTests = []struct { name string - fs map[string][]byte + fs MockFS expectedErrors []string }{ { @@ -97,48 +97,18 @@ var licenseKindTests = []struct { func TestLicenseKind(t *testing.T) { for _, test := range licenseKindTests { t.Run(test.name, func(t *testing.T) { - _, errs := testLicenseKind(test.fs) - - expectedErrors := test.expectedErrors - if expectedErrors == nil { - FailIfErrored(t, errs) - } else { - for _, expectedError := range expectedErrors { - FailIfNoMatchingErrors(t, expectedError, errs) - } - if len(errs) > len(expectedErrors) { - t.Errorf("additional errors found, expected %d, found %d", len(expectedErrors), len(errs)) - for i, expectedError := range expectedErrors { - t.Errorf("expectedErrors[%d] = %s", i, expectedError) - } - for i, err := range errs { - t.Errorf("errs[%d] = %s", i, err) - } - } - } + licenseTestFixtureFactory. + Extend( + FixtureRegisterWithContext(func(ctx RegistrationContext) { + ctx.RegisterModuleType("mock_license", newMockLicenseModule) + }), + test.fs.AddToFixture(), + ).ExtendWithErrorHandler(FixtureExpectsAllErrorsToMatchAPattern(test.expectedErrors)). + RunTest(t) }) } } -func testLicenseKind(fs map[string][]byte) (*TestContext, []error) { - - // Create a new config per test as license_kind information is stored in the config. - config := TestArchConfig(buildDir, nil, "", fs) - - ctx := NewTestArchContext(config) - RegisterLicenseKindBuildComponents(ctx) - ctx.RegisterModuleType("mock_license", newMockLicenseModule) - ctx.Register() - - _, errs := ctx.ParseBlueprintsFiles(".") - if len(errs) > 0 { - return ctx, errs - } - - _, errs = ctx.PrepareBuildActions(config) - return ctx, errs -} - type mockLicenseProperties struct { License_kinds []string } diff --git a/android/license_test.go b/android/license_test.go index 9f6871374..a564827e6 100644 --- a/android/license_test.go +++ b/android/license_test.go @@ -4,9 +4,24 @@ import ( "testing" ) +// Common test set up for license tests. +var licenseTestFixtureFactory = emptyTestFixtureFactory.Extend( + // General preparers in alphabetical order. + PrepareForTestWithDefaults, + prepareForTestWithLicenses, + PrepareForTestWithOverrides, + PrepareForTestWithPackageModule, + PrepareForTestWithPrebuilts, + PrepareForTestWithVisibility, + + // Additional test specific stuff + prepareForTestWithFakePrebuiltModules, + FixtureMergeEnv(map[string]string{"ANDROID_REQUIRE_LICENSES": "1"}), +) + var licenseTests = []struct { name string - fs map[string][]byte + fs MockFS expectedErrors []string }{ { @@ -163,58 +178,20 @@ var licenseTests = []struct { func TestLicense(t *testing.T) { for _, test := range licenseTests { t.Run(test.name, func(t *testing.T) { - _, errs := testLicense(test.fs) - - expectedErrors := test.expectedErrors - if expectedErrors == nil { - FailIfErrored(t, errs) - } else { - for _, expectedError := range expectedErrors { - FailIfNoMatchingErrors(t, expectedError, errs) - } - if len(errs) > len(expectedErrors) { - t.Errorf("additional errors found, expected %d, found %d", len(expectedErrors), len(errs)) - for i, expectedError := range expectedErrors { - t.Errorf("expectedErrors[%d] = %s", i, expectedError) - } - for i, err := range errs { - t.Errorf("errs[%d] = %s", i, err) - } - } - } + // Customize the common license text fixture factory. + licenseTestFixtureFactory.Extend( + FixtureRegisterWithContext(func(ctx RegistrationContext) { + ctx.RegisterModuleType("rule", newMockRuleModule) + }), + test.fs.AddToFixture(), + ). + ExtendWithErrorHandler(FixtureExpectsAllErrorsToMatchAPattern(test.expectedErrors)). + RunTest(t) }) } } -func testLicense(fs map[string][]byte) (*TestContext, []error) { - - // Create a new config per test as visibility information is stored in the config. - env := make(map[string]string) - env["ANDROID_REQUIRE_LICENSES"] = "1" - config := TestArchConfig(buildDir, env, "", fs) - - ctx := NewTestArchContext(config) - RegisterPackageBuildComponents(ctx) - registerTestPrebuiltBuildComponents(ctx) - RegisterLicenseKindBuildComponents(ctx) - RegisterLicenseBuildComponents(ctx) - ctx.RegisterModuleType("rule", newMockRuleModule) - ctx.PreArchMutators(RegisterVisibilityRuleChecker) - ctx.PreArchMutators(RegisterLicensesPackageMapper) - ctx.PreArchMutators(RegisterDefaultsPreArchMutators) - ctx.PreArchMutators(RegisterLicensesPropertyGatherer) - ctx.PreArchMutators(RegisterVisibilityRuleGatherer) - ctx.PostDepsMutators(RegisterVisibilityRuleEnforcer) - ctx.PostDepsMutators(RegisterLicensesDependencyChecker) - ctx.Register() - - _, errs := ctx.ParseBlueprintsFiles(".") - if len(errs) > 0 { - return ctx, errs - } - - _, errs = ctx.PrepareBuildActions(config) - return ctx, errs +func testLicense(t *testing.T, fs MockFS, expectedErrors []string) { } type mockRuleModule struct { diff --git a/android/licenses_test.go b/android/licenses_test.go index c04379108..d0e35330a 100644 --- a/android/licenses_test.go +++ b/android/licenses_test.go @@ -6,9 +6,21 @@ import ( "github.com/google/blueprint" ) +var prepareForTestWithLicenses = GroupFixturePreparers( + FixtureRegisterWithContext(RegisterLicenseKindBuildComponents), + FixtureRegisterWithContext(RegisterLicenseBuildComponents), + FixtureRegisterWithContext(registerLicenseMutators), +) + +func registerLicenseMutators(ctx RegistrationContext) { + ctx.PreArchMutators(RegisterLicensesPackageMapper) + ctx.PreArchMutators(RegisterLicensesPropertyGatherer) + ctx.PostDepsMutators(RegisterLicensesDependencyChecker) +} + var licensesTests = []struct { name string - fs map[string][]byte + fs MockFS expectedErrors []string effectiveLicenses map[string][]string effectiveInheritedLicenses map[string][]string @@ -457,40 +469,48 @@ var licensesTests = []struct { func TestLicenses(t *testing.T) { for _, test := range licensesTests { t.Run(test.name, func(t *testing.T) { - ctx, errs := testLicenses(buildDir, test.fs) - - CheckErrorsAgainstExpectations(t, errs, test.expectedErrors) + // Customize the common license text fixture factory. + result := licenseTestFixtureFactory.Extend( + FixtureRegisterWithContext(func(ctx RegistrationContext) { + ctx.RegisterModuleType("mock_bad_module", newMockLicensesBadModule) + ctx.RegisterModuleType("mock_library", newMockLicensesLibraryModule) + ctx.RegisterModuleType("mock_defaults", defaultsLicensesFactory) + }), + test.fs.AddToFixture(), + ). + ExtendWithErrorHandler(FixtureExpectsAllErrorsToMatchAPattern(test.expectedErrors)). + RunTest(t) if test.effectiveLicenses != nil { - checkEffectiveLicenses(t, ctx, test.effectiveLicenses) + checkEffectiveLicenses(result, test.effectiveLicenses) } if test.effectivePackage != nil { - checkEffectivePackage(t, ctx, test.effectivePackage) + checkEffectivePackage(result, test.effectivePackage) } if test.effectiveNotices != nil { - checkEffectiveNotices(t, ctx, test.effectiveNotices) + checkEffectiveNotices(result, test.effectiveNotices) } if test.effectiveKinds != nil { - checkEffectiveKinds(t, ctx, test.effectiveKinds) + checkEffectiveKinds(result, test.effectiveKinds) } if test.effectiveConditions != nil { - checkEffectiveConditions(t, ctx, test.effectiveConditions) + checkEffectiveConditions(result, test.effectiveConditions) } if test.effectiveInheritedLicenses != nil { - checkEffectiveInheritedLicenses(t, ctx, test.effectiveInheritedLicenses) + checkEffectiveInheritedLicenses(result, test.effectiveInheritedLicenses) } }) } } -func checkEffectiveLicenses(t *testing.T, ctx *TestContext, effectiveLicenses map[string][]string) { +func checkEffectiveLicenses(result *TestResult, effectiveLicenses map[string][]string) { actualLicenses := make(map[string][]string) - ctx.Context.Context.VisitAllModules(func(m blueprint.Module) { + result.Context.Context.VisitAllModules(func(m blueprint.Module) { if _, ok := m.(*licenseModule); ok { return } @@ -502,7 +522,7 @@ func checkEffectiveLicenses(t *testing.T, ctx *TestContext, effectiveLicenses ma } module, ok := m.(Module) if !ok { - t.Errorf("%q not a module", m.Name()) + result.Errorf("%q not a module", m.Name()) return } base := module.base() @@ -518,14 +538,14 @@ func checkEffectiveLicenses(t *testing.T, ctx *TestContext, effectiveLicenses ma licenses = []string{} } if !compareUnorderedStringArrays(expectedLicenses, licenses) { - t.Errorf("effective licenses mismatch for module %q: expected %q, found %q", moduleName, expectedLicenses, licenses) + result.Errorf("effective licenses mismatch for module %q: expected %q, found %q", moduleName, expectedLicenses, licenses) } } } -func checkEffectiveInheritedLicenses(t *testing.T, ctx *TestContext, effectiveInheritedLicenses map[string][]string) { +func checkEffectiveInheritedLicenses(result *TestResult, effectiveInheritedLicenses map[string][]string) { actualLicenses := make(map[string][]string) - ctx.Context.Context.VisitAllModules(func(m blueprint.Module) { + result.Context.Context.VisitAllModules(func(m blueprint.Module) { if _, ok := m.(*licenseModule); ok { return } @@ -537,7 +557,7 @@ func checkEffectiveInheritedLicenses(t *testing.T, ctx *TestContext, effectiveIn } module, ok := m.(Module) if !ok { - t.Errorf("%q not a module", m.Name()) + result.Errorf("%q not a module", m.Name()) return } base := module.base() @@ -548,7 +568,7 @@ func checkEffectiveInheritedLicenses(t *testing.T, ctx *TestContext, effectiveIn for _, l := range base.commonProperties.Effective_licenses { inherited[l] = true } - ctx.Context.Context.VisitDepsDepthFirst(m, func(c blueprint.Module) { + result.Context.Context.VisitDepsDepthFirst(m, func(c blueprint.Module) { if _, ok := c.(*licenseModule); ok { return } @@ -560,7 +580,7 @@ func checkEffectiveInheritedLicenses(t *testing.T, ctx *TestContext, effectiveIn } cmodule, ok := c.(Module) if !ok { - t.Errorf("%q not a module", c.Name()) + result.Errorf("%q not a module", c.Name()) return } cbase := cmodule.base() @@ -583,14 +603,14 @@ func checkEffectiveInheritedLicenses(t *testing.T, ctx *TestContext, effectiveIn licenses = []string{} } if !compareUnorderedStringArrays(expectedInheritedLicenses, licenses) { - t.Errorf("effective inherited licenses mismatch for module %q: expected %q, found %q", moduleName, expectedInheritedLicenses, licenses) + result.Errorf("effective inherited licenses mismatch for module %q: expected %q, found %q", moduleName, expectedInheritedLicenses, licenses) } } } -func checkEffectivePackage(t *testing.T, ctx *TestContext, effectivePackage map[string]string) { +func checkEffectivePackage(result *TestResult, effectivePackage map[string]string) { actualPackage := make(map[string]string) - ctx.Context.Context.VisitAllModules(func(m blueprint.Module) { + result.Context.Context.VisitAllModules(func(m blueprint.Module) { if _, ok := m.(*licenseModule); ok { return } @@ -602,7 +622,7 @@ func checkEffectivePackage(t *testing.T, ctx *TestContext, effectivePackage map[ } module, ok := m.(Module) if !ok { - t.Errorf("%q not a module", m.Name()) + result.Errorf("%q not a module", m.Name()) return } base := module.base() @@ -623,14 +643,14 @@ func checkEffectivePackage(t *testing.T, ctx *TestContext, effectivePackage map[ packageName = "" } if expectedPackage != packageName { - t.Errorf("effective package mismatch for module %q: expected %q, found %q", moduleName, expectedPackage, packageName) + result.Errorf("effective package mismatch for module %q: expected %q, found %q", moduleName, expectedPackage, packageName) } } } -func checkEffectiveNotices(t *testing.T, ctx *TestContext, effectiveNotices map[string][]string) { +func checkEffectiveNotices(result *TestResult, effectiveNotices map[string][]string) { actualNotices := make(map[string][]string) - ctx.Context.Context.VisitAllModules(func(m blueprint.Module) { + result.Context.Context.VisitAllModules(func(m blueprint.Module) { if _, ok := m.(*licenseModule); ok { return } @@ -642,7 +662,7 @@ func checkEffectiveNotices(t *testing.T, ctx *TestContext, effectiveNotices map[ } module, ok := m.(Module) if !ok { - t.Errorf("%q not a module", m.Name()) + result.Errorf("%q not a module", m.Name()) return } base := module.base() @@ -658,14 +678,14 @@ func checkEffectiveNotices(t *testing.T, ctx *TestContext, effectiveNotices map[ notices = []string{} } if !compareUnorderedStringArrays(expectedNotices, notices) { - t.Errorf("effective notice files mismatch for module %q: expected %q, found %q", moduleName, expectedNotices, notices) + result.Errorf("effective notice files mismatch for module %q: expected %q, found %q", moduleName, expectedNotices, notices) } } } -func checkEffectiveKinds(t *testing.T, ctx *TestContext, effectiveKinds map[string][]string) { +func checkEffectiveKinds(result *TestResult, effectiveKinds map[string][]string) { actualKinds := make(map[string][]string) - ctx.Context.Context.VisitAllModules(func(m blueprint.Module) { + result.Context.Context.VisitAllModules(func(m blueprint.Module) { if _, ok := m.(*licenseModule); ok { return } @@ -677,7 +697,7 @@ func checkEffectiveKinds(t *testing.T, ctx *TestContext, effectiveKinds map[stri } module, ok := m.(Module) if !ok { - t.Errorf("%q not a module", m.Name()) + result.Errorf("%q not a module", m.Name()) return } base := module.base() @@ -693,14 +713,14 @@ func checkEffectiveKinds(t *testing.T, ctx *TestContext, effectiveKinds map[stri kinds = []string{} } if !compareUnorderedStringArrays(expectedKinds, kinds) { - t.Errorf("effective license kinds mismatch for module %q: expected %q, found %q", moduleName, expectedKinds, kinds) + result.Errorf("effective license kinds mismatch for module %q: expected %q, found %q", moduleName, expectedKinds, kinds) } } } -func checkEffectiveConditions(t *testing.T, ctx *TestContext, effectiveConditions map[string][]string) { +func checkEffectiveConditions(result *TestResult, effectiveConditions map[string][]string) { actualConditions := make(map[string][]string) - ctx.Context.Context.VisitAllModules(func(m blueprint.Module) { + result.Context.Context.VisitAllModules(func(m blueprint.Module) { if _, ok := m.(*licenseModule); ok { return } @@ -712,7 +732,7 @@ func checkEffectiveConditions(t *testing.T, ctx *TestContext, effectiveCondition } module, ok := m.(Module) if !ok { - t.Errorf("%q not a module", m.Name()) + result.Errorf("%q not a module", m.Name()) return } base := module.base() @@ -728,7 +748,7 @@ func checkEffectiveConditions(t *testing.T, ctx *TestContext, effectiveCondition conditions = []string{} } if !compareUnorderedStringArrays(expectedConditions, conditions) { - t.Errorf("effective license conditions mismatch for module %q: expected %q, found %q", moduleName, expectedConditions, conditions) + result.Errorf("effective license conditions mismatch for module %q: expected %q, found %q", moduleName, expectedConditions, conditions) } } } @@ -754,41 +774,6 @@ func compareUnorderedStringArrays(expected, actual []string) bool { return true } -func testLicenses(buildDir string, fs map[string][]byte) (*TestContext, []error) { - - // Create a new config per test as licenses information is stored in the config. - env := make(map[string]string) - env["ANDROID_REQUIRE_LICENSES"] = "1" - config := TestArchConfig(buildDir, env, "", fs) - - ctx := NewTestArchContext(config) - ctx.RegisterModuleType("mock_bad_module", newMockLicensesBadModule) - ctx.RegisterModuleType("mock_library", newMockLicensesLibraryModule) - ctx.RegisterModuleType("mock_defaults", defaultsLicensesFactory) - - // Order of the following method calls is significant. - RegisterPackageBuildComponents(ctx) - registerTestPrebuiltBuildComponents(ctx) - RegisterLicenseKindBuildComponents(ctx) - RegisterLicenseBuildComponents(ctx) - ctx.PreArchMutators(RegisterVisibilityRuleChecker) - ctx.PreArchMutators(RegisterLicensesPackageMapper) - ctx.PreArchMutators(RegisterDefaultsPreArchMutators) - ctx.PreArchMutators(RegisterLicensesPropertyGatherer) - ctx.PreArchMutators(RegisterVisibilityRuleGatherer) - ctx.PostDepsMutators(RegisterVisibilityRuleEnforcer) - ctx.PostDepsMutators(RegisterLicensesDependencyChecker) - ctx.Register() - - _, errs := ctx.ParseBlueprintsFiles(".") - if len(errs) > 0 { - return ctx, errs - } - - _, errs = ctx.PrepareBuildActions(config) - return ctx, errs -} - type mockLicensesBadProperties struct { Visibility []string } diff --git a/android/override_module.go b/android/override_module.go index fa0856631..97acc5c36 100644 --- a/android/override_module.go +++ b/android/override_module.go @@ -215,7 +215,14 @@ func RegisterOverridePostDepsMutators(ctx RegisterMutatorsContext) { ctx.BottomUp("override_deps", overrideModuleDepsMutator).Parallel() ctx.TopDown("register_override", registerOverrideMutator).Parallel() ctx.BottomUp("perform_override", performOverrideMutator).Parallel() + // overridableModuleDepsMutator calls OverridablePropertiesDepsMutator so that overridable modules can + // add deps from overridable properties. ctx.BottomUp("overridable_deps", overridableModuleDepsMutator).Parallel() + // Because overridableModuleDepsMutator is run after PrebuiltPostDepsMutator, + // prebuilt's ReplaceDependencies doesn't affect to those deps added by overridable properties. + // By running PrebuiltPostDepsMutator again after overridableModuleDepsMutator, deps via overridable properties + // can be replaced with prebuilts. + ctx.BottomUp("replace_deps_on_prebuilts_for_overridable_deps_again", PrebuiltPostDepsMutator).Parallel() ctx.BottomUp("replace_deps_on_override", replaceDepsOnOverridingModuleMutator).Parallel() } diff --git a/android/path_properties.go b/android/path_properties.go index 853e5a9a7..2c8d27c56 100644 --- a/android/path_properties.go +++ b/android/path_properties.go @@ -118,6 +118,13 @@ func fieldsByIndex(v reflect.Value, index []int, values *[]reflect.Value) { *values = append(*values, v.Index(i).Field(index[0])) } } else { + // Dereference it if it's a pointer. + if v.Kind() == reflect.Ptr { + if v.IsNil() { + return + } + v = v.Elem() + } *values = append(*values, v.Field(index[0])) } return diff --git a/android/path_properties_test.go b/android/path_properties_test.go index 2aab74835..85c96eee3 100644 --- a/android/path_properties_test.go +++ b/android/path_properties_test.go @@ -26,6 +26,9 @@ type pathDepsMutatorTestModule struct { Bar []string `android:"path,arch_variant"` Baz *string `android:"path"` Qux string + V *struct { + W string `android:"path"` + } } // A second property struct with a duplicate property name @@ -94,8 +97,11 @@ func TestPathDepsMutator(t *testing.T) { ], }, ], + v: { + w: ":w", + }, }`, - deps: []string{"a", "b", "c", "x", "y", "z"}, + deps: []string{"a", "b", "c", "w", "x", "y", "z"}, }, { name: "arch variant", @@ -136,6 +142,10 @@ func TestPathDepsMutator(t *testing.T) { } filegroup { + name: "w", + } + + filegroup { name: "x", } diff --git a/android/queryview.go b/android/queryview.go index b940202e0..12d14dfb6 100644 --- a/android/queryview.go +++ b/android/queryview.go @@ -66,16 +66,20 @@ func generateBuildActionsForBazelConversion(ctx SingletonContext, converterMode bazelQueryView := ctx.Rule(pctx, "bazelQueryView", blueprint.RuleParams{ Command: fmt.Sprintf( - "rm -rf ${outDir}/* && "+ - "BUILDER=\"%s\" && "+ - "cd $$(dirname \"$$BUILDER\") && "+ - "ABSBUILDER=\"$$PWD/$$(basename \"$$BUILDER\")\" && "+ - "cd / && "+ - "env -i \"$$ABSBUILDER\" --bazel_queryview_dir ${outDir} \"%s\" && "+ - "echo WORKSPACE: `cat %s` > ${outDir}/.queryview-depfile.d", + `rm -rf "${outDir}/"* && `+ + `mkdir -p "${outDir}" && `+ + `echo WORKSPACE: cat "%s" > "${outDir}/.queryview-depfile.d" && `+ + `BUILDER="%s" && `+ + `echo BUILDER=$$BUILDER && `+ + `cd "$$(dirname "$$BUILDER")" && `+ + `echo PWD=$$PWD && `+ + `ABSBUILDER="$$PWD/$$(basename "$$BUILDER")" && `+ + `echo ABSBUILDER=$$ABSBUILDER && `+ + `cd / && `+ + `env -i "$$ABSBUILDER" --bazel_queryview_dir "${outDir}" "%s"`, + moduleListFilePath.String(), // Use the contents of Android.bp.list as the depfile. primaryBuilder.String(), strings.Join(os.Args[1:], "\" \""), - moduleListFilePath.String(), // Use the contents of Android.bp.list as the depfile. ), CommandDeps: []string{primaryBuilder.String()}, Description: fmt.Sprintf( diff --git a/android/testing.go b/android/testing.go index 042fa2b9a..dd3d607aa 100644 --- a/android/testing.go +++ b/android/testing.go @@ -24,6 +24,7 @@ import ( "testing" "github.com/google/blueprint" + "github.com/google/blueprint/proptools" ) func NewTestContext(config Config) *TestContext { @@ -73,17 +74,47 @@ var PrepareForTestWithOverrides = FixtureRegisterWithContext(func(ctx Registrati ctx.PostDepsMutators(RegisterOverridePostDepsMutators) }) -// Prepares an integration test with build components from the android package. -var PrepareForIntegrationTestWithAndroid = GroupFixturePreparers( - // Mutators. Must match order in mutator.go. +// Test fixture preparer that will register most java build components. +// +// Singletons and mutators should only be added here if they are needed for a majority of java +// module types, otherwise they should be added under a separate preparer to allow them to be +// selected only when needed to reduce test execution time. +// +// Module types do not have much of an overhead unless they are used so this should include as many +// module types as possible. The exceptions are those module types that require mutators and/or +// singletons in order to function in which case they should be kept together in a separate +// preparer. +// +// The mutators in this group were chosen because they are needed by the vast majority of tests. +var PrepareForTestWithAndroidBuildComponents = GroupFixturePreparers( + // Sorted alphabetically as the actual order does not matter as tests automatically enforce the + // correct order. PrepareForTestWithArchMutator, - PrepareForTestWithDefaults, PrepareForTestWithComponentsMutator, - PrepareForTestWithPrebuilts, + PrepareForTestWithDefaults, + PrepareForTestWithFilegroup, PrepareForTestWithOverrides, + PrepareForTestWithPackageModule, + PrepareForTestWithPrebuilts, + PrepareForTestWithVisibility, +) - // Modules - PrepareForTestWithFilegroup, +// Prepares an integration test with all build components from the android package. +// +// This should only be used by tests that want to run with as much of the build enabled as possible. +var PrepareForIntegrationTestWithAndroid = GroupFixturePreparers( + PrepareForTestWithAndroidBuildComponents, +) + +// Prepares a test that may be missing dependencies by setting allow_missing_dependencies to +// true. +var PrepareForTestWithAllowMissingDependencies = GroupFixturePreparers( + FixtureModifyProductVariables(func(variables FixtureProductVariables) { + variables.Allow_missing_dependencies = proptools.BoolPtr(true) + }), + FixtureModifyContext(func(ctx *TestContext) { + ctx.SetAllowMissingDependencies(true) + }), ) func NewTestArchContext(config Config) *TestContext { @@ -378,9 +409,9 @@ func (ctx *TestContext) Register() { ctx.singletons.registerAll(ctx.Context) // Save the sorted components order away to make them easy to access while debugging. - ctx.preSingletonOrder = globalOrder.preSingletonOrder.namesInOrder - ctx.mutatorOrder = globalOrder.mutatorOrder.namesInOrder - ctx.singletonOrder = globalOrder.singletonOrder.namesInOrder + ctx.preSingletonOrder = componentsToNames(preSingletons) + ctx.mutatorOrder = componentsToNames(mutators) + ctx.singletonOrder = componentsToNames(singletons) } // RegisterForBazelConversion prepares a test context for bp2build conversion. @@ -787,10 +818,6 @@ func NormalizePathForTesting(path Path) string { return "<nil path>" } p := path.String() - // Allow absolute paths to /dev/ - if strings.HasPrefix(p, "/dev/") { - return p - } if w, ok := path.(WritablePath); ok { rel, err := filepath.Rel(w.buildDir(), p) if err != nil { diff --git a/android/variable.go b/android/variable.go index dd000ad22..be12a0ad9 100644 --- a/android/variable.go +++ b/android/variable.go @@ -24,11 +24,17 @@ import ( ) func init() { - PreDepsMutators(func(ctx RegisterMutatorsContext) { + registerVariableBuildComponents(InitRegistrationContext) +} + +func registerVariableBuildComponents(ctx RegistrationContext) { + ctx.PreDepsMutators(func(ctx RegisterMutatorsContext) { ctx.BottomUp("variable", VariableMutator).Parallel() }) } +var PrepareForTestWithVariables = FixtureRegisterWithContext(registerVariableBuildComponents) + type variableProperties struct { Product_variables struct { Platform_sdk_version struct { diff --git a/android/visibility.go b/android/visibility.go index 631e88ff9..5d1be6b47 100644 --- a/android/visibility.go +++ b/android/visibility.go @@ -202,17 +202,14 @@ type ExcludeFromVisibilityEnforcementTag interface { ExcludeFromVisibilityEnforcement() } -var PrepareForTestWithVisibilityRuleChecker = FixtureRegisterWithContext(func(ctx RegistrationContext) { - ctx.PreArchMutators(RegisterVisibilityRuleChecker) -}) +// The visibility mutators. +var PrepareForTestWithVisibility = FixtureRegisterWithContext(registerVisibilityMutators) -var PrepareForTestWithVisibilityRuleGatherer = FixtureRegisterWithContext(func(ctx RegistrationContext) { +func registerVisibilityMutators(ctx RegistrationContext) { + ctx.PreArchMutators(RegisterVisibilityRuleChecker) ctx.PreArchMutators(RegisterVisibilityRuleGatherer) -}) - -var PrepareForTestWithVisibilityRuleEnforcer = FixtureRegisterWithContext(func(ctx RegistrationContext) { ctx.PostDepsMutators(RegisterVisibilityRuleEnforcer) -}) +} // The rule checker needs to be registered before defaults expansion to correctly check that // //visibility:xxx isn't combined with other packages in the same list in any one module. diff --git a/android/visibility_test.go b/android/visibility_test.go index 30cdcbf8f..eb4071eb7 100644 --- a/android/visibility_test.go +++ b/android/visibility_test.go @@ -1143,25 +1143,26 @@ func TestVisibility(t *testing.T) { for _, test := range visibilityTests { t.Run(test.name, func(t *testing.T) { result := emptyTestFixtureFactory.Extend( + // General preparers in alphabetical order as test infrastructure will enforce correct + // registration order. + PrepareForTestWithArchMutator, + PrepareForTestWithDefaults, + PrepareForTestWithOverrides, + PrepareForTestWithPackageModule, + PrepareForTestWithPrebuilts, + PrepareForTestWithVisibility, + + // Additional test specific preparers. FixtureRegisterWithContext(func(ctx RegistrationContext) { ctx.RegisterModuleType("mock_library", newMockLibraryModule) ctx.RegisterModuleType("mock_parent", newMockParentFactory) ctx.RegisterModuleType("mock_defaults", defaultsFactory) }), prepareForTestWithFakePrebuiltModules, - PrepareForTestWithPackageModule, - // Order of the following method calls is significant as they register mutators. - PrepareForTestWithArchMutator, - PrepareForTestWithPrebuilts, - PrepareForTestWithOverrides, - PrepareForTestWithVisibilityRuleChecker, - PrepareForTestWithDefaults, - PrepareForTestWithVisibilityRuleGatherer, - PrepareForTestWithVisibilityRuleEnforcer, // Add additional files to the mock filesystem test.fs.AddToFixture(), ). - SetErrorHandler(FixtureExpectsAllErrorsToMatchAPattern(test.expectedErrors)). + ExtendWithErrorHandler(FixtureExpectsAllErrorsToMatchAPattern(test.expectedErrors)). RunTest(t) if test.effectiveVisibility != nil { diff --git a/android/writedocs.go b/android/writedocs.go index 6cb2f1024..67b9aa3ad 100644 --- a/android/writedocs.go +++ b/android/writedocs.go @@ -35,10 +35,11 @@ type docsSingleton struct{} func primaryBuilderPath(ctx SingletonContext) Path { buildDir := absolutePath(ctx.Config().BuildDir()) - primaryBuilder, err := filepath.Rel(buildDir, os.Args[0]) + binary := absolutePath(os.Args[0]) + primaryBuilder, err := filepath.Rel(buildDir, binary) if err != nil { - ctx.Errorf("path to primary builder %q is not in build dir %q", - os.Args[0], ctx.Config().BuildDir()) + ctx.Errorf("path to primary builder %q is not in build dir %q (%q)", + os.Args[0], ctx.Config().BuildDir(), err) } return PathForOutput(ctx, primaryBuilder) diff --git a/apex/allowed_deps.txt b/apex/allowed_deps.txt index 047a0f3d1..170302c36 100644 --- a/apex/allowed_deps.txt +++ b/apex/allowed_deps.txt @@ -163,11 +163,14 @@ crtend_android(minSdkVersion:apex_inherit) crtend_so(minSdkVersion:16) crtend_so(minSdkVersion:apex_inherit) datastallprotosnano(minSdkVersion:29) +derive_classpath(minSdkVersion:30) derive_sdk(minSdkVersion:30) derive_sdk(minSdkVersion:current) derive_sdk_prefer32(minSdkVersion:30) derive_sdk_prefer32(minSdkVersion:current) +dnsresolver_aidl_interface-lateststable-ndk_platform(minSdkVersion:29) dnsresolver_aidl_interface-unstable-ndk_platform(minSdkVersion:29) +dnsresolver_aidl_interface-V7-ndk_platform(minSdkVersion:29) dnsresolver_aidl_interface-V8-ndk_platform(minSdkVersion:29) DocumentsUI-res-lib(minSdkVersion:29) exoplayer2-extractor(minSdkVersion:16) @@ -306,6 +309,7 @@ libcrypto_utils(minSdkVersion:(no version)) libcutils(minSdkVersion:29) libcutils_headers(minSdkVersion:29) libcutils_sockets(minSdkVersion:29) +libderive_classpath(minSdkVersion:30) libderive_sdk(minSdkVersion:30) libdiagnose_usb(minSdkVersion:(no version)) libdl(minSdkVersion:(no version)) @@ -502,8 +506,10 @@ netd_aidl_interface-unstable-java(minSdkVersion:29) netd_aidl_interface-V5-java(minSdkVersion:29) netd_aidl_interface-V6-java(minSdkVersion:29) netd_event_listener_interface-java(minSdkVersion:29) +netd_event_listener_interface-lateststable-ndk_platform(minSdkVersion:29) netd_event_listener_interface-ndk_platform(minSdkVersion:29) netd_event_listener_interface-unstable-ndk_platform(minSdkVersion:29) +netd_event_listener_interface-V1-ndk_platform(minSdkVersion:29) netd_event_listener_interface-V2-ndk_platform(minSdkVersion:29) netlink-client(minSdkVersion:29) networkstack-aidl-interfaces-unstable-java(minSdkVersion:29) diff --git a/apex/apex.go b/apex/apex.go index efd1736db..e5b5c9272 100644 --- a/apex/apex.go +++ b/apex/apex.go @@ -39,16 +39,20 @@ import ( ) func init() { - android.RegisterModuleType("apex", BundleFactory) - android.RegisterModuleType("apex_test", testApexBundleFactory) - android.RegisterModuleType("apex_vndk", vndkApexBundleFactory) - android.RegisterModuleType("apex_defaults", defaultsFactory) - android.RegisterModuleType("prebuilt_apex", PrebuiltFactory) - android.RegisterModuleType("override_apex", overrideApexFactory) - android.RegisterModuleType("apex_set", apexSetFactory) + registerApexBuildComponents(android.InitRegistrationContext) +} + +func registerApexBuildComponents(ctx android.RegistrationContext) { + ctx.RegisterModuleType("apex", BundleFactory) + ctx.RegisterModuleType("apex_test", testApexBundleFactory) + ctx.RegisterModuleType("apex_vndk", vndkApexBundleFactory) + ctx.RegisterModuleType("apex_defaults", defaultsFactory) + ctx.RegisterModuleType("prebuilt_apex", PrebuiltFactory) + ctx.RegisterModuleType("override_apex", overrideApexFactory) + ctx.RegisterModuleType("apex_set", apexSetFactory) - android.PreDepsMutators(RegisterPreDepsMutators) - android.PostDepsMutators(RegisterPostDepsMutators) + ctx.PreDepsMutators(RegisterPreDepsMutators) + ctx.PostDepsMutators(RegisterPostDepsMutators) } func RegisterPreDepsMutators(ctx android.RegisterMutatorsContext) { @@ -970,6 +974,10 @@ func markPlatformAvailability(mctx android.BottomUpMutatorContext) { // If any of the dep is not available to platform, this module is also considered as being // not available to platform even if it has "//apex_available:platform" mctx.VisitDirectDeps(func(child android.Module) { + depTag := mctx.OtherModuleDependencyTag(child) + if _, ok := depTag.(android.ExcludeFromApexContentsTag); ok { + return + } if !am.DepIsInSameApex(mctx, child) { // if the dependency crosses apex boundary, don't consider it return diff --git a/apex/apex_test.go b/apex/apex_test.go index 991f5c9e9..08f54f724 100644 --- a/apex/apex_test.go +++ b/apex/apex_test.go @@ -229,14 +229,8 @@ func testApexContext(_ *testing.T, bp string, handlers ...testCustomizer) (*andr android.RegisterPackageBuildComponents(ctx) ctx.PreArchMutators(android.RegisterVisibilityRuleChecker) - ctx.RegisterModuleType("apex", BundleFactory) - ctx.RegisterModuleType("apex_test", testApexBundleFactory) - ctx.RegisterModuleType("apex_vndk", vndkApexBundleFactory) - ctx.RegisterModuleType("apex_key", ApexKeyFactory) - ctx.RegisterModuleType("apex_defaults", defaultsFactory) - ctx.RegisterModuleType("prebuilt_apex", PrebuiltFactory) - ctx.RegisterModuleType("override_apex", overrideApexFactory) - ctx.RegisterModuleType("apex_set", apexSetFactory) + registerApexBuildComponents(ctx) + registerApexKeyBuildComponents(ctx) ctx.PreArchMutators(android.RegisterDefaultsPreArchMutators) ctx.PreArchMutators(android.RegisterComponentsMutator) @@ -263,12 +257,8 @@ func testApexContext(_ *testing.T, bp string, handlers ...testCustomizer) (*andr ctx.RegisterModuleType("platform_compat_config", java.PlatformCompatConfigFactory) ctx.RegisterModuleType("sh_binary", sh.ShBinaryFactory) ctx.RegisterModuleType("filegroup", android.FileGroupFactory) - ctx.RegisterSingletonType("apex_keys_text", apexKeysTextFactory) ctx.RegisterModuleType("bpf", bpf.BpfFactory) - ctx.PreDepsMutators(RegisterPreDepsMutators) - ctx.PostDepsMutators(RegisterPostDepsMutators) - ctx.Register() return ctx, config @@ -5207,8 +5197,7 @@ func TestApexWithAppImportsPrefer(t *testing.T) { })) ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{ - // TODO(b/181974714) - this is wrong it should be "app/AppFoo/AppFooPrebuilt.apk" - "app/AppFoo/AppFoo.apk", + "app/AppFoo/AppFooPrebuilt.apk", }) } diff --git a/apex/key.go b/apex/key.go index 752888da2..8b33b593f 100644 --- a/apex/key.go +++ b/apex/key.go @@ -27,8 +27,12 @@ import ( var String = proptools.String func init() { - android.RegisterModuleType("apex_key", ApexKeyFactory) - android.RegisterSingletonType("apex_keys_text", apexKeysTextFactory) + registerApexKeyBuildComponents(android.InitRegistrationContext) +} + +func registerApexKeyBuildComponents(ctx android.RegistrationContext) { + ctx.RegisterModuleType("apex_key", ApexKeyFactory) + ctx.RegisterSingletonType("apex_keys_text", apexKeysTextFactory) } type apexKey struct { diff --git a/bp2build/Android.bp b/bp2build/Android.bp index 8deb5a217..99d706cc5 100644 --- a/bp2build/Android.bp +++ b/bp2build/Android.bp @@ -19,6 +19,7 @@ bootstrap_go_package { "soong-bazel", "soong-cc", "soong-genrule", + "soong-python", "soong-sh", ], testSrcs: [ @@ -27,6 +28,7 @@ bootstrap_go_package { "cc_library_headers_conversion_test.go", "cc_object_conversion_test.go", "conversion_test.go", + "python_binary_conversion_test.go", "sh_conversion_test.go", "testing.go", ], diff --git a/bp2build/python_binary_conversion_test.go b/bp2build/python_binary_conversion_test.go new file mode 100644 index 000000000..7600e3651 --- /dev/null +++ b/bp2build/python_binary_conversion_test.go @@ -0,0 +1,170 @@ +package bp2build + +import ( + "android/soong/android" + "android/soong/python" + "fmt" + "strings" + "testing" +) + +func TestPythonBinaryHost(t *testing.T) { + testCases := []struct { + description string + moduleTypeUnderTest string + moduleTypeUnderTestFactory android.ModuleFactory + moduleTypeUnderTestBp2BuildMutator func(android.TopDownMutatorContext) + blueprint string + expectedBazelTargets []string + filesystem map[string]string + }{ + { + description: "simple python_binary_host converts to a native py_binary", + moduleTypeUnderTest: "python_binary_host", + moduleTypeUnderTestFactory: python.PythonBinaryHostFactory, + moduleTypeUnderTestBp2BuildMutator: python.PythonBinaryBp2Build, + filesystem: map[string]string{ + "a.py": "", + "b/c.py": "", + "b/d.py": "", + "b/e.py": "", + "files/data.txt": "", + }, + blueprint: `python_binary_host { + name: "foo", + main: "a.py", + srcs: [ + "**/*.py" + ], + exclude_srcs: [ + "b/e.py" + ], + data: [ + "files/data.txt", + ], + + bazel_module: { bp2build_available: true }, +} +`, + expectedBazelTargets: []string{`py_binary( + name = "foo", + data = [ + "files/data.txt", + ], + main = "a.py", + srcs = [ + "a.py", + "b/c.py", + "b/d.py", + ], +)`, + }, + }, + { + description: "py2 python_binary_host", + moduleTypeUnderTest: "python_binary_host", + moduleTypeUnderTestFactory: python.PythonBinaryHostFactory, + moduleTypeUnderTestBp2BuildMutator: python.PythonBinaryBp2Build, + blueprint: `python_binary_host { + name: "foo", + srcs: ["a.py"], + version: { + py2: { + enabled: true, + }, + py3: { + enabled: false, + }, + }, + + bazel_module: { bp2build_available: true }, +} +`, + expectedBazelTargets: []string{`py_binary( + name = "foo", + python_version = "PY2", + srcs = [ + "a.py", + ], +)`, + }, + }, + { + description: "py3 python_binary_host", + moduleTypeUnderTest: "python_binary_host", + moduleTypeUnderTestFactory: python.PythonBinaryHostFactory, + moduleTypeUnderTestBp2BuildMutator: python.PythonBinaryBp2Build, + blueprint: `python_binary_host { + name: "foo", + srcs: ["a.py"], + version: { + py2: { + enabled: false, + }, + py3: { + enabled: true, + }, + }, + + bazel_module: { bp2build_available: true }, +} +`, + expectedBazelTargets: []string{ + // python_version is PY3 by default. + `py_binary( + name = "foo", + srcs = [ + "a.py", + ], +)`, + }, + }, + } + + dir := "." + for _, testCase := range testCases { + filesystem := make(map[string][]byte) + toParse := []string{ + "Android.bp", + } + for f, content := range testCase.filesystem { + if strings.HasSuffix(f, "Android.bp") { + toParse = append(toParse, f) + } + filesystem[f] = []byte(content) + } + config := android.TestConfig(buildDir, nil, testCase.blueprint, filesystem) + ctx := android.NewTestContext(config) + + ctx.RegisterModuleType(testCase.moduleTypeUnderTest, testCase.moduleTypeUnderTestFactory) + ctx.RegisterBp2BuildMutator(testCase.moduleTypeUnderTest, testCase.moduleTypeUnderTestBp2BuildMutator) + ctx.RegisterForBazelConversion() + + _, errs := ctx.ParseFileList(dir, toParse) + if Errored(t, testCase.description, errs) { + continue + } + _, errs = ctx.ResolveDependencies(config) + if Errored(t, testCase.description, errs) { + continue + } + + codegenCtx := NewCodegenContext(config, *ctx.Context, Bp2Build) + bazelTargets := generateBazelTargetsForDir(codegenCtx, dir) + if actualCount, expectedCount := len(bazelTargets), len(testCase.expectedBazelTargets); actualCount != expectedCount { + fmt.Println(bazelTargets) + t.Errorf("%s: Expected %d bazel target, got %d", testCase.description, expectedCount, actualCount) + } else { + for i, target := range bazelTargets { + if w, g := testCase.expectedBazelTargets[i], target.content; w != g { + t.Errorf( + "%s: Expected generated Bazel target to be '%s', got '%s'", + testCase.description, + w, + g, + ) + } + } + } + } +} diff --git a/bpf/bpf.go b/bpf/bpf.go index 8142f10a5..fa1a84d04 100644 --- a/bpf/bpf.go +++ b/bpf/bpf.go @@ -26,7 +26,7 @@ import ( ) func init() { - android.RegisterModuleType("bpf", BpfFactory) + registerBpfBuildComponents(android.InitRegistrationContext) pctx.Import("android/soong/cc/config") } @@ -43,6 +43,12 @@ var ( "ccCmd", "cFlags") ) +func registerBpfBuildComponents(ctx android.RegistrationContext) { + ctx.RegisterModuleType("bpf", BpfFactory) +} + +var PrepareForTestWithBpf = android.FixtureRegisterWithContext(registerBpfBuildComponents) + // BpfModule interface is used by the apex package to gather information from a bpf module. type BpfModule interface { android.Module diff --git a/bpf/bpf_test.go b/bpf/bpf_test.go index be9e36ea5..eb0d8c8f7 100644 --- a/bpf/bpf_test.go +++ b/bpf/bpf_test.go @@ -46,24 +46,20 @@ func TestMain(m *testing.M) { } os.Exit(run()) -} - -func testConfig(buildDir string, env map[string]string, bp string) android.Config { - mockFS := map[string][]byte{ - "bpf.c": nil, - "BpfTest.cpp": nil, - } - return cc.TestConfig(buildDir, android.Android, env, bp, mockFS) } -func testContext(config android.Config) *android.TestContext { - ctx := cc.CreateTestContext(config) - ctx.RegisterModuleType("bpf", BpfFactory) - ctx.Register() - - return ctx -} +var bpfFactory = android.NewFixtureFactory( + &buildDir, + cc.PrepareForTestWithCcDefaultModules, + android.FixtureMergeMockFs( + map[string][]byte{ + "bpf.c": nil, + "BpfTest.cpp": nil, + }, + ), + PrepareForTestWithBpf, +) func TestBpfDataDependency(t *testing.T) { bp := ` @@ -80,16 +76,7 @@ func TestBpfDataDependency(t *testing.T) { } ` - config := testConfig(buildDir, nil, bp) - ctx := testContext(config) - - _, errs := ctx.ParseFileList(".", []string{"Android.bp"}) - if errs == nil { - _, errs = ctx.PrepareBuildActions(config) - } - if errs != nil { - t.Fatal(errs) - } + bpfFactory.RunTestWithBp(t, bp) // We only verify the above BP configuration is processed successfully since the data property // value is not available for testing from this package. diff --git a/build_kzip.bash b/build_kzip.bash index 956472332..a4659d4c8 100755 --- a/build_kzip.bash +++ b/build_kzip.bash @@ -16,6 +16,7 @@ : ${BUILD_NUMBER:=$(uuidgen)} : ${KYTHE_JAVA_SOURCE_BATCH_SIZE:=500} : ${KYTHE_KZIP_ENCODING:=proto} +: ${XREF_CORPUS:?should be set} export KYTHE_JAVA_SOURCE_BATCH_SIZE KYTHE_KZIP_ENCODING # The extraction might fail for some source files, so run with -k and then check that @@ -29,11 +30,15 @@ build/soong/soong_ui.bash --build-mode --all-modules --dir=$PWD -k merge_zips xr declare -r abspath_out=$(realpath "${out}") declare -r go_extractor=$(realpath prebuilts/build-tools/linux-x86/bin/go_extractor) declare -r go_root=$(realpath prebuilts/go/linux-x86) -declare -r vnames_path=$(realpath build/soong/vnames.go.json) declare -r source_root=$PWD + +# TODO(asmundak): Until b/182183061 is fixed, default corpus has to be specified +# in the rules file. Generate this file on the fly with corpus value set from the +# environment variable. for dir in blueprint soong; do (cd "build/$dir"; - KYTHE_ROOT_DIRECTORY="${source_root}" "$go_extractor" --goroot="$go_root" --rules="${vnames_path}" \ + KYTHE_ROOT_DIRECTORY="${source_root}" "$go_extractor" --goroot="$go_root" \ + --rules=<(printf '[{"pattern": "(.*)","vname": {"path": "@1@", "corpus":"%s"}}]' "${XREF_CORPUS}") \ --canonicalize_package_corpus --output "${abspath_out}/soong/build_${dir}.go.kzip" ./... ) done diff --git a/cc/cc_test.go b/cc/cc_test.go index e640f123e..7d9fa477b 100644 --- a/cc/cc_test.go +++ b/cc/cc_test.go @@ -52,29 +52,49 @@ func TestMain(m *testing.M) { os.Exit(run()) } +var ccFixtureFactory = android.NewFixtureFactory( + &buildDir, + PrepareForTestWithCcIncludeVndk, + android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { + variables.DeviceVndkVersion = StringPtr("current") + variables.ProductVndkVersion = StringPtr("current") + variables.Platform_vndk_version = StringPtr("VER") + }), +) + +// testCcWithConfig runs tests using the ccFixtureFactory +// +// See testCc for an explanation as to how to stop using this deprecated method. +// +// deprecated func testCcWithConfig(t *testing.T, config android.Config) *android.TestContext { t.Helper() - ctx := CreateTestContext(config) - ctx.Register() - - _, errs := ctx.ParseFileList(".", []string{"Android.bp"}) - android.FailIfErrored(t, errs) - _, errs = ctx.PrepareBuildActions(config) - android.FailIfErrored(t, errs) - - return ctx + result := ccFixtureFactory.RunTestWithConfig(t, config) + return result.TestContext } +// testCc runs tests using the ccFixtureFactory +// +// Do not add any new usages of this, instead use the ccFixtureFactory directly as it makes it much +// easier to customize the test behavior. +// +// If it is necessary to customize the behavior of an existing test that uses this then please first +// convert the test to using ccFixtureFactory first and then in a following change add the +// appropriate fixture preparers. Keeping the conversion change separate makes it easy to verify +// that it did not change the test behavior unexpectedly. +// +// deprecated func testCc(t *testing.T, bp string) *android.TestContext { t.Helper() - config := TestConfig(buildDir, android.Android, nil, bp, nil) - config.TestProductVariables.DeviceVndkVersion = StringPtr("current") - config.TestProductVariables.ProductVndkVersion = StringPtr("current") - config.TestProductVariables.Platform_vndk_version = StringPtr("VER") - - return testCcWithConfig(t, config) + result := ccFixtureFactory.RunTestWithBp(t, bp) + return result.TestContext } +// testCcNoVndk runs tests using the ccFixtureFactory +// +// See testCc for an explanation as to how to stop using this deprecated method. +// +// deprecated func testCcNoVndk(t *testing.T, bp string) *android.TestContext { t.Helper() config := TestConfig(buildDir, android.Android, nil, bp, nil) @@ -83,6 +103,11 @@ func testCcNoVndk(t *testing.T, bp string) *android.TestContext { return testCcWithConfig(t, config) } +// testCcNoProductVndk runs tests using the ccFixtureFactory +// +// See testCc for an explanation as to how to stop using this deprecated method. +// +// deprecated func testCcNoProductVndk(t *testing.T, bp string) *android.TestContext { t.Helper() config := TestConfig(buildDir, android.Android, nil, bp, nil) @@ -92,27 +117,24 @@ func testCcNoProductVndk(t *testing.T, bp string) *android.TestContext { return testCcWithConfig(t, config) } +// testCcErrorWithConfig runs tests using the ccFixtureFactory +// +// See testCc for an explanation as to how to stop using this deprecated method. +// +// deprecated func testCcErrorWithConfig(t *testing.T, pattern string, config android.Config) { t.Helper() - ctx := CreateTestContext(config) - ctx.Register() - - _, errs := ctx.ParseFileList(".", []string{"Android.bp"}) - if len(errs) > 0 { - android.FailIfNoMatchingErrors(t, pattern, errs) - return - } - - _, errs = ctx.PrepareBuildActions(config) - if len(errs) > 0 { - android.FailIfNoMatchingErrors(t, pattern, errs) - return - } - - t.Fatalf("missing expected error %q (0 errors are returned)", pattern) + ccFixtureFactory.Extend(). + ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(pattern)). + RunTestWithConfig(t, config) } +// testCcError runs tests using the ccFixtureFactory +// +// See testCc for an explanation as to how to stop using this deprecated method. +// +// deprecated func testCcError(t *testing.T, pattern string, bp string) { t.Helper() config := TestConfig(buildDir, android.Android, nil, bp, nil) @@ -122,6 +144,11 @@ func testCcError(t *testing.T, pattern string, bp string) { return } +// testCcErrorProductVndk runs tests using the ccFixtureFactory +// +// See testCc for an explanation as to how to stop using this deprecated method. +// +// deprecated func testCcErrorProductVndk(t *testing.T, pattern string, bp string) { t.Helper() config := TestConfig(buildDir, android.Android, nil, bp, nil) @@ -153,13 +180,12 @@ func TestFuchsiaDeps(t *testing.T) { }, }` - config := TestConfig(buildDir, android.Fuchsia, nil, bp, nil) - ctx := testCcWithConfig(t, config) + result := ccFixtureFactory.Extend(PrepareForTestOnFuchsia).RunTestWithBp(t, bp) rt := false fb := false - ld := ctx.ModuleForTests("libTest", "fuchsia_arm64_shared").Rule("ld") + ld := result.ModuleForTests("libTest", "fuchsia_arm64_shared").Rule("ld") implicits := ld.Implicits for _, lib := range implicits { if strings.Contains(lib.Rel(), "libcompiler_rt") { @@ -190,16 +216,13 @@ func TestFuchsiaTargetDecl(t *testing.T) { }, }` - config := TestConfig(buildDir, android.Fuchsia, nil, bp, nil) - ctx := testCcWithConfig(t, config) - ld := ctx.ModuleForTests("libTest", "fuchsia_arm64_shared").Rule("ld") + result := ccFixtureFactory.Extend(PrepareForTestOnFuchsia).RunTestWithBp(t, bp) + ld := result.ModuleForTests("libTest", "fuchsia_arm64_shared").Rule("ld") var objs []string for _, o := range ld.Inputs { objs = append(objs, o.Base()) } - if len(objs) != 2 || objs[0] != "foo.o" || objs[1] != "bar.o" { - t.Errorf("inputs of libTest must be []string{\"foo.o\", \"bar.o\"}, but was %#v.", objs) - } + result.AssertArrayString("libTest inputs", []string{"foo.o", "bar.o"}, objs) } func TestVendorSrc(t *testing.T) { @@ -3397,24 +3420,16 @@ func TestProductVariableDefaults(t *testing.T) { } ` - config := TestConfig(buildDir, android.Android, nil, bp, nil) - config.TestProductVariables.Debuggable = BoolPtr(true) + result := ccFixtureFactory.Extend( + android.PrepareForTestWithVariables, - ctx := CreateTestContext(config) - ctx.PreDepsMutators(func(ctx android.RegisterMutatorsContext) { - ctx.BottomUp("variable", android.VariableMutator).Parallel() - }) - ctx.Register() + android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { + variables.Debuggable = BoolPtr(true) + }), + ).RunTestWithBp(t, bp) - _, errs := ctx.ParseFileList(".", []string{"Android.bp"}) - android.FailIfErrored(t, errs) - _, errs = ctx.PrepareBuildActions(config) - android.FailIfErrored(t, errs) - - libfoo := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_static").Module().(*Module) - if !android.InList("-DBAR", libfoo.flags.Local.CppFlags) { - t.Errorf("expected -DBAR in cppflags, got %q", libfoo.flags.Local.CppFlags) - } + libfoo := result.Module("libfoo", "android_arm64_armv8-a_static").(*Module) + result.AssertStringListContains("cppflags", libfoo.flags.Local.CppFlags, "-DBAR") } func TestEmptyWholeStaticLibsAllowMissingDependencies(t *testing.T) { @@ -3432,32 +3447,17 @@ func TestEmptyWholeStaticLibsAllowMissingDependencies(t *testing.T) { } ` - config := TestConfig(buildDir, android.Android, nil, bp, nil) - config.TestProductVariables.Allow_missing_dependencies = BoolPtr(true) - - ctx := CreateTestContext(config) - ctx.SetAllowMissingDependencies(true) - ctx.Register() - - _, errs := ctx.ParseFileList(".", []string{"Android.bp"}) - android.FailIfErrored(t, errs) - _, errs = ctx.PrepareBuildActions(config) - android.FailIfErrored(t, errs) + result := ccFixtureFactory.Extend( + android.PrepareForTestWithAllowMissingDependencies, + ).RunTestWithBp(t, bp) - libbar := ctx.ModuleForTests("libbar", "android_arm64_armv8-a_static").Output("libbar.a") - if g, w := libbar.Rule, android.ErrorRule; g != w { - t.Fatalf("Expected libbar rule to be %q, got %q", w, g) - } + libbar := result.ModuleForTests("libbar", "android_arm64_armv8-a_static").Output("libbar.a") + result.AssertDeepEquals("libbar rule", android.ErrorRule, libbar.Rule) - if g, w := libbar.Args["error"], "missing dependencies: libmissing"; !strings.Contains(g, w) { - t.Errorf("Expected libbar error to contain %q, was %q", w, g) - } - - libfoo := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_static").Output("libfoo.a") - if g, w := libfoo.Inputs.Strings(), libbar.Output.String(); !android.InList(w, g) { - t.Errorf("Expected libfoo.a to depend on %q, got %q", w, g) - } + result.AssertStringDoesContain("libbar error", libbar.Args["error"], "missing dependencies: libmissing") + libfoo := result.ModuleForTests("libfoo", "android_arm64_armv8-a_static").Output("libfoo.a") + result.AssertStringListContains("libfoo.a dependencies", libfoo.Inputs.Strings(), libbar.Output.String()) } func TestInstallSharedLibs(t *testing.T) { @@ -3647,8 +3647,9 @@ func checkHasMemtagNote(t *testing.T, m android.TestingModule, expected MemtagNo } } -func makeMemtagTestConfig(t *testing.T) android.Config { - templateBp := ` +var prepareForTestWithMemtagHeap = android.GroupFixturePreparers( + android.FixtureModifyMockFS(func(fs android.MockFS) { + templateBp := ` cc_test { name: "%[1]s_test", gtest: false, @@ -3702,35 +3703,30 @@ func makeMemtagTestConfig(t *testing.T) android.Config { sanitize: { memtag_heap: true, diag: { memtag_heap: true } }, } ` - subdirDefaultBp := fmt.Sprintf(templateBp, "default") - subdirExcludeBp := fmt.Sprintf(templateBp, "exclude") - subdirSyncBp := fmt.Sprintf(templateBp, "sync") - subdirAsyncBp := fmt.Sprintf(templateBp, "async") - - mockFS := map[string][]byte{ - "subdir_default/Android.bp": []byte(subdirDefaultBp), - "subdir_exclude/Android.bp": []byte(subdirExcludeBp), - "subdir_sync/Android.bp": []byte(subdirSyncBp), - "subdir_async/Android.bp": []byte(subdirAsyncBp), - } - - return TestConfig(buildDir, android.Android, nil, "", mockFS) -} + subdirDefaultBp := fmt.Sprintf(templateBp, "default") + subdirExcludeBp := fmt.Sprintf(templateBp, "exclude") + subdirSyncBp := fmt.Sprintf(templateBp, "sync") + subdirAsyncBp := fmt.Sprintf(templateBp, "async") + + fs.Merge(android.MockFS{ + "subdir_default/Android.bp": []byte(subdirDefaultBp), + "subdir_exclude/Android.bp": []byte(subdirExcludeBp), + "subdir_sync/Android.bp": []byte(subdirSyncBp), + "subdir_async/Android.bp": []byte(subdirAsyncBp), + }) + }), + android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { + variables.MemtagHeapExcludePaths = []string{"subdir_exclude"} + variables.MemtagHeapSyncIncludePaths = []string{"subdir_sync"} + variables.MemtagHeapAsyncIncludePaths = []string{"subdir_async"} + }), +) func TestSanitizeMemtagHeap(t *testing.T) { variant := "android_arm64_armv8-a" - config := makeMemtagTestConfig(t) - config.TestProductVariables.MemtagHeapExcludePaths = []string{"subdir_exclude"} - config.TestProductVariables.MemtagHeapSyncIncludePaths = []string{"subdir_sync"} - config.TestProductVariables.MemtagHeapAsyncIncludePaths = []string{"subdir_async"} - ctx := CreateTestContext(config) - ctx.Register() - - _, errs := ctx.ParseFileList(".", []string{"Android.bp", "subdir_default/Android.bp", "subdir_exclude/Android.bp", "subdir_sync/Android.bp", "subdir_async/Android.bp"}) - android.FailIfErrored(t, errs) - _, errs = ctx.PrepareBuildActions(config) - android.FailIfErrored(t, errs) + result := ccFixtureFactory.Extend(prepareForTestWithMemtagHeap).RunTest(t) + ctx := result.TestContext checkHasMemtagNote(t, ctx.ModuleForTests("default_test", variant), Sync) checkHasMemtagNote(t, ctx.ModuleForTests("default_test_false", variant), None) @@ -3784,18 +3780,13 @@ func TestSanitizeMemtagHeap(t *testing.T) { func TestSanitizeMemtagHeapWithSanitizeDevice(t *testing.T) { variant := "android_arm64_armv8-a" - config := makeMemtagTestConfig(t) - config.TestProductVariables.MemtagHeapExcludePaths = []string{"subdir_exclude"} - config.TestProductVariables.MemtagHeapSyncIncludePaths = []string{"subdir_sync"} - config.TestProductVariables.MemtagHeapAsyncIncludePaths = []string{"subdir_async"} - config.TestProductVariables.SanitizeDevice = []string{"memtag_heap"} - ctx := CreateTestContext(config) - ctx.Register() - - _, errs := ctx.ParseFileList(".", []string{"Android.bp", "subdir_default/Android.bp", "subdir_exclude/Android.bp", "subdir_sync/Android.bp", "subdir_async/Android.bp"}) - android.FailIfErrored(t, errs) - _, errs = ctx.PrepareBuildActions(config) - android.FailIfErrored(t, errs) + result := ccFixtureFactory.Extend( + prepareForTestWithMemtagHeap, + android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { + variables.SanitizeDevice = []string{"memtag_heap"} + }), + ).RunTest(t) + ctx := result.TestContext checkHasMemtagNote(t, ctx.ModuleForTests("default_test", variant), Sync) checkHasMemtagNote(t, ctx.ModuleForTests("default_test_false", variant), None) @@ -3849,19 +3840,14 @@ func TestSanitizeMemtagHeapWithSanitizeDevice(t *testing.T) { func TestSanitizeMemtagHeapWithSanitizeDeviceDiag(t *testing.T) { variant := "android_arm64_armv8-a" - config := makeMemtagTestConfig(t) - config.TestProductVariables.MemtagHeapExcludePaths = []string{"subdir_exclude"} - config.TestProductVariables.MemtagHeapSyncIncludePaths = []string{"subdir_sync"} - config.TestProductVariables.MemtagHeapAsyncIncludePaths = []string{"subdir_async"} - config.TestProductVariables.SanitizeDevice = []string{"memtag_heap"} - config.TestProductVariables.SanitizeDeviceDiag = []string{"memtag_heap"} - ctx := CreateTestContext(config) - ctx.Register() - - _, errs := ctx.ParseFileList(".", []string{"Android.bp", "subdir_default/Android.bp", "subdir_exclude/Android.bp", "subdir_sync/Android.bp", "subdir_async/Android.bp"}) - android.FailIfErrored(t, errs) - _, errs = ctx.PrepareBuildActions(config) - android.FailIfErrored(t, errs) + result := ccFixtureFactory.Extend( + prepareForTestWithMemtagHeap, + android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { + variables.SanitizeDevice = []string{"memtag_heap"} + variables.SanitizeDeviceDiag = []string{"memtag_heap"} + }), + ).RunTest(t) + ctx := result.TestContext checkHasMemtagNote(t, ctx.ModuleForTests("default_test", variant), Sync) checkHasMemtagNote(t, ctx.ModuleForTests("default_test_false", variant), None) diff --git a/cc/cmakelists.go b/cc/cmakelists.go index d441c57fe..04536fc56 100644 --- a/cc/cmakelists.go +++ b/cc/cmakelists.go @@ -319,6 +319,9 @@ func categorizeParameter(parameter string) parameterType { if strings.HasPrefix(parameter, "-fsanitize-blacklist") { return relativeFilePathFlag } + if strings.HasPrefix(parameter, "-fprofile-sample-use") { + return relativeFilePathFlag + } return flag } diff --git a/cc/config/x86_darwin_host.go b/cc/config/x86_darwin_host.go index 1035df35b..b0344af84 100644 --- a/cc/config/x86_darwin_host.go +++ b/cc/config/x86_darwin_host.go @@ -136,7 +136,7 @@ var macTools = &macPlatformTools{} func getMacTools(ctx android.PackageVarContext) *macPlatformTools { macTools.once.Do(func() { - xcrunTool := ctx.Config().NonHermeticHostSystemTool("xcrun") + xcrunTool := "/usr/bin/xcrun" xcrun := func(args ...string) string { if macTools.err != nil { diff --git a/cc/library.go b/cc/library.go index 0e6e10764..6a3b87693 100644 --- a/cc/library.go +++ b/cc/library.go @@ -230,6 +230,7 @@ func LibraryStaticFactory() android.Module { module, library := NewLibrary(android.HostAndDeviceSupported) library.BuildOnlyStatic() module.sdkMemberTypes = []android.SdkMemberType{staticLibrarySdkMemberType} + module.bazelHandler = &staticLibraryBazelHandler{module: module} return module.Init() } @@ -406,6 +407,49 @@ type libraryDecorator struct { collectedSnapshotHeaders android.Paths } +type staticLibraryBazelHandler struct { + bazelHandler + + module *Module +} + +func (handler *staticLibraryBazelHandler) generateBazelBuildActions(ctx android.ModuleContext, label string) bool { + bazelCtx := ctx.Config().BazelContext + outputPaths, objPaths, ok := bazelCtx.GetAllFilesAndCcObjectFiles(label, ctx.Arch().ArchType) + if ok { + if len(outputPaths) != 1 { + // TODO(cparsons): This is actually expected behavior for static libraries with no srcs. + // We should support this. + ctx.ModuleErrorf("expected exactly one output file for '%s', but got %s", label, objPaths) + return false + } + outputFilePath := android.PathForBazelOut(ctx, outputPaths[0]) + handler.module.outputFile = android.OptionalPathForPath(outputFilePath) + + objFiles := make(android.Paths, len(objPaths)) + for i, objPath := range objPaths { + objFiles[i] = android.PathForBazelOut(ctx, objPath) + } + objects := Objects{ + objFiles: objFiles, + } + + ctx.SetProvider(StaticLibraryInfoProvider, StaticLibraryInfo{ + StaticLibrary: outputFilePath, + ReuseObjects: objects, + Objects: objects, + + // TODO(cparsons): Include transitive static libraries in this provider to support + // static libraries with deps. + TransitiveStaticLibrariesForOrdering: android.NewDepSetBuilder(android.TOPOLOGICAL). + Direct(outputFilePath). + Build(), + }) + handler.module.outputFile = android.OptionalPathForPath(android.PathForBazelOut(ctx, objPaths[0])) + } + return ok +} + // collectHeadersForSnapshot collects all exported headers from library. // It globs header files in the source tree for exported include directories, // and tracks generated header files separately. diff --git a/cc/prebuilt_test.go b/cc/prebuilt_test.go index ee4de6ee8..20274b2ba 100644 --- a/cc/prebuilt_test.go +++ b/cc/prebuilt_test.go @@ -23,27 +23,16 @@ import ( "github.com/google/blueprint" ) -func testPrebuilt(t *testing.T, bp string, fs map[string][]byte, handlers ...configCustomizer) *android.TestContext { - config := TestConfig(buildDir, android.Android, nil, bp, fs) - ctx := CreateTestContext(config) - - // Enable androidmk support. - // * Register the singleton - // * Configure that we are inside make - // * Add CommonOS to ensure that androidmk processing works. - android.RegisterAndroidMkBuildComponents(ctx) - android.SetKatiEnabledForTests(config) - - for _, handler := range handlers { - handler(config) - } +var prebuiltFixtureFactory = ccFixtureFactory.Extend( + android.PrepareForTestWithAndroidMk, +) - ctx.Register() - _, errs := ctx.ParseFileList(".", []string{"Android.bp"}) - android.FailIfErrored(t, errs) - _, errs = ctx.PrepareBuildActions(config) - android.FailIfErrored(t, errs) - return ctx +func testPrebuilt(t *testing.T, bp string, fs android.MockFS, handlers ...android.FixturePreparer) *android.TestContext { + result := prebuiltFixtureFactory.Extend( + fs.AddToFixture(), + ).Extend(handlers...).RunTestWithBp(t, bp) + + return result.TestContext } type configCustomizer func(config android.Config) @@ -370,9 +359,11 @@ func TestPrebuiltLibrarySanitized(t *testing.T) { assertString(t, static2.OutputFile().Path().Base(), "libf.a") // With SANITIZE_TARGET=hwaddress - ctx = testPrebuilt(t, bp, fs, func(config android.Config) { - config.TestProductVariables.SanitizeDevice = []string{"hwaddress"} - }) + ctx = testPrebuilt(t, bp, fs, + android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { + variables.SanitizeDevice = []string{"hwaddress"} + }), + ) shared_rule = ctx.ModuleForTests("libtest", "android_arm64_armv8-a_shared_hwasan").Rule("android/soong/cc.strip") assertString(t, shared_rule.Input.String(), "hwasan/libf.so") diff --git a/cc/testing.go b/cc/testing.go index f62c5f114..6840ef4c5 100644 --- a/cc/testing.go +++ b/cc/testing.go @@ -37,7 +37,31 @@ func RegisterRequiredBuildComponentsForTest(ctx android.RegistrationContext) { } func GatherRequiredDepsForTest(oses ...android.OsType) string { - ret := ` + ret := commonDefaultModules() + + supportLinuxBionic := false + for _, os := range oses { + if os == android.Fuchsia { + ret += withFuchsiaModules() + } + if os == android.Windows { + ret += withWindowsModules() + } + if os == android.LinuxBionic { + supportLinuxBionic = true + ret += withLinuxBionic() + } + } + + if !supportLinuxBionic { + ret += withoutLinuxBionic() + } + + return ret +} + +func commonDefaultModules() string { + return ` toolchain_library { name: "libatomic", defaults: ["linux_bionic_supported"], @@ -475,23 +499,10 @@ func GatherRequiredDepsForTest(oses ...android.OsType) string { name: "note_memtag_heap_sync", } ` +} - supportLinuxBionic := false - for _, os := range oses { - if os == android.Fuchsia { - ret += ` - cc_library { - name: "libbioniccompat", - stl: "none", - } - cc_library { - name: "libcompiler_rt", - stl: "none", - } - ` - } - if os == android.Windows { - ret += ` +func withWindowsModules() string { + return ` toolchain_library { name: "libwinpthread", host_supported: true, @@ -504,10 +515,23 @@ func GatherRequiredDepsForTest(oses ...android.OsType) string { src: "", } ` +} + +func withFuchsiaModules() string { + return ` + cc_library { + name: "libbioniccompat", + stl: "none", } - if os == android.LinuxBionic { - supportLinuxBionic = true - ret += ` + cc_library { + name: "libcompiler_rt", + stl: "none", + } + ` +} + +func withLinuxBionic() string { + return ` cc_binary { name: "linker", defaults: ["linux_bionic_supported"], @@ -547,23 +571,112 @@ func GatherRequiredDepsForTest(oses ...android.OsType) string { }, } ` - } - } +} - if !supportLinuxBionic { - ret += ` +func withoutLinuxBionic() string { + return ` cc_defaults { name: "linux_bionic_supported", } ` - } - - return ret } func GatherRequiredFilesForTest(fs map[string][]byte) { } +// The directory in which cc linux bionic default modules will be defined. +// +// Placing them here ensures that their location does not conflict with default test modules +// defined by other packages. +const linuxBionicDefaultsPath = "defaults/cc/linux-bionic/Android.bp" + +// The directory in which the default cc common test modules will be defined. +// +// Placing them here ensures that their location does not conflict with default test modules +// defined by other packages. +const DefaultCcCommonTestModulesDir = "defaults/cc/common/" + +// Test fixture preparer that will register most cc build components. +// +// Singletons and mutators should only be added here if they are needed for a majority of cc +// module types, otherwise they should be added under a separate preparer to allow them to be +// selected only when needed to reduce test execution time. +// +// Module types do not have much of an overhead unless they are used so this should include as many +// module types as possible. The exceptions are those module types that require mutators and/or +// singletons in order to function in which case they should be kept together in a separate +// preparer. +var PrepareForTestWithCcBuildComponents = android.GroupFixturePreparers( + android.PrepareForTestWithAndroidBuildComponents, + android.FixtureRegisterWithContext(RegisterRequiredBuildComponentsForTest), + android.FixtureRegisterWithContext(func(ctx android.RegistrationContext) { + ctx.RegisterModuleType("cc_fuzz", FuzzFactory) + ctx.RegisterModuleType("cc_test", TestFactory) + ctx.RegisterModuleType("cc_test_library", TestLibraryFactory) + ctx.RegisterModuleType("llndk_headers", llndkHeadersFactory) + ctx.RegisterModuleType("vendor_public_library", vendorPublicLibraryFactory) + ctx.RegisterModuleType("vndk_prebuilt_shared", VndkPrebuiltSharedFactory) + + RegisterVndkLibraryTxtTypes(ctx) + }), +) + +// Preparer that will define default cc modules, e.g. standard prebuilt modules. +var PrepareForTestWithCcDefaultModules = android.GroupFixturePreparers( + PrepareForTestWithCcBuildComponents, + // Place the default cc test modules that are common to all platforms in a location that will not + // conflict with default test modules defined by other packages. + android.FixtureAddTextFile(DefaultCcCommonTestModulesDir+"Android.bp", commonDefaultModules()), + // Disable linux bionic by default. + android.FixtureAddTextFile(linuxBionicDefaultsPath, withoutLinuxBionic()), +) + +// Prepare a fixture to use all cc module types, mutators and singletons fully. +// +// This should only be used by tests that want to run with as much of the build enabled as possible. +var PrepareForIntegrationTestWithCc = android.GroupFixturePreparers( + android.PrepareForIntegrationTestWithAndroid, + genrule.PrepareForIntegrationTestWithGenrule, + PrepareForTestWithCcDefaultModules, +) + +// The preparer to include if running a cc related test for windows. +var PrepareForTestOnWindows = android.GroupFixturePreparers( + // Place the default cc test modules for windows platforms in a location that will not conflict + // with default test modules defined by other packages. + android.FixtureAddTextFile("defaults/cc/windows/Android.bp", withWindowsModules()), +) + +// The preparer to include if running a cc related test for linux bionic. +var PrepareForTestOnLinuxBionic = android.GroupFixturePreparers( + // Enable linux bionic. + android.FixtureAddTextFile(linuxBionicDefaultsPath, withLinuxBionic()), +) + +// The preparer to include if running a cc related test for fuchsia. +var PrepareForTestOnFuchsia = android.GroupFixturePreparers( + // Place the default cc test modules for fuschia in a location that will not conflict with default + // test modules defined by other packages. + android.FixtureAddTextFile("defaults/cc/fuschia/Android.bp", withFuchsiaModules()), + android.PrepareForTestSetDeviceToFuchsia, +) + +// This adds some additional modules and singletons which might negatively impact the performance +// of tests so they are not included in the PrepareForIntegrationTestWithCc. +var PrepareForTestWithCcIncludeVndk = android.GroupFixturePreparers( + PrepareForIntegrationTestWithCc, + android.FixtureRegisterWithContext(func(ctx android.RegistrationContext) { + vendorSnapshotImageSingleton.init(ctx) + recoverySnapshotImageSingleton.init(ctx) + ctx.RegisterSingletonType("vndk-snapshot", VndkSnapshotSingleton) + }), +) + +// TestConfig is the legacy way of creating a test Config for testing cc modules. +// +// See testCc for an explanation as to how to stop using this deprecated method. +// +// deprecated func TestConfig(buildDir string, os android.OsType, env map[string]string, bp string, fs map[string][]byte) android.Config { @@ -580,7 +693,7 @@ func TestConfig(buildDir string, os android.OsType, env map[string]string, var config android.Config if os == android.Fuchsia { - config = android.TestArchConfigFuchsia(buildDir, env, bp, mockFS) + panic("Fuchsia not supported use test fixture instead") } else { config = android.TestArchConfig(buildDir, env, bp, mockFS) } @@ -588,6 +701,11 @@ func TestConfig(buildDir string, os android.OsType, env map[string]string, return config } +// CreateTestContext is the legacy way of creating a TestContext for testing cc modules. +// +// See testCc for an explanation as to how to stop using this deprecated method. +// +// deprecated func CreateTestContext(config android.Config) *android.TestContext { ctx := android.NewTestArchContext(config) genrule.RegisterGenruleBuildComponents(ctx) @@ -598,13 +716,15 @@ func CreateTestContext(config android.Config) *android.TestContext { ctx.RegisterModuleType("vendor_public_library", vendorPublicLibraryFactory) ctx.RegisterModuleType("filegroup", android.FileGroupFactory) ctx.RegisterModuleType("vndk_prebuilt_shared", VndkPrebuiltSharedFactory) + vendorSnapshotImageSingleton.init(ctx) recoverySnapshotImageSingleton.init(ctx) + ctx.RegisterSingletonType("vndk-snapshot", VndkSnapshotSingleton) RegisterVndkLibraryTxtTypes(ctx) + ctx.PreArchMutators(android.RegisterDefaultsPreArchMutators) android.RegisterPrebuiltMutators(ctx) RegisterRequiredBuildComponentsForTest(ctx) - ctx.RegisterSingletonType("vndk-snapshot", VndkSnapshotSingleton) return ctx } diff --git a/cmd/soong_build/main.go b/cmd/soong_build/main.go index d022f4993..4586f44a6 100644 --- a/cmd/soong_build/main.go +++ b/cmd/soong_build/main.go @@ -43,7 +43,7 @@ func init() { flag.StringVar(&delveListen, "delve_listen", "", "Delve port to listen on for debugging") flag.StringVar(&delvePath, "delve_path", "", "Path to Delve. Only used if --delve_listen is set") flag.StringVar(&docFile, "soong_docs", "", "build documentation file to output") - flag.StringVar(&bazelQueryViewDir, "bazel_queryview_dir", "", "path to the bazel queryview directory") + flag.StringVar(&bazelQueryViewDir, "bazel_queryview_dir", "", "path to the bazel queryview directory relative to --top") } func newNameResolver(config android.Config) *android.NameResolver { @@ -150,7 +150,8 @@ func main() { if bazelQueryViewDir != "" { // Run the code-generation phase to convert BazelTargetModules to BUILD files. codegenContext := bp2build.NewCodegenContext(configuration, *ctx, bp2build.QueryView) - if err := createBazelQueryView(codegenContext, bazelQueryViewDir); err != nil { + absoluteQueryViewDir := shared.JoinPath(topDir, bazelQueryViewDir) + if err := createBazelQueryView(codegenContext, absoluteQueryViewDir); err != nil { fmt.Fprintf(os.Stderr, "%s", err) os.Exit(1) } diff --git a/dexpreopt/testing.go b/dexpreopt/testing.go index bccbfc1e5..8e90295b1 100644 --- a/dexpreopt/testing.go +++ b/dexpreopt/testing.go @@ -45,3 +45,36 @@ func BpToolModulesForTest() string { } ` } + +// Prepares a test fixture by enabling dexpreopt. +var PrepareForTestWithDexpreopt = FixtureModifyGlobalConfig(func(*GlobalConfig) {}) + +// FixtureModifyGlobalConfig enables dexpreopt (unless modified by the mutator) and modifies the +// configuration. +func FixtureModifyGlobalConfig(configModifier func(dexpreoptConfig *GlobalConfig)) android.FixturePreparer { + return android.FixtureModifyConfig(func(config android.Config) { + // Initialize the dexpreopt GlobalConfig to an empty structure. This has no effect if it has + // already been set. + pathCtx := android.PathContextForTesting(config) + dexpreoptConfig := GlobalConfigForTests(pathCtx) + SetTestGlobalConfig(config, dexpreoptConfig) + + // Retrieve the existing configuration and modify it. + dexpreoptConfig = GetGlobalConfig(pathCtx) + configModifier(dexpreoptConfig) + }) +} + +// FixtureSetArtBootJars enables dexpreopt and sets the ArtApexJars property. +func FixtureSetArtBootJars(bootJars ...string) android.FixturePreparer { + return FixtureModifyGlobalConfig(func(dexpreoptConfig *GlobalConfig) { + dexpreoptConfig.ArtApexJars = android.CreateTestConfiguredJarList(bootJars) + }) +} + +// FixtureSetBootJars enables dexpreopt and sets the BootJars property. +func FixtureSetBootJars(bootJars ...string) android.FixturePreparer { + return FixtureModifyGlobalConfig(func(dexpreoptConfig *GlobalConfig) { + dexpreoptConfig.BootJars = android.CreateTestConfiguredJarList(bootJars) + }) +} diff --git a/etc/prebuilt_etc.go b/etc/prebuilt_etc.go index b07ad9115..6291325f4 100644 --- a/etc/prebuilt_etc.go +++ b/etc/prebuilt_etc.go @@ -54,6 +54,8 @@ func RegisterPrebuiltEtcBuildComponents(ctx android.RegistrationContext) { ctx.RegisterModuleType("prebuilt_dsp", PrebuiltDSPFactory) } +var PrepareForTestWithPrebuiltEtc = android.FixtureRegisterWithContext(RegisterPrebuiltEtcBuildComponents) + type prebuiltEtcProperties struct { // Source file of this prebuilt. Can reference a genrule type module with the ":module" syntax. Src *string `android:"path,arch_variant"` diff --git a/etc/prebuilt_etc_test.go b/etc/prebuilt_etc_test.go index 585760d47..6727e59e4 100644 --- a/etc/prebuilt_etc_test.go +++ b/etc/prebuilt_etc_test.go @@ -18,7 +18,6 @@ import ( "io/ioutil" "os" "path/filepath" - "reflect" "testing" "android/soong/android" @@ -49,60 +48,19 @@ func TestMain(m *testing.M) { os.Exit(run()) } -func testPrebuiltEtcContext(t *testing.T, bp string) (*android.TestContext, android.Config) { - fs := map[string][]byte{ +var prebuiltEtcFixtureFactory = android.NewFixtureFactory( + &buildDir, + android.PrepareForTestWithArchMutator, + PrepareForTestWithPrebuiltEtc, + android.FixtureMergeMockFs(android.MockFS{ "foo.conf": nil, "bar.conf": nil, "baz.conf": nil, - } - - config := android.TestArchConfig(buildDir, nil, bp, fs) - - ctx := android.NewTestArchContext(config) - ctx.RegisterModuleType("prebuilt_etc", PrebuiltEtcFactory) - ctx.RegisterModuleType("prebuilt_etc_host", PrebuiltEtcHostFactory) - ctx.RegisterModuleType("prebuilt_usr_share", PrebuiltUserShareFactory) - ctx.RegisterModuleType("prebuilt_usr_share_host", PrebuiltUserShareHostFactory) - ctx.RegisterModuleType("prebuilt_font", PrebuiltFontFactory) - ctx.RegisterModuleType("prebuilt_firmware", PrebuiltFirmwareFactory) - ctx.RegisterModuleType("prebuilt_dsp", PrebuiltDSPFactory) - ctx.Register() - - return ctx, config -} - -func testPrebuiltEtc(t *testing.T, bp string) (*android.TestContext, android.Config) { - t.Helper() - - ctx, config := testPrebuiltEtcContext(t, bp) - _, errs := ctx.ParseFileList(".", []string{"Android.bp"}) - android.FailIfErrored(t, errs) - _, errs = ctx.PrepareBuildActions(config) - android.FailIfErrored(t, errs) - - return ctx, config -} - -func testPrebuiltEtcError(t *testing.T, pattern, bp string) { - t.Helper() - - ctx, config := testPrebuiltEtcContext(t, bp) - _, errs := ctx.ParseFileList(".", []string{"Android.bp"}) - if len(errs) > 0 { - android.FailIfNoMatchingErrors(t, pattern, errs) - return - } - - _, errs = ctx.PrepareBuildActions(config) - if len(errs) > 0 { - android.FailIfNoMatchingErrors(t, pattern, errs) - return - } + }), +) - t.Fatalf("missing expected error %q (0 errors are returned)", pattern) -} func TestPrebuiltEtcVariants(t *testing.T) { - ctx, _ := testPrebuiltEtc(t, ` + result := prebuiltEtcFixtureFactory.RunTestWithBp(t, ` prebuilt_etc { name: "foo.conf", src: "foo.conf", @@ -119,24 +77,24 @@ func TestPrebuiltEtcVariants(t *testing.T) { } `) - foo_variants := ctx.ModuleVariantsForTests("foo.conf") + foo_variants := result.ModuleVariantsForTests("foo.conf") if len(foo_variants) != 1 { t.Errorf("expected 1, got %#v", foo_variants) } - bar_variants := ctx.ModuleVariantsForTests("bar.conf") + bar_variants := result.ModuleVariantsForTests("bar.conf") if len(bar_variants) != 2 { t.Errorf("expected 2, got %#v", bar_variants) } - baz_variants := ctx.ModuleVariantsForTests("baz.conf") + baz_variants := result.ModuleVariantsForTests("baz.conf") if len(baz_variants) != 1 { t.Errorf("expected 1, got %#v", bar_variants) } } func TestPrebuiltEtcOutputPath(t *testing.T) { - ctx, _ := testPrebuiltEtc(t, ` + result := prebuiltEtcFixtureFactory.RunTestWithBp(t, ` prebuilt_etc { name: "foo.conf", src: "foo.conf", @@ -144,14 +102,12 @@ func TestPrebuiltEtcOutputPath(t *testing.T) { } `) - p := ctx.ModuleForTests("foo.conf", "android_arm64_armv8-a").Module().(*PrebuiltEtc) - if p.outputFilePath.Base() != "foo.installed.conf" { - t.Errorf("expected foo.installed.conf, got %q", p.outputFilePath.Base()) - } + p := result.Module("foo.conf", "android_arm64_armv8-a").(*PrebuiltEtc) + result.AssertStringEquals("output file path", "foo.installed.conf", p.outputFilePath.Base()) } func TestPrebuiltEtcGlob(t *testing.T) { - ctx, _ := testPrebuiltEtc(t, ` + result := prebuiltEtcFixtureFactory.RunTestWithBp(t, ` prebuilt_etc { name: "my_foo", src: "foo.*", @@ -163,19 +119,15 @@ func TestPrebuiltEtcGlob(t *testing.T) { } `) - p := ctx.ModuleForTests("my_foo", "android_arm64_armv8-a").Module().(*PrebuiltEtc) - if p.outputFilePath.Base() != "my_foo" { - t.Errorf("expected my_foo, got %q", p.outputFilePath.Base()) - } + p := result.Module("my_foo", "android_arm64_armv8-a").(*PrebuiltEtc) + result.AssertStringEquals("my_foo output file path", "my_foo", p.outputFilePath.Base()) - p = ctx.ModuleForTests("my_bar", "android_arm64_armv8-a").Module().(*PrebuiltEtc) - if p.outputFilePath.Base() != "bar.conf" { - t.Errorf("expected bar.conf, got %q", p.outputFilePath.Base()) - } + p = result.Module("my_bar", "android_arm64_armv8-a").(*PrebuiltEtc) + result.AssertStringEquals("my_bar output file path", "bar.conf", p.outputFilePath.Base()) } func TestPrebuiltEtcAndroidMk(t *testing.T) { - ctx, _ := testPrebuiltEtc(t, ` + result := prebuiltEtcFixtureFactory.RunTestWithBp(t, ` prebuilt_etc { name: "foo", src: "foo.conf", @@ -197,13 +149,11 @@ func TestPrebuiltEtcAndroidMk(t *testing.T) { "LOCAL_TARGET_REQUIRED_MODULES": {"targetModA"}, } - mod := ctx.ModuleForTests("foo", "android_arm64_armv8-a").Module().(*PrebuiltEtc) - entries := android.AndroidMkEntriesForTest(t, ctx, mod)[0] + mod := result.Module("foo", "android_arm64_armv8-a").(*PrebuiltEtc) + entries := android.AndroidMkEntriesForTest(t, result.TestContext, mod)[0] for k, expectedValue := range expected { if value, ok := entries.EntryMap[k]; ok { - if !reflect.DeepEqual(value, expectedValue) { - t.Errorf("Incorrect %s '%s', expected '%s'", k, value, expectedValue) - } + result.AssertDeepEquals(k, expectedValue, value) } else { t.Errorf("No %s defined, saw %q", k, entries.EntryMap) } @@ -211,7 +161,7 @@ func TestPrebuiltEtcAndroidMk(t *testing.T) { } func TestPrebuiltEtcRelativeInstallPathInstallDirPath(t *testing.T) { - ctx, _ := testPrebuiltEtc(t, ` + result := prebuiltEtcFixtureFactory.RunTestWithBp(t, ` prebuilt_etc { name: "foo.conf", src: "foo.conf", @@ -219,26 +169,26 @@ func TestPrebuiltEtcRelativeInstallPathInstallDirPath(t *testing.T) { } `) - p := ctx.ModuleForTests("foo.conf", "android_arm64_armv8-a").Module().(*PrebuiltEtc) + p := result.Module("foo.conf", "android_arm64_armv8-a").(*PrebuiltEtc) expected := buildDir + "/target/product/test_device/system/etc/bar" - if p.installDirPath.String() != expected { - t.Errorf("expected %q, got %q", expected, p.installDirPath.String()) - } + result.AssertStringEquals("install dir", expected, p.installDirPath.String()) } func TestPrebuiltEtcCannotSetRelativeInstallPathAndSubDir(t *testing.T) { - testPrebuiltEtcError(t, "relative_install_path is set. Cannot set sub_dir", ` - prebuilt_etc { - name: "foo.conf", - src: "foo.conf", - sub_dir: "bar", - relative_install_path: "bar", - } - `) + prebuiltEtcFixtureFactory. + ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern("relative_install_path is set. Cannot set sub_dir")). + RunTestWithBp(t, ` + prebuilt_etc { + name: "foo.conf", + src: "foo.conf", + sub_dir: "bar", + relative_install_path: "bar", + } + `) } func TestPrebuiltEtcHost(t *testing.T) { - ctx, _ := testPrebuiltEtc(t, ` + result := prebuiltEtcFixtureFactory.RunTestWithBp(t, ` prebuilt_etc_host { name: "foo.conf", src: "foo.conf", @@ -246,14 +196,14 @@ func TestPrebuiltEtcHost(t *testing.T) { `) buildOS := android.BuildOs.String() - p := ctx.ModuleForTests("foo.conf", buildOS+"_common").Module().(*PrebuiltEtc) + p := result.Module("foo.conf", buildOS+"_common").(*PrebuiltEtc) if !p.Host() { t.Errorf("host bit is not set for a prebuilt_etc_host module.") } } func TestPrebuiltUserShareInstallDirPath(t *testing.T) { - ctx, _ := testPrebuiltEtc(t, ` + result := prebuiltEtcFixtureFactory.RunTestWithBp(t, ` prebuilt_usr_share { name: "foo.conf", src: "foo.conf", @@ -261,15 +211,13 @@ func TestPrebuiltUserShareInstallDirPath(t *testing.T) { } `) - p := ctx.ModuleForTests("foo.conf", "android_arm64_armv8-a").Module().(*PrebuiltEtc) + p := result.Module("foo.conf", "android_arm64_armv8-a").(*PrebuiltEtc) expected := buildDir + "/target/product/test_device/system/usr/share/bar" - if p.installDirPath.String() != expected { - t.Errorf("expected %q, got %q", expected, p.installDirPath.String()) - } + result.AssertStringEquals("install dir", expected, p.installDirPath.String()) } func TestPrebuiltUserShareHostInstallDirPath(t *testing.T) { - ctx, config := testPrebuiltEtc(t, ` + result := prebuiltEtcFixtureFactory.RunTestWithBp(t, ` prebuilt_usr_share_host { name: "foo.conf", src: "foo.conf", @@ -278,26 +226,22 @@ func TestPrebuiltUserShareHostInstallDirPath(t *testing.T) { `) buildOS := android.BuildOs.String() - p := ctx.ModuleForTests("foo.conf", buildOS+"_common").Module().(*PrebuiltEtc) - expected := filepath.Join(buildDir, "host", config.PrebuiltOS(), "usr", "share", "bar") - if p.installDirPath.String() != expected { - t.Errorf("expected %q, got %q", expected, p.installDirPath.String()) - } + p := result.Module("foo.conf", buildOS+"_common").(*PrebuiltEtc) + expected := filepath.Join(buildDir, "host", result.Config.PrebuiltOS(), "usr", "share", "bar") + result.AssertStringEquals("install dir", expected, p.installDirPath.String()) } func TestPrebuiltFontInstallDirPath(t *testing.T) { - ctx, _ := testPrebuiltEtc(t, ` + result := prebuiltEtcFixtureFactory.RunTestWithBp(t, ` prebuilt_font { name: "foo.conf", src: "foo.conf", } `) - p := ctx.ModuleForTests("foo.conf", "android_arm64_armv8-a").Module().(*PrebuiltEtc) + p := result.Module("foo.conf", "android_arm64_armv8-a").(*PrebuiltEtc) expected := buildDir + "/target/product/test_device/system/fonts" - if p.installDirPath.String() != expected { - t.Errorf("expected %q, got %q", expected, p.installDirPath.String()) - } + result.AssertStringEquals("install dir", expected, p.installDirPath.String()) } func TestPrebuiltFirmwareDirPath(t *testing.T) { @@ -327,11 +271,9 @@ func TestPrebuiltFirmwareDirPath(t *testing.T) { }} for _, tt := range tests { t.Run(tt.description, func(t *testing.T) { - ctx, _ := testPrebuiltEtc(t, tt.config) - p := ctx.ModuleForTests("foo.conf", "android_arm64_armv8-a").Module().(*PrebuiltEtc) - if p.installDirPath.String() != tt.expectedPath { - t.Errorf("expected %q, got %q", tt.expectedPath, p.installDirPath) - } + result := prebuiltEtcFixtureFactory.RunTestWithBp(t, tt.config) + p := result.Module("foo.conf", "android_arm64_armv8-a").(*PrebuiltEtc) + result.AssertStringEquals("install dir", tt.expectedPath, p.installDirPath.String()) }) } } @@ -363,11 +305,9 @@ func TestPrebuiltDSPDirPath(t *testing.T) { }} for _, tt := range tests { t.Run(tt.description, func(t *testing.T) { - ctx, _ := testPrebuiltEtc(t, tt.config) - p := ctx.ModuleForTests("foo.conf", "android_arm64_armv8-a").Module().(*PrebuiltEtc) - if p.installDirPath.String() != tt.expectedPath { - t.Errorf("expected %q, got %q", tt.expectedPath, p.installDirPath) - } + result := prebuiltEtcFixtureFactory.RunTestWithBp(t, tt.config) + p := result.Module("foo.conf", "android_arm64_armv8-a").(*PrebuiltEtc) + result.AssertStringEquals("install dir", tt.expectedPath, p.installDirPath.String()) }) } } diff --git a/genrule/genrule.go b/genrule/genrule.go index 50c77cf9a..53499068c 100644 --- a/genrule/genrule.go +++ b/genrule/genrule.go @@ -37,6 +37,27 @@ func init() { RegisterGenruleBuildComponents(android.InitRegistrationContext) } +// Test fixture preparer that will register most genrule build components. +// +// Singletons and mutators should only be added here if they are needed for a majority of genrule +// module types, otherwise they should be added under a separate preparer to allow them to be +// selected only when needed to reduce test execution time. +// +// Module types do not have much of an overhead unless they are used so this should include as many +// module types as possible. The exceptions are those module types that require mutators and/or +// singletons in order to function in which case they should be kept together in a separate +// preparer. +var PrepareForTestWithGenRuleBuildComponents = android.GroupFixturePreparers( + android.FixtureRegisterWithContext(RegisterGenruleBuildComponents), +) + +// Prepare a fixture to use all genrule module types, mutators and singletons fully. +// +// This should only be used by tests that want to run with as much of the build enabled as possible. +var PrepareForIntegrationTestWithGenrule = android.GroupFixturePreparers( + PrepareForTestWithGenRuleBuildComponents, +) + func RegisterGenruleBuildComponents(ctx android.RegistrationContext) { ctx.RegisterModuleType("genrule_defaults", defaultsFactory) diff --git a/genrule/genrule_test.go b/genrule/genrule_test.go index 2f5605e94..0873704ba 100644 --- a/genrule/genrule_test.go +++ b/genrule/genrule_test.go @@ -17,8 +17,7 @@ package genrule import ( "io/ioutil" "os" - "reflect" - "strings" + "regexp" "testing" "android/soong/android" @@ -51,22 +50,30 @@ func TestMain(m *testing.M) { os.Exit(run()) } -func testContext(config android.Config) *android.TestContext { - - ctx := android.NewTestArchContext(config) - ctx.RegisterModuleType("filegroup", android.FileGroupFactory) - ctx.RegisterModuleType("tool", toolFactory) - - RegisterGenruleBuildComponents(ctx) - - ctx.PreArchMutators(android.RegisterDefaultsPreArchMutators) - ctx.Register() - - return ctx -} +var genruleFixtureFactory = android.NewFixtureFactory( + &buildDir, + android.PrepareForTestWithArchMutator, + android.PrepareForTestWithDefaults, + + android.PrepareForTestWithFilegroup, + PrepareForTestWithGenRuleBuildComponents, + android.FixtureRegisterWithContext(func(ctx android.RegistrationContext) { + ctx.RegisterModuleType("tool", toolFactory) + }), + android.FixtureMergeMockFs(android.MockFS{ + "tool": nil, + "tool_file1": nil, + "tool_file2": nil, + "in1": nil, + "in2": nil, + "in1.txt": nil, + "in2.txt": nil, + "in3.txt": nil, + }), +) -func testConfig(bp string, fs map[string][]byte) android.Config { - bp += ` +func testGenruleBp() string { + return ` tool { name: "tool", } @@ -105,23 +112,6 @@ func testConfig(bp string, fs map[string][]byte) android.Config { name: "empty", } ` - - mockFS := map[string][]byte{ - "tool": nil, - "tool_file1": nil, - "tool_file2": nil, - "in1": nil, - "in2": nil, - "in1.txt": nil, - "in2.txt": nil, - "in3.txt": nil, - } - - for k, v := range fs { - mockFS[k] = v - } - - return android.TestArchConfig(buildDir, nil, bp, mockFS) } func TestGenruleCmd(t *testing.T) { @@ -466,38 +456,28 @@ func TestGenruleCmd(t *testing.T) { bp += test.prop bp += "}\n" - config := testConfig(bp, nil) - config.TestProductVariables.Allow_missing_dependencies = proptools.BoolPtr(test.allowMissingDependencies) - - ctx := testContext(config) - ctx.SetAllowMissingDependencies(test.allowMissingDependencies) - - _, errs := ctx.ParseFileList(".", []string{"Android.bp"}) - if errs == nil { - _, errs = ctx.PrepareBuildActions(config) + var expectedErrors []string + if test.err != "" { + expectedErrors = append(expectedErrors, regexp.QuoteMeta(test.err)) } - if errs == nil && test.err != "" { - t.Fatalf("want error %q, got no error", test.err) - } else if errs != nil && test.err == "" { - android.FailIfErrored(t, errs) - } else if test.err != "" { - if len(errs) != 1 { - t.Errorf("want 1 error, got %d errors:", len(errs)) - for _, err := range errs { - t.Errorf(" %s", err.Error()) - } - t.FailNow() - } - if !strings.Contains(errs[0].Error(), test.err) { - t.Fatalf("want %q, got %q", test.err, errs[0].Error()) - } + + result := genruleFixtureFactory.Extend( + android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { + variables.Allow_missing_dependencies = proptools.BoolPtr(test.allowMissingDependencies) + }), + android.FixtureModifyContext(func(ctx *android.TestContext) { + ctx.SetAllowMissingDependencies(test.allowMissingDependencies) + }), + ). + ExtendWithErrorHandler(android.FixtureExpectsAllErrorsToMatchAPattern(expectedErrors)). + RunTestWithBp(t, testGenruleBp()+bp) + + if expectedErrors != nil { return } - gen := ctx.ModuleForTests("gen", "").Module().(*Module) - if g, w := gen.rawCommands[0], test.expect; w != g { - t.Errorf("want %q, got %q", w, g) - } + gen := result.Module("gen", "").(*Module) + result.AssertStringEquals("raw commands", test.expect, gen.rawCommands[0]) }) } } @@ -557,25 +537,16 @@ func TestGenruleHashInputs(t *testing.T) { }, } - config := testConfig(bp, nil) - ctx := testContext(config) - _, errs := ctx.ParseFileList(".", []string{"Android.bp"}) - if errs == nil { - _, errs = ctx.PrepareBuildActions(config) - } - if errs != nil { - t.Fatal(errs) - } + result := genruleFixtureFactory.RunTestWithBp(t, testGenruleBp()+bp) for _, test := range testcases { t.Run(test.name, func(t *testing.T) { - gen := ctx.ModuleForTests(test.name, "") + subResult := result.ResultForSubTest(t) + gen := subResult.ModuleForTests(test.name, "") manifest := android.RuleBuilderSboxProtoForTests(t, gen.Output("genrule.sbox.textproto")) hash := manifest.Commands[0].GetInputHash() - if g, w := hash, test.expectedHash; g != w { - t.Errorf("Expected has %q, got %q", w, g) - } + subResult.AssertStringEquals("hash", test.expectedHash, hash) }) } } @@ -630,46 +601,27 @@ func TestGenSrcs(t *testing.T) { bp += test.prop bp += "}\n" - config := testConfig(bp, nil) - ctx := testContext(config) - - _, errs := ctx.ParseFileList(".", []string{"Android.bp"}) - if errs == nil { - _, errs = ctx.PrepareBuildActions(config) + var expectedErrors []string + if test.err != "" { + expectedErrors = append(expectedErrors, regexp.QuoteMeta(test.err)) } - if errs == nil && test.err != "" { - t.Fatalf("want error %q, got no error", test.err) - } else if errs != nil && test.err == "" { - android.FailIfErrored(t, errs) - } else if test.err != "" { - if len(errs) != 1 { - t.Errorf("want 1 error, got %d errors:", len(errs)) - for _, err := range errs { - t.Errorf(" %s", err.Error()) - } - t.FailNow() - } - if !strings.Contains(errs[0].Error(), test.err) { - t.Fatalf("want %q, got %q", test.err, errs[0].Error()) - } + + result := genruleFixtureFactory. + ExtendWithErrorHandler(android.FixtureExpectsAllErrorsToMatchAPattern(expectedErrors)). + RunTestWithBp(t, testGenruleBp()+bp) + + if expectedErrors != nil { return } - gen := ctx.ModuleForTests("gen", "").Module().(*Module) - if g, w := gen.rawCommands, test.cmds; !reflect.DeepEqual(w, g) { - t.Errorf("want %q, got %q", w, g) - } + gen := result.Module("gen", "").(*Module) + result.AssertDeepEquals("cmd", test.cmds, gen.rawCommands) - if g, w := gen.outputDeps.Strings(), test.deps; !reflect.DeepEqual(w, g) { - t.Errorf("want deps %q, got %q", w, g) - } + result.AssertDeepEquals("deps", test.deps, gen.outputDeps.Strings()) - if g, w := gen.outputFiles.Strings(), test.files; !reflect.DeepEqual(w, g) { - t.Errorf("want files %q, got %q", w, g) - } + result.AssertDeepEquals("files", test.files, gen.outputFiles.Strings()) }) } - } func TestGenruleDefaults(t *testing.T) { @@ -690,26 +642,16 @@ func TestGenruleDefaults(t *testing.T) { defaults: ["gen_defaults1", "gen_defaults2"], } ` - config := testConfig(bp, nil) - ctx := testContext(config) - _, errs := ctx.ParseFileList(".", []string{"Android.bp"}) - if errs == nil { - _, errs = ctx.PrepareBuildActions(config) - } - if errs != nil { - t.Fatal(errs) - } - gen := ctx.ModuleForTests("gen", "").Module().(*Module) + + result := genruleFixtureFactory.RunTestWithBp(t, testGenruleBp()+bp) + + gen := result.Module("gen", "").(*Module) expectedCmd := "cp in1 __SBOX_SANDBOX_DIR__/out/out" - if gen.rawCommands[0] != expectedCmd { - t.Errorf("Expected cmd: %q, actual: %q", expectedCmd, gen.rawCommands[0]) - } + result.AssertStringEquals("cmd", expectedCmd, gen.rawCommands[0]) expectedSrcs := []string{"in1"} - if !reflect.DeepEqual(expectedSrcs, gen.properties.Srcs) { - t.Errorf("Expected srcs: %q, actual: %q", expectedSrcs, gen.properties.Srcs) - } + result.AssertDeepEquals("srcs", expectedSrcs, gen.properties.Srcs) } func TestGenruleWithBazel(t *testing.T) { @@ -721,29 +663,18 @@ func TestGenruleWithBazel(t *testing.T) { } ` - config := testConfig(bp, nil) - config.BazelContext = android.MockBazelContext{ - AllFiles: map[string][]string{ - "//foo/bar:bar": []string{"bazelone.txt", "bazeltwo.txt"}}} + result := genruleFixtureFactory.Extend(android.FixtureModifyConfig(func(config android.Config) { + config.BazelContext = android.MockBazelContext{ + AllFiles: map[string][]string{ + "//foo/bar:bar": []string{"bazelone.txt", "bazeltwo.txt"}}} + })).RunTestWithBp(t, testGenruleBp()+bp) - ctx := testContext(config) - _, errs := ctx.ParseFileList(".", []string{"Android.bp"}) - if errs == nil { - _, errs = ctx.PrepareBuildActions(config) - } - if errs != nil { - t.Fatal(errs) - } - gen := ctx.ModuleForTests("foo", "").Module().(*Module) + gen := result.Module("foo", "").(*Module) expectedOutputFiles := []string{"outputbase/execroot/__main__/bazelone.txt", "outputbase/execroot/__main__/bazeltwo.txt"} - if !reflect.DeepEqual(gen.outputFiles.Strings(), expectedOutputFiles) { - t.Errorf("Expected output files: %q, actual: %q", expectedOutputFiles, gen.outputFiles) - } - if !reflect.DeepEqual(gen.outputDeps.Strings(), expectedOutputFiles) { - t.Errorf("Expected output deps: %q, actual: %q", expectedOutputFiles, gen.outputDeps) - } + result.AssertDeepEquals("output files", expectedOutputFiles, gen.outputFiles.Strings()) + result.AssertDeepEquals("output deps", expectedOutputFiles, gen.outputDeps.Strings()) } type testTool struct { diff --git a/java/Android.bp b/java/Android.bp index 461b16d58..9e2db8314 100644 --- a/java/Android.bp +++ b/java/Android.bp @@ -78,6 +78,7 @@ bootstrap_go_package { "plugin_test.go", "rro_test.go", "sdk_test.go", + "system_modules_test.go", ], pluginFor: ["soong_build"], } diff --git a/java/app.go b/java/app.go index 2d918e942..e98fe3114 100755 --- a/java/app.go +++ b/java/app.go @@ -122,8 +122,8 @@ type overridableAppProperties struct { // or an android_app_certificate module name in the form ":module". Certificate *string - // Name of the signing certificate lineage file. - Lineage *string + // Name of the signing certificate lineage file or filegroup module. + Lineage *string `android:"path"` // the package name of this app. The package name in the manifest file is used if one was not given. Package_name *string @@ -1280,6 +1280,14 @@ func (u *usesLibrary) verifyUsesLibrariesManifest(ctx android.ModuleContext, man outputFile := android.PathForModuleOut(ctx, "manifest_check", "AndroidManifest.xml") statusFile := dexpreopt.UsesLibrariesStatusFile(ctx) + // Disable verify_uses_libraries check if dexpreopt is globally disabled. Without dexpreopt the + // check is not necessary, and although it is good to have, it is difficult to maintain on + // non-linux build platforms where dexpreopt is generally disabled (the check may fail due to + // various unrelated reasons, such as a failure to get manifest from an APK). + if dexpreopt.GetGlobalConfig(ctx).DisablePreopt { + return manifest + } + rule := android.NewRuleBuilder(pctx, ctx) cmd := rule.Command().BuiltTool("manifest_check"). Flag("--enforce-uses-libraries"). @@ -1310,6 +1318,14 @@ func (u *usesLibrary) verifyUsesLibrariesAPK(ctx android.ModuleContext, apk andr outputFile := android.PathForModuleOut(ctx, "verify_uses_libraries", apk.Base()) statusFile := dexpreopt.UsesLibrariesStatusFile(ctx) + // Disable verify_uses_libraries check if dexpreopt is globally disabled. Without dexpreopt the + // check is not necessary, and although it is good to have, it is difficult to maintain on + // non-linux build platforms where dexpreopt is generally disabled (the check may fail due to + // various unrelated reasons, such as a failure to get manifest from an APK). + if dexpreopt.GetGlobalConfig(ctx).DisablePreopt { + return apk + } + rule := android.NewRuleBuilder(pctx, ctx) aapt := ctx.Config().HostToolPath(ctx, "aapt") rule.Command(). diff --git a/java/app_import.go b/java/app_import.go index d69dd10f9..d4da64da5 100644 --- a/java/app_import.go +++ b/java/app_import.go @@ -67,12 +67,15 @@ type AndroidAppImportProperties struct { // module name in the form ":module". Should be empty if presigned or default_dev_cert is set. Certificate *string + // Names of extra android_app_certificate modules to sign the apk with in the form ":module". + Additional_certificates []string + // Set this flag to true if the prebuilt apk is already signed. The certificate property must not // be set for presigned modules. Presigned *bool - // Name of the signing certificate lineage file. - Lineage *string + // Name of the signing certificate lineage file or filegroup module. + Lineage *string `android:"path"` // Sign with the default system dev certificate. Must be used judiciously. Most imported apps // need to either specify a specific certificate or be presigned. @@ -156,6 +159,16 @@ func (a *AndroidAppImport) DepsMutator(ctx android.BottomUpMutatorContext) { ctx.AddDependency(ctx.Module(), certificateTag, cert) } + for _, cert := range a.properties.Additional_certificates { + cert = android.SrcIsModule(cert) + if cert != "" { + ctx.AddDependency(ctx.Module(), certificateTag, cert) + } else { + ctx.PropertyErrorf("additional_certificates", + `must be names of android_app_certificate modules in the form ":module"`) + } + } + a.usesLibrary.deps(ctx, !a.isPrebuiltFrameworkRes()) } @@ -303,9 +316,6 @@ func (a *AndroidAppImport) generateAndroidBuildActions(ctx android.ModuleContext // If the certificate property is empty at this point, default_dev_cert must be set to true. // Which makes processMainCert's behavior for the empty cert string WAI. certificates = processMainCert(a.ModuleBase, String(a.properties.Certificate), certificates, ctx) - if len(certificates) != 1 { - ctx.ModuleErrorf("Unexpected number of certificates were extracted: %q", certificates) - } a.certificate = certificates[0] signed := android.PathForModuleOut(ctx, "signed", apkFilename) var lineageFile android.Path diff --git a/java/app_import_test.go b/java/app_import_test.go index dc31d07c9..cae41d0e7 100644 --- a/java/app_import_test.go +++ b/java/app_import_test.go @@ -109,14 +109,54 @@ func TestAndroidAppImport_SigningLineage(t *testing.T) { name: "foo", apk: "prebuilts/apk/app.apk", certificate: "platform", + additional_certificates: [":additional_certificate"], lineage: "lineage.bin", } + + android_app_certificate { + name: "additional_certificate", + certificate: "cert/additional_cert", + } `) variant := ctx.ModuleForTests("foo", "android_common") + signedApk := variant.Output("signed/foo.apk") + // Check certificates + certificatesFlag := signedApk.Args["certificates"] + expected := "build/make/target/product/security/platform.x509.pem " + + "build/make/target/product/security/platform.pk8 " + + "cert/additional_cert.x509.pem cert/additional_cert.pk8" + if expected != certificatesFlag { + t.Errorf("Incorrect certificates flags, expected: %q, got: %q", expected, certificatesFlag) + } // Check cert signing lineage flag. + signingFlag := signedApk.Args["flags"] + expected = "--lineage lineage.bin" + if expected != signingFlag { + t.Errorf("Incorrect signing flags, expected: %q, got: %q", expected, signingFlag) + } +} + +func TestAndroidAppImport_SigningLineageFilegroup(t *testing.T) { + ctx, _ := testJava(t, ` + android_app_import { + name: "foo", + apk: "prebuilts/apk/app.apk", + certificate: "platform", + lineage: ":lineage_bin", + } + + filegroup { + name: "lineage_bin", + srcs: ["lineage.bin"], + } + `) + + variant := ctx.ModuleForTests("foo", "android_common") + signedApk := variant.Output("signed/foo.apk") + // Check cert signing lineage flag. signingFlag := signedApk.Args["flags"] expected := "--lineage lineage.bin" if expected != signingFlag { diff --git a/java/app_test.go b/java/app_test.go index f41047aa6..78e1a57a9 100644 --- a/java/app_test.go +++ b/java/app_test.go @@ -1576,6 +1576,31 @@ func TestCertificates(t *testing.T) { expectedLineage: "--lineage lineage.bin", expectedCertificate: "cert/new_cert.x509.pem cert/new_cert.pk8", }, + { + name: "lineage from filegroup", + bp: ` + android_app { + name: "foo", + srcs: ["a.java"], + certificate: ":new_certificate", + lineage: ":lineage_bin", + sdk_version: "current", + } + + android_app_certificate { + name: "new_certificate", + certificate: "cert/new_cert", + } + + filegroup { + name: "lineage_bin", + srcs: ["lineage.bin"], + } + `, + certificateOverride: "", + expectedLineage: "--lineage lineage.bin", + expectedCertificate: "cert/new_cert.x509.pem cert/new_cert.pk8", + }, } for _, test := range testCases { diff --git a/java/droiddoc.go b/java/droiddoc.go index 8f1644c7f..f0decec74 100644 --- a/java/droiddoc.go +++ b/java/droiddoc.go @@ -1203,8 +1203,14 @@ func (d *Droidstubs) apiLevelsAnnotationsFlags(ctx android.ModuleContext, cmd *a } func metalavaCmd(ctx android.ModuleContext, rule *android.RuleBuilder, javaVersion javaVersion, srcs android.Paths, - srcJarList android.Path, bootclasspath, classpath classpath, sourcepaths android.Paths, implicitsRsp android.WritablePath, sandbox bool) *android.RuleBuilderCommand { + srcJarList android.Path, bootclasspath, classpath classpath, sourcepaths android.Paths, + implicitsRsp, homeDir android.WritablePath, sandbox bool) *android.RuleBuilderCommand { + rule.Command().Text("rm -rf").Flag(homeDir.String()) + rule.Command().Text("mkdir -p").Flag(homeDir.String()) + cmd := rule.Command() + cmd.FlagWithArg("ANDROID_SDK_HOME=", homeDir.String()) + if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_METALAVA") { rule.Remoteable(android.RemoteRuleSupports{RBE: true}) pool := ctx.Config().GetenvWithDefault("RBE_METALAVA_POOL", "metalava") @@ -1214,17 +1220,21 @@ func metalavaCmd(ctx android.ModuleContext, rule *android.RuleBuilder, javaVersi execStrategy = remoteexec.LocalExecStrategy labels["shallow"] = "true" } - inputs := []string{android.PathForOutput(ctx, "host", ctx.Config().PrebuiltOS(), "framework", "metalava.jar").String()} + inputs := []string{ + ctx.Config().HostJavaToolPath(ctx, "metalava").String(), + homeDir.String(), + } if v := ctx.Config().Getenv("RBE_METALAVA_INPUTS"); v != "" { inputs = append(inputs, strings.Split(v, ",")...) } cmd.Text((&remoteexec.REParams{ - Labels: labels, - ExecStrategy: execStrategy, - Inputs: inputs, - RSPFile: implicitsRsp.String(), - ToolchainInputs: []string{config.JavaCmd(ctx).String()}, - Platform: map[string]string{remoteexec.PoolKey: pool}, + Labels: labels, + ExecStrategy: execStrategy, + Inputs: inputs, + RSPFile: implicitsRsp.String(), + ToolchainInputs: []string{config.JavaCmd(ctx).String()}, + Platform: map[string]string{remoteexec.PoolKey: pool}, + EnvironmentVariables: []string{"ANDROID_SDK_HOME"}, }).NoVarTemplate(ctx.Config())) } @@ -1302,9 +1312,9 @@ func (d *Droidstubs) GenerateAndroidBuildActions(ctx android.ModuleContext) { srcJarList := zipSyncCmd(ctx, rule, srcJarDir, d.Javadoc.srcJars) implicitsRsp := android.PathForModuleOut(ctx, ctx.ModuleName()+"-"+"implicits.rsp") - + homeDir := android.PathForModuleOut(ctx, "metalava-home") cmd := metalavaCmd(ctx, rule, javaVersion, d.Javadoc.srcFiles, srcJarList, - deps.bootClasspath, deps.classpath, d.Javadoc.sourcepaths, implicitsRsp, + deps.bootClasspath, deps.classpath, d.Javadoc.sourcepaths, implicitsRsp, homeDir, Bool(d.Javadoc.properties.Sandbox)) cmd.Implicits(d.Javadoc.implicits) diff --git a/java/java_test.go b/java/java_test.go index 911265532..670eefc76 100644 --- a/java/java_test.go +++ b/java/java_test.go @@ -48,6 +48,26 @@ func tearDown() { os.RemoveAll(buildDir) } +// Factory to use to create fixtures for tests in this package. +var javaFixtureFactory = android.NewFixtureFactory( + &buildDir, + genrule.PrepareForTestWithGenRuleBuildComponents, + // Get the CC build components but not default modules. + cc.PrepareForTestWithCcBuildComponents, + // Include all the default java modules. + PrepareForTestWithJavaDefaultModules, + android.FixtureRegisterWithContext(func(ctx android.RegistrationContext) { + ctx.RegisterModuleType("java_plugin", PluginFactory) + ctx.RegisterModuleType("python_binary_host", python.PythonBinaryHostFactory) + + ctx.PreDepsMutators(python.RegisterPythonPreDepsMutators) + ctx.RegisterPreSingletonType("overlay", OverlaySingletonFactory) + ctx.RegisterPreSingletonType("sdk_versions", sdkPreSingletonFactory) + }), + javaMockFS().AddToFixture(), + dexpreopt.PrepareForTestWithDexpreopt, +) + func TestMain(m *testing.M) { run := func() int { setUp() @@ -59,10 +79,20 @@ func TestMain(m *testing.M) { os.Exit(run()) } +// testConfig is a legacy way of creating a test Config for testing java modules. +// +// See testJava for an explanation as to how to stop using this deprecated method. +// +// deprecated func testConfig(env map[string]string, bp string, fs map[string][]byte) android.Config { return TestConfig(buildDir, env, bp, fs) } +// testContext is a legacy way of creating a TestContext for testing java modules. +// +// See testJava for an explanation as to how to stop using this deprecated method. +// +// deprecated func testContext(config android.Config) *android.TestContext { ctx := android.NewTestArchContext(config) @@ -92,6 +122,11 @@ func testContext(config android.Config) *android.TestContext { return ctx } +// run is a legacy way of running tests of java modules. +// +// See testJava for an explanation as to how to stop using this deprecated method. +// +// deprecated func run(t *testing.T, ctx *android.TestContext, config android.Config) { t.Helper() @@ -105,23 +140,38 @@ func run(t *testing.T, ctx *android.TestContext, config android.Config) { android.FailIfErrored(t, errs) } +// testJavaError is a legacy way of running tests of java modules that expect errors. +// +// See testJava for an explanation as to how to stop using this deprecated method. +// +// deprecated func testJavaError(t *testing.T, pattern string, bp string) (*android.TestContext, android.Config) { t.Helper() return testJavaErrorWithConfig(t, pattern, testConfig(nil, bp, nil)) } +// testJavaErrorWithConfig is a legacy way of running tests of java modules that expect errors. +// +// See testJava for an explanation as to how to stop using this deprecated method. +// +// deprecated func testJavaErrorWithConfig(t *testing.T, pattern string, config android.Config) (*android.TestContext, android.Config) { t.Helper() - ctx := testContext(config) - + // This must be done on the supplied config and not as part of the fixture because any changes to + // the fixture's config will be ignored when RunTestWithConfig replaces it. pathCtx := android.PathContextForTesting(config) dexpreopt.SetTestGlobalConfig(config, dexpreopt.GlobalConfigForTests(pathCtx)) - - runWithErrors(t, ctx, config, pattern) - - return ctx, config + result := javaFixtureFactory. + ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(pattern)). + RunTestWithConfig(t, config) + return result.TestContext, result.Config } +// runWithErrors is a legacy way of running tests of java modules that expect errors. +// +// See testJava for an explanation as to how to stop using this deprecated method. +// +// deprecated func runWithErrors(t *testing.T, ctx *android.TestContext, config android.Config, pattern string) { ctx.Register() _, errs := ctx.ParseBlueprintsFiles("Android.bp") @@ -139,22 +189,43 @@ func runWithErrors(t *testing.T, ctx *android.TestContext, config android.Config return } -func testJavaWithFS(t *testing.T, bp string, fs map[string][]byte) (*android.TestContext, android.Config) { +// testJavaWithFS runs tests using the javaFixtureFactory +// +// See testJava for an explanation as to how to stop using this deprecated method. +// +// deprecated +func testJavaWithFS(t *testing.T, bp string, fs android.MockFS) (*android.TestContext, android.Config) { t.Helper() - return testJavaWithConfig(t, testConfig(nil, bp, fs)) + result := javaFixtureFactory.Extend(fs.AddToFixture()).RunTestWithBp(t, bp) + return result.TestContext, result.Config } +// testJava runs tests using the javaFixtureFactory +// +// Do not add any new usages of this, instead use the javaFixtureFactory directly as it makes it +// much easier to customize the test behavior. +// +// If it is necessary to customize the behavior of an existing test that uses this then please first +// convert the test to using javaFixtureFactory first and then in a following change add the +// appropriate fixture preparers. Keeping the conversion change separate makes it easy to verify +// that it did not change the test behavior unexpectedly. +// +// deprecated func testJava(t *testing.T, bp string) (*android.TestContext, android.Config) { t.Helper() - return testJavaWithFS(t, bp, nil) + result := javaFixtureFactory.RunTestWithBp(t, bp) + return result.TestContext, result.Config } +// testJavaWithConfig runs tests using the javaFixtureFactory +// +// See testJava for an explanation as to how to stop using this deprecated method. +// +// deprecated func testJavaWithConfig(t *testing.T, config android.Config) (*android.TestContext, android.Config) { t.Helper() - ctx := testContext(config) - run(t, ctx, config) - - return ctx, config + result := javaFixtureFactory.RunTestWithConfig(t, config) + return result.TestContext, result.Config } func moduleToPath(name string) string { @@ -168,6 +239,12 @@ func moduleToPath(name string) string { } } +// defaultModuleToPath constructs a path to the turbine generate jar for a default test module that +// is defined in PrepareForIntegrationTestWithJava +func defaultModuleToPath(name string) string { + return filepath.Join(buildDir, ".intermediates", defaultJavaDir, name, "android_common", "turbine-combined", name+".jar") +} + func TestJavaLinkType(t *testing.T) { testJava(t, ` java_library { @@ -2352,75 +2429,11 @@ func TestPatchModule(t *testing.T) { expected := "java.base=.:" + buildDir checkPatchModuleFlag(t, ctx, "bar", expected) expected = "java.base=" + strings.Join([]string{ - ".", buildDir, "dir", "dir2", "nested", moduleToPath("ext"), moduleToPath("framework")}, ":") + ".", buildDir, "dir", "dir2", "nested", defaultModuleToPath("ext"), defaultModuleToPath("framework")}, ":") checkPatchModuleFlag(t, ctx, "baz", expected) }) } -func TestJavaSystemModules(t *testing.T) { - ctx, _ := testJava(t, ` - java_system_modules { - name: "system-modules", - libs: ["system-module1", "system-module2"], - } - java_library { - name: "system-module1", - srcs: ["a.java"], - sdk_version: "none", - system_modules: "none", - } - java_library { - name: "system-module2", - srcs: ["b.java"], - sdk_version: "none", - system_modules: "none", - } - `) - - // check the existence of the module - systemModules := ctx.ModuleForTests("system-modules", "android_common") - - cmd := systemModules.Rule("jarsTosystemModules") - - // make sure the command compiles against the supplied modules. - for _, module := range []string{"system-module1.jar", "system-module2.jar"} { - if !strings.Contains(cmd.Args["classpath"], module) { - t.Errorf("system modules classpath %v does not contain %q", cmd.Args["classpath"], - module) - } - } -} - -func TestJavaSystemModulesImport(t *testing.T) { - ctx, _ := testJava(t, ` - java_system_modules_import { - name: "system-modules", - libs: ["system-module1", "system-module2"], - } - java_import { - name: "system-module1", - jars: ["a.jar"], - } - java_import { - name: "system-module2", - jars: ["b.jar"], - } - `) - - // check the existence of the module - systemModules := ctx.ModuleForTests("system-modules", "android_common") - - cmd := systemModules.Rule("jarsTosystemModules") - - // make sure the command compiles against the supplied modules. - for _, module := range []string{"system-module1.jar", "system-module2.jar"} { - if !strings.Contains(cmd.Args["classpath"], module) { - t.Errorf("system modules classpath %v does not contain %q", cmd.Args["classpath"], - module) - } - } -} - func TestJavaLibraryWithSystemModules(t *testing.T) { ctx, _ := testJava(t, ` java_library { diff --git a/java/legacy_core_platform_api_usage.go b/java/legacy_core_platform_api_usage.go index 021920af6..874338d10 100644 --- a/java/legacy_core_platform_api_usage.go +++ b/java/legacy_core_platform_api_usage.go @@ -19,10 +19,6 @@ import ( "android/soong/java/config" ) -// This variable is effectively unused in pre-master branches, and is -// included (with the same value as it has in AOSP) only to ease -// merges between branches (see the comment in the -// useLegacyCorePlatformApi() function): var legacyCorePlatformApiModules = []string{ "ahat-test-dump", "android.car", @@ -34,29 +30,44 @@ var legacyCorePlatformApiModules = []string{ "art_cts_jvmti_test_library", "art-gtest-jars-MyClassNatives", "BackupFrameworksServicesRoboTests", + "backuplib", "BandwidthEnforcementTest", "BlockedNumberProvider", "BluetoothInstrumentationTests", "BluetoothMidiService", + "CarDeveloperOptions", + "CarService", + "CarServiceTest", "car-apps-common", + "car-service-test-lib", + "car-service-test-static-lib", "CertInstaller", "ConnectivityManagerTest", "ContactsProvider", + "CorePerfTests", "core-tests-support", + "CtsAppExitTestCases", "CtsContentTestCases", "CtsIkeTestCases", + "CtsAppExitTestCases", "CtsLibcoreWycheproofBCTestCases", "CtsMediaTestCases", "CtsNetTestCases", "CtsNetTestCasesLatestSdk", "CtsSecurityTestCases", + "CtsSuspendAppsTestCases", "CtsUsageStatsTestCases", + "DeadpoolService", + "DeadpoolServiceBtServices", + "DeviceInfo", + "DiagnosticTools", "DisplayCutoutEmulationEmu01Overlay", "DocumentsUIPerfTests", "DocumentsUITests", "DownloadProvider", "DownloadProviderTests", "DownloadProviderUi", + "ds-car-docs", // for AAOS API documentation only "DynamicSystemInstallationService", "EmergencyInfo-lib", "ethernet-service", @@ -73,6 +84,7 @@ var legacyCorePlatformApiModules = []string{ "FrameworksServicesRoboTests", "FrameworksServicesTests", "FrameworksUtilTests", + "FrameworksWifiTests", "hid", "hidl_test_java_java", "hwbinder", @@ -95,6 +107,9 @@ var legacyCorePlatformApiModules = []string{ "platform_library-docs", "PrintSpooler", "RollbackTest", + "service-blobstore", + "service-connectivity", + "service-jobscheduler", "services", "services.accessibility", "services.backup", @@ -136,10 +151,6 @@ var legacyCorePlatformApiModules = []string{ "wifi-service", } -// This variable is effectively unused in pre-master branches, and is -// included (with the same value as it has in AOSP) only to ease -// merges between branches (see the comment in the -// useLegacyCorePlatformApi() function): var legacyCorePlatformApiLookup = make(map[string]struct{}) func init() { @@ -149,12 +160,8 @@ func init() { } func useLegacyCorePlatformApi(ctx android.EarlyModuleContext) bool { - // In pre-master branches, we don't attempt to force usage of the stable - // version of the core/platform API. Instead, we always use the legacy - // version --- except in tests, where we always use stable, so that we - // can make the test assertions the same as other branches. - // This should be false in tests and true otherwise: - return ctx.Config().TestProductVariables == nil + _, found := legacyCorePlatformApiLookup[ctx.ModuleName()] + return found } func corePlatformSystemModules(ctx android.EarlyModuleContext) string { diff --git a/java/lint.go b/java/lint.go index 50b84dc71..9f677db3a 100644 --- a/java/lint.go +++ b/java/lint.go @@ -22,6 +22,8 @@ import ( "github.com/google/blueprint/proptools" "android/soong/android" + "android/soong/java/config" + "android/soong/remoteexec" ) type LintProperties struct { @@ -172,8 +174,44 @@ func (l *linter) deps(ctx android.BottomUpMutatorContext) { extraLintCheckTag, extraCheckModules...) } -func (l *linter) writeLintProjectXML(ctx android.ModuleContext, - rule *android.RuleBuilder) (projectXMLPath, configXMLPath, cacheDir, homeDir android.WritablePath, deps android.Paths) { +// lintPaths contains the paths to lint's inputs and outputs to make it easier to pass them +// around. +type lintPaths struct { + projectXML android.WritablePath + configXML android.WritablePath + cacheDir android.WritablePath + homeDir android.WritablePath + srcjarDir android.WritablePath + + deps android.Paths + + remoteInputs android.Paths + remoteRSPInputs android.Paths +} + +func lintRBEExecStrategy(ctx android.ModuleContext) string { + return ctx.Config().GetenvWithDefault("RBE_LINT_EXEC_STRATEGY", remoteexec.LocalExecStrategy) +} + +func (l *linter) writeLintProjectXML(ctx android.ModuleContext, rule *android.RuleBuilder) lintPaths { + var deps android.Paths + var remoteInputs android.Paths + var remoteRSPInputs android.Paths + + // Paths passed to trackInputDependency will be added as dependencies of the rule that runs + // lint and passed as inputs to the remote execution proxy. + trackInputDependency := func(paths ...android.Path) { + deps = append(deps, paths...) + remoteInputs = append(remoteInputs, paths...) + } + + // Paths passed to trackRSPDependency will be added as dependencies of the rule that runs + // lint, but the RSP file will be used by the remote execution proxy to find the files so that + // it doesn't overflow command line limits. + trackRSPDependency := func(paths android.Paths, rsp android.Path) { + deps = append(deps, paths...) + remoteRSPInputs = append(remoteRSPInputs, rsp) + } var resourcesList android.WritablePath if len(l.resources) > 0 { @@ -184,17 +222,27 @@ func (l *linter) writeLintProjectXML(ctx android.ModuleContext, resListRule := android.NewRuleBuilder(pctx, ctx) resListRule.Command().Text("cp").FlagWithRspFileInputList("", l.resources).Output(resourcesList) resListRule.Build("lint_resources_list", "lint resources list") - deps = append(deps, l.resources...) + trackRSPDependency(l.resources, resourcesList) } - projectXMLPath = android.PathForModuleOut(ctx, "lint", "project.xml") + projectXMLPath := android.PathForModuleOut(ctx, "lint", "project.xml") // Lint looks for a lint.xml file next to the project.xml file, give it one. - configXMLPath = android.PathForModuleOut(ctx, "lint", "lint.xml") - cacheDir = android.PathForModuleOut(ctx, "lint", "cache") - homeDir = android.PathForModuleOut(ctx, "lint", "home") + configXMLPath := android.PathForModuleOut(ctx, "lint", "lint.xml") + cacheDir := android.PathForModuleOut(ctx, "lint", "cache") + homeDir := android.PathForModuleOut(ctx, "lint", "home") srcJarDir := android.PathForModuleOut(ctx, "lint-srcjars") srcJarList := zipSyncCmd(ctx, rule, srcJarDir, l.srcJars) + // TODO(ccross): this is a little fishy. The files extracted from the srcjars are referenced + // by the project.xml and used by the later lint rule, but the lint rule depends on the srcjars, + // not the extracted files. + trackRSPDependency(l.srcJars, srcJarList) + + // TODO(ccross): some of the files in l.srcs are generated sources and should be passed to + // lint separately. + srcsList := android.PathForModuleOut(ctx, "lint", "srcs.list") + rule.Command().Text("cp").FlagWithRspFileInputList("", l.srcs).Output(srcsList) + trackRSPDependency(l.srcs, srcsList) cmd := rule.Command(). BuiltTool("lint-project-xml"). @@ -209,38 +257,40 @@ func (l *linter) writeLintProjectXML(ctx android.ModuleContext, cmd.Flag("--test") } if l.manifest != nil { - deps = append(deps, l.manifest) cmd.FlagWithArg("--manifest ", l.manifest.String()) + trackInputDependency(l.manifest) } if l.mergedManifest != nil { - deps = append(deps, l.mergedManifest) cmd.FlagWithArg("--merged_manifest ", l.mergedManifest.String()) + trackInputDependency(l.mergedManifest) } - // TODO(ccross): some of the files in l.srcs are generated sources and should be passed to - // lint separately. - cmd.FlagWithRspFileInputList("--srcs ", l.srcs) - deps = append(deps, l.srcs...) + cmd.FlagWithInput("--srcs ", srcsList) cmd.FlagWithInput("--generated_srcs ", srcJarList) - deps = append(deps, l.srcJars...) if resourcesList != nil { cmd.FlagWithInput("--resources ", resourcesList) } if l.classes != nil { - deps = append(deps, l.classes) cmd.FlagWithArg("--classes ", l.classes.String()) + trackInputDependency(l.classes) } cmd.FlagForEachArg("--classpath ", l.classpath.Strings()) - deps = append(deps, l.classpath...) + trackInputDependency(l.classpath...) cmd.FlagForEachArg("--extra_checks_jar ", l.extraLintCheckJars.Strings()) - deps = append(deps, l.extraLintCheckJars...) + trackInputDependency(l.extraLintCheckJars...) - cmd.FlagWithArg("--root_dir ", "$PWD") + if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_LINT") && + lintRBEExecStrategy(ctx) != remoteexec.LocalExecStrategy { + // TODO(b/181912787): remove these and use "." instead. + cmd.FlagWithArg("--root_dir ", "/b/f/w") + } else { + cmd.FlagWithArg("--root_dir ", "$PWD") + } // The cache tag in project.xml is relative to the root dir, or the project.xml file if // the root dir is not set. @@ -254,7 +304,18 @@ func (l *linter) writeLintProjectXML(ctx android.ModuleContext, cmd.FlagForEachArg("--error_check ", l.properties.Lint.Error_checks) cmd.FlagForEachArg("--fatal_check ", l.properties.Lint.Fatal_checks) - return projectXMLPath, configXMLPath, cacheDir, homeDir, deps + return lintPaths{ + projectXML: projectXMLPath, + configXML: configXMLPath, + cacheDir: cacheDir, + homeDir: homeDir, + + deps: deps, + + remoteInputs: remoteInputs, + remoteRSPInputs: remoteRSPInputs, + } + } // generateManifest adds a command to the rule to write a simple manifest that contains the @@ -297,7 +358,7 @@ func (l *linter) lint(ctx android.ModuleContext) { l.manifest = manifest } - projectXML, lintXML, cacheDir, homeDir, deps := l.writeLintProjectXML(ctx, rule) + lintPaths := l.writeLintProjectXML(ctx, rule) html := android.PathForModuleOut(ctx, "lint-report.html") text := android.PathForModuleOut(ctx, "lint-report.txt") @@ -311,8 +372,8 @@ func (l *linter) lint(ctx android.ModuleContext) { } }) - rule.Command().Text("rm -rf").Flag(cacheDir.String()).Flag(homeDir.String()) - rule.Command().Text("mkdir -p").Flag(cacheDir.String()).Flag(homeDir.String()) + rule.Command().Text("rm -rf").Flag(lintPaths.cacheDir.String()).Flag(lintPaths.homeDir.String()) + rule.Command().Text("mkdir -p").Flag(lintPaths.cacheDir.String()).Flag(lintPaths.homeDir.String()) rule.Command().Text("rm -f").Output(html).Output(text).Output(xml) var annotationsZipPath, apiVersionsXMLPath android.Path @@ -324,16 +385,53 @@ func (l *linter) lint(ctx android.ModuleContext) { apiVersionsXMLPath = copiedAPIVersionsXmlPath(ctx) } - cmd := rule.Command(). - Text("("). - Flag("JAVA_OPTS=-Xmx3072m"). - FlagWithArg("ANDROID_SDK_HOME=", homeDir.String()). + cmd := rule.Command() + + cmd.Flag("JAVA_OPTS=-Xmx3072m"). + FlagWithArg("ANDROID_SDK_HOME=", lintPaths.homeDir.String()). FlagWithInput("SDK_ANNOTATIONS=", annotationsZipPath). - FlagWithInput("LINT_OPTS=-DLINT_API_DATABASE=", apiVersionsXMLPath). - BuiltTool("lint"). + FlagWithInput("LINT_OPTS=-DLINT_API_DATABASE=", apiVersionsXMLPath) + + if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_LINT") { + pool := ctx.Config().GetenvWithDefault("RBE_LINT_POOL", "java16") + // TODO(b/181912787): this should be local fallback once the hack that passes /b/f/w in project.xml + // is removed. + execStrategy := lintRBEExecStrategy(ctx) + labels := map[string]string{"type": "tool", "name": "lint"} + rule.Remoteable(android.RemoteRuleSupports{RBE: true}) + remoteInputs := lintPaths.remoteInputs + remoteInputs = append(remoteInputs, + lintPaths.projectXML, + lintPaths.configXML, + lintPaths.homeDir, + lintPaths.cacheDir, + ctx.Config().HostJavaToolPath(ctx, "lint.jar"), + annotationsZipPath, + apiVersionsXMLPath, + ) + + cmd.Text((&remoteexec.REParams{ + Labels: labels, + ExecStrategy: execStrategy, + ToolchainInputs: []string{config.JavaCmd(ctx).String()}, + Inputs: remoteInputs.Strings(), + OutputFiles: android.Paths{html, text, xml}.Strings(), + RSPFile: strings.Join(lintPaths.remoteRSPInputs.Strings(), ","), + EnvironmentVariables: []string{ + "JAVA_OPTS", + "ANDROID_SDK_HOME", + "SDK_ANNOTATIONS", + "LINT_OPTS", + "LANG", + }, + Platform: map[string]string{remoteexec.PoolKey: pool}, + }).NoVarTemplate(ctx.Config())) + } + + cmd.BuiltTool("lint"). Flag("--quiet"). - FlagWithInput("--project ", projectXML). - FlagWithInput("--config ", lintXML). + FlagWithInput("--project ", lintPaths.projectXML). + FlagWithInput("--config ", lintPaths.configXML). FlagWithOutput("--html ", html). FlagWithOutput("--text ", text). FlagWithOutput("--xml ", xml). @@ -343,7 +441,9 @@ func (l *linter) lint(ctx android.ModuleContext) { FlagWithArg("--url ", fmt.Sprintf(".=.,%s=out", android.PathForOutput(ctx).String())). Flag("--exitcode"). Flags(l.properties.Lint.Flags). - Implicits(deps) + Implicit(annotationsZipPath). + Implicit(apiVersionsXMLPath). + Implicits(lintPaths.deps) if checkOnly := ctx.Config().Getenv("ANDROID_LINT_CHECK"); checkOnly != "" { cmd.FlagWithArg("--check ", checkOnly) @@ -362,9 +462,9 @@ func (l *linter) lint(ctx android.ModuleContext) { } } - cmd.Text("|| (").Text("if [ -e").Input(text).Text("]; then cat").Input(text).Text("; fi; exit 7)").Text(")") + cmd.Text("|| (").Text("if [ -e").Input(text).Text("]; then cat").Input(text).Text("; fi; exit 7)") - rule.Command().Text("rm -rf").Flag(cacheDir.String()).Flag(homeDir.String()) + rule.Command().Text("rm -rf").Flag(lintPaths.cacheDir.String()).Flag(lintPaths.homeDir.String()) rule.Build("lint", "lint") diff --git a/java/prebuilt_apis.go b/java/prebuilt_apis.go index c91b32117..8a442b5ff 100644 --- a/java/prebuilt_apis.go +++ b/java/prebuilt_apis.go @@ -178,7 +178,7 @@ func createSystemModules(mctx android.LoadHookContext, apiver string) { props.Name = proptools.StringPtr(prebuiltApiModuleName(mctx, "system_modules", "public", apiver)) props.Libs = append(props.Libs, prebuiltApiModuleName(mctx, "core-for-system-modules", "public", apiver)) - mctx.CreateModule(SystemModulesFactory, &props) + mctx.CreateModule(systemModulesImportFactory, &props) } func prebuiltSdkSystemModules(mctx android.LoadHookContext, p *prebuiltApis) { @@ -248,9 +248,9 @@ func prebuiltApiFiles(mctx android.LoadHookContext, p *prebuiltApis) { } // Create incompatibilities tracking files for all modules, if we have a "next" api. + incompatibilities := make(map[string]bool) if nextApiDir := String(p.properties.Next_api_dir); nextApiDir != "" { files := getPrebuiltFilesInSubdir(mctx, nextApiDir, "api/*incompatibilities.txt") - incompatibilities := make(map[string]bool) for _, f := range files { localPath := strings.TrimPrefix(f, mydir) module, _, scope := parseApiFilePath(mctx, localPath) @@ -266,11 +266,11 @@ func prebuiltApiFiles(mctx android.LoadHookContext, p *prebuiltApis) { incompatibilities[referencedModule+"."+scope] = true } - // Create empty incompatibilities files for remaining modules - for _, k := range android.SortedStringKeys(m) { - if _, ok := incompatibilities[k]; !ok { - createEmptyFile(mctx, apiModuleName(m[k].module+"-incompatibilities", m[k].scope, "latest")) - } + } + // Create empty incompatibilities files for remaining modules + for _, k := range android.SortedStringKeys(m) { + if _, ok := incompatibilities[k]; !ok { + createEmptyFile(mctx, apiModuleName(m[k].module+"-incompatibilities", m[k].scope, "latest")) } } } diff --git a/java/sdk_library.go b/java/sdk_library.go index 30d120d5c..b03f90cf4 100644 --- a/java/sdk_library.go +++ b/java/sdk_library.go @@ -452,6 +452,7 @@ type sdkLibraryProperties struct { // that references the latest released API and remove API specification files. // * API specification filegroup -> <dist-stem>.api.<scope>.latest // * Removed API specification filegroup -> <dist-stem>-removed.api.<scope>.latest + // * API incompatibilities baseline filegroup -> <dist-stem>-incompatibilities.api.<scope>.latest Dist_stem *string // A compatibility mode that allows historical API-tracking files to not exist. @@ -1059,6 +1060,9 @@ func (module *SdkLibrary) DepsMutator(ctx android.BottomUpMutatorContext) { if m := android.SrcIsModule(module.latestRemovedApiFilegroupName(apiScope)); !ctx.OtherModuleExists(m) { missingApiModules = append(missingApiModules, m) } + if m := android.SrcIsModule(module.latestIncompatibilitiesFilegroupName(apiScope)); !ctx.OtherModuleExists(m) { + missingApiModules = append(missingApiModules, m) + } } if len(missingApiModules) != 0 && !module.sdkLibraryProperties.Unsafe_ignore_missing_latest_api { m := module.Name() + " is missing tracking files for previously released library versions.\n" @@ -1165,6 +1169,10 @@ func (module *SdkLibrary) latestRemovedApiFilegroupName(apiScope *apiScope) stri return ":" + module.distStem() + "-removed.api." + apiScope.name + ".latest" } +func (module *SdkLibrary) latestIncompatibilitiesFilegroupName(apiScope *apiScope) string { + return ":" + module.distStem() + "-incompatibilities.api." + apiScope.name + ".latest" +} + func childModuleVisibility(childVisibility []string) []string { if childVisibility == nil { // No child visibility set. The child will use the visibility of the sdk_library. @@ -1389,6 +1397,8 @@ func (module *SdkLibrary) createStubsSourcesAndApi(mctx android.DefaultableHookC props.Check_api.Last_released.Api_file = latestApiFilegroupName props.Check_api.Last_released.Removed_api_file = proptools.StringPtr( module.latestRemovedApiFilegroupName(apiScope)) + props.Check_api.Last_released.Baseline_file = proptools.StringPtr( + module.latestIncompatibilitiesFilegroupName(apiScope)) if proptools.Bool(module.sdkLibraryProperties.Api_lint.Enabled) { // Enable api lint. diff --git a/java/system_modules.go b/java/system_modules.go index 95f71b80f..8c69051ae 100644 --- a/java/system_modules.go +++ b/java/system_modules.go @@ -169,7 +169,13 @@ func (system *SystemModules) GenerateAndroidBuildActions(ctx android.ModuleConte system.outputDir, system.outputDeps = TransformJarsToSystemModules(ctx, jars) } -func (system *SystemModules) DepsMutator(ctx android.BottomUpMutatorContext) { +// ComponentDepsMutator is called before prebuilt modules without a corresponding source module are +// renamed so unless the supplied libs specifically includes the prebuilt_ prefix this is guaranteed +// to only add dependencies on source modules. +// +// The systemModuleLibsTag will prevent the prebuilt mutators from replacing this dependency so it +// will never be changed to depend on a prebuilt either. +func (system *SystemModules) ComponentDepsMutator(ctx android.BottomUpMutatorContext) { ctx.AddVariationDependencies(nil, systemModulesLibsTag, system.properties.Libs...) } @@ -225,6 +231,15 @@ func (system *systemModulesImport) Prebuilt() *android.Prebuilt { return &system.prebuilt } +// ComponentDepsMutator is called before prebuilt modules without a corresponding source module are +// renamed so as this adds a prebuilt_ prefix this is guaranteed to only add dependencies on source +// modules. +func (system *systemModulesImport) ComponentDepsMutator(ctx android.BottomUpMutatorContext) { + for _, lib := range system.properties.Libs { + ctx.AddVariationDependencies(nil, systemModulesLibsTag, "prebuilt_"+lib) + } +} + type systemModulesSdkMemberType struct { android.SdkMemberTypeBase } diff --git a/java/system_modules_test.go b/java/system_modules_test.go new file mode 100644 index 000000000..44049ee6b --- /dev/null +++ b/java/system_modules_test.go @@ -0,0 +1,112 @@ +// Copyright 2021 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 java + +import ( + "testing" + + "android/soong/android" +) + +func normalizedPathsToHeaderJars(result *android.TestResult, moduleNames ...string) []string { + paths := []string{} + for _, moduleName := range moduleNames { + module := result.Module(moduleName, "android_common") + info := result.ModuleProvider(module, JavaInfoProvider).(JavaInfo) + paths = append(paths, result.NormalizePathsForTesting(info.HeaderJars)...) + } + return paths +} + +var addSourceSystemModules = android.FixtureAddTextFile("source/Android.bp", ` + java_system_modules { + name: "system-modules", + libs: ["system-module1", "system-module2"], + } + java_library { + name: "system-module1", + srcs: ["a.java"], + sdk_version: "none", + system_modules: "none", + } + java_library { + name: "system-module2", + srcs: ["b.java"], + sdk_version: "none", + system_modules: "none", + } +`) + +func TestJavaSystemModules(t *testing.T) { + result := javaFixtureFactory.RunTest(t, addSourceSystemModules) + + // check the existence of the source module + sourceSystemModules := result.ModuleForTests("system-modules", "android_common") + sourceInputs := sourceSystemModules.Rule("jarsTosystemModules").Inputs + + // The expected paths are the header jars from the source input modules. + expectedSourcePaths := normalizedPathsToHeaderJars(result, "system-module1", "system-module2") + result.AssertArrayString("source system modules inputs", expectedSourcePaths, result.NormalizePathsForTesting(sourceInputs)) +} + +var addPrebuiltSystemModules = android.FixtureAddTextFile("prebuilts/Android.bp", ` + java_system_modules_import { + name: "system-modules", + libs: ["system-module1", "system-module2"], + } + java_import { + name: "system-module1", + jars: ["a.jar"], + } + java_import { + name: "system-module2", + jars: ["b.jar"], + } +`) + +func TestJavaSystemModulesImport(t *testing.T) { + result := javaFixtureFactory.RunTest(t, addPrebuiltSystemModules) + + // check the existence of the renamed prebuilt module + prebuiltSystemModules := result.ModuleForTests("system-modules", "android_common") + prebuiltInputs := prebuiltSystemModules.Rule("jarsTosystemModules").Inputs + + // The expected paths are the header jars from the renamed prebuilt input modules. + expectedPrebuiltPaths := normalizedPathsToHeaderJars(result, "system-module1", "system-module2") + result.AssertArrayString("renamed prebuilt system modules inputs", expectedPrebuiltPaths, result.NormalizePathsForTesting(prebuiltInputs)) +} + +func TestJavaSystemModulesMixSourceAndPrebuilt(t *testing.T) { + result := javaFixtureFactory.RunTest(t, + addSourceSystemModules, + addPrebuiltSystemModules, + ) + + // check the existence of the source module + sourceSystemModules := result.ModuleForTests("system-modules", "android_common") + sourceInputs := sourceSystemModules.Rule("jarsTosystemModules").Inputs + + // The expected paths are the header jars from the source input modules. + expectedSourcePaths := normalizedPathsToHeaderJars(result, "system-module1", "system-module2") + result.AssertArrayString("source system modules inputs", expectedSourcePaths, result.NormalizePathsForTesting(sourceInputs)) + + // check the existence of the renamed prebuilt module + prebuiltSystemModules := result.ModuleForTests("prebuilt_system-modules", "android_common") + prebuiltInputs := prebuiltSystemModules.Rule("jarsTosystemModules").Inputs + + // The expected paths are the header jars from the renamed prebuilt input modules. + expectedPrebuiltPaths := normalizedPathsToHeaderJars(result, "prebuilt_system-module1", "prebuilt_system-module2") + result.AssertArrayString("prebuilt system modules inputs", expectedPrebuiltPaths, result.NormalizePathsForTesting(prebuiltInputs)) +} diff --git a/java/testing.go b/java/testing.go index bfa1e6b2a..4e1997e45 100644 --- a/java/testing.go +++ b/java/testing.go @@ -29,10 +29,40 @@ import ( "github.com/google/blueprint" ) -func TestConfig(buildDir string, env map[string]string, bp string, fs map[string][]byte) android.Config { - bp += GatherRequiredDepsForTest() +const defaultJavaDir = "default/java" + +// Test fixture preparer that will register most java build components. +// +// Singletons and mutators should only be added here if they are needed for a majority of java +// module types, otherwise they should be added under a separate preparer to allow them to be +// selected only when needed to reduce test execution time. +// +// Module types do not have much of an overhead unless they are used so this should include as many +// module types as possible. The exceptions are those module types that require mutators and/or +// singletons in order to function in which case they should be kept together in a separate +// preparer. +var PrepareForTestWithJavaBuildComponents = android.FixtureRegisterWithContext(RegisterRequiredBuildComponentsForTest) + +// Test fixture preparer that will define default java modules, e.g. standard prebuilt modules. +var PrepareForTestWithJavaDefaultModules = android.GroupFixturePreparers( + // Make sure that mutators and module types, e.g. prebuilt mutators available. + android.PrepareForTestWithAndroidBuildComponents, + // Make sure that all the module types used in the defaults are registered. + PrepareForTestWithJavaBuildComponents, + // The java default module definitions. + android.FixtureAddTextFile(defaultJavaDir+"/Android.bp", GatherRequiredDepsForTest()), +) - mockFS := map[string][]byte{ +// Prepare a fixture to use all java module types, mutators and singletons fully. +// +// This should only be used by tests that want to run with as much of the build enabled as possible. +var PrepareForIntegrationTestWithJava = android.GroupFixturePreparers( + cc.PrepareForIntegrationTestWithCc, + PrepareForTestWithJavaDefaultModules, +) + +func javaMockFS() android.MockFS { + mockFS := android.MockFS{ "api/current.txt": nil, "api/removed.txt": nil, "api/system-current.txt": nil, @@ -64,6 +94,14 @@ func TestConfig(buildDir string, env map[string]string, bp string, fs map[string mockFS[k] = v } + return mockFS +} + +func TestConfig(buildDir string, env map[string]string, bp string, fs map[string][]byte) android.Config { + bp += GatherRequiredDepsForTest() + + mockFS := javaMockFS() + cc.GatherRequiredFilesForTest(mockFS) for k, v := range fs { diff --git a/python/binary.go b/python/binary.go index 416a7eec0..372b8a8c1 100644 --- a/python/binary.go +++ b/python/binary.go @@ -20,10 +20,92 @@ import ( "fmt" "android/soong/android" + "android/soong/bazel" + + "github.com/google/blueprint/proptools" ) func init() { android.RegisterModuleType("python_binary_host", PythonBinaryHostFactory) + android.RegisterBp2BuildMutator("python_binary_host", PythonBinaryBp2Build) +} + +type bazelPythonBinaryAttributes struct { + Main string + Srcs bazel.LabelList + Data bazel.LabelList + Python_version string +} + +type bazelPythonBinary struct { + android.BazelTargetModuleBase + bazelPythonBinaryAttributes +} + +func BazelPythonBinaryFactory() android.Module { + module := &bazelPythonBinary{} + module.AddProperties(&module.bazelPythonBinaryAttributes) + android.InitBazelTargetModule(module) + return module +} + +func (m *bazelPythonBinary) Name() string { + return m.BaseModuleName() +} + +func (m *bazelPythonBinary) GenerateAndroidBuildActions(ctx android.ModuleContext) {} + +func PythonBinaryBp2Build(ctx android.TopDownMutatorContext) { + m, ok := ctx.Module().(*Module) + if !ok || !m.ConvertWithBp2build() { + return + } + + // a Module can be something other than a python_binary_host + if ctx.ModuleType() != "python_binary_host" { + return + } + + var main string + for _, propIntf := range m.GetProperties() { + if props, ok := propIntf.(*BinaryProperties); ok { + // main is optional. + if props.Main != nil { + main = *props.Main + break + } + } + } + // TODO(b/182306917): this doesn't fully handle all nested props versioned + // by the python version, which would have been handled by the version split + // mutator. This is sufficient for very simple python_binary_host modules + // under Bionic. + py3Enabled := proptools.BoolDefault(m.properties.Version.Py3.Enabled, false) + py2Enabled := proptools.BoolDefault(m.properties.Version.Py2.Enabled, false) + var python_version string + if py3Enabled && py2Enabled { + panic(fmt.Errorf( + "error for '%s' module: bp2build's python_binary_host converter does not support "+ + "converting a module that is enabled for both Python 2 and 3 at the same time.", m.Name())) + } else if py2Enabled { + python_version = "PY2" + } else { + // do nothing, since python_version defaults to PY3. + } + + attrs := &bazelPythonBinaryAttributes{ + Main: main, + Srcs: android.BazelLabelForModuleSrcExcludes(ctx, m.properties.Srcs, m.properties.Exclude_srcs), + Data: android.BazelLabelForModuleSrc(ctx, m.properties.Data), + Python_version: python_version, + } + + props := bazel.BazelTargetModuleProperties{ + // Use the native py_binary rule. + Rule_class: "py_binary", + } + + ctx.CreateBazelTargetModule(BazelPythonBinaryFactory, m.Name(), props, attrs) } type BinaryProperties struct { @@ -81,6 +163,8 @@ func NewBinary(hod android.HostOrDeviceSupported) (*Module, *binaryDecorator) { func PythonBinaryHostFactory() android.Module { module, _ := NewBinary(android.HostSupported) + android.InitBazelModule(module) + return module.init() } diff --git a/python/python.go b/python/python.go index b3e3d13b2..a078c0b58 100644 --- a/python/python.go +++ b/python/python.go @@ -125,6 +125,7 @@ type pathMapping struct { type Module struct { android.ModuleBase android.DefaultableModuleBase + android.BazelModuleBase properties BaseProperties protoProperties android.ProtoProperties diff --git a/remoteexec/remoteexec.go b/remoteexec/remoteexec.go index d6e2c0a75..5f0426a7f 100644 --- a/remoteexec/remoteexec.go +++ b/remoteexec/remoteexec.go @@ -81,6 +81,9 @@ type REParams struct { // ToolchainInputs is a list of paths or ninja variables pointing to the location of // toolchain binaries used by the rule. ToolchainInputs []string + // EnvironmentVariables is a list of environment variables whose values should be passed through + // to the remote execution. + EnvironmentVariables []string } func init() { @@ -162,6 +165,10 @@ func (r *REParams) wrapperArgs() string { args += " --toolchain_inputs=" + strings.Join(r.ToolchainInputs, ",") } + if len(r.EnvironmentVariables) > 0 { + args += " --env_var_allowlist=" + strings.Join(r.EnvironmentVariables, ",") + } + return args + " -- " } diff --git a/rust/config/allowed_list.go b/rust/config/allowed_list.go index fc11d2901..408d433c9 100644 --- a/rust/config/allowed_list.go +++ b/rust/config/allowed_list.go @@ -14,6 +14,7 @@ var ( "external/rust", "external/vm_tools/p9", "frameworks/native/libs/binder/rust", + "frameworks/proto_logging/stats", "packages/modules/DnsResolver", "packages/modules/Virtualization", "prebuilts/rust", diff --git a/rust/testing.go b/rust/testing.go index 9534ab580..5be71c90e 100644 --- a/rust/testing.go +++ b/rust/testing.go @@ -20,6 +20,30 @@ import ( "android/soong/genrule" ) +// Preparer that will define all cc module types and a limited set of mutators and singletons that +// make those module types usable. +var PrepareForTestWithRustBuildComponents = android.GroupFixturePreparers( + android.FixtureRegisterWithContext(RegisterRequiredBuildComponentsForTest), +) + +// The directory in which rust test default modules will be defined. +// +// Placing them here ensures that their location does not conflict with default test modules +// defined by other packages. +const rustDefaultsDir = "defaults/rust/" + +// Preparer that will define default rust modules, e.g. standard prebuilt modules. +var PrepareForTestWithRustDefaultModules = android.GroupFixturePreparers( + cc.PrepareForTestWithCcDefaultModules, + PrepareForTestWithRustBuildComponents, + android.FixtureAddTextFile(rustDefaultsDir+"Android.bp", GatherRequiredDepsForTest()), +) + +// Preparer that will allow use of all rust modules fully. +var PrepareForIntegrationTestWithRust = android.GroupFixturePreparers( + PrepareForTestWithRustDefaultModules, +) + func GatherRequiredDepsForTest() string { bp := ` rust_prebuilt_library { diff --git a/scripts/build-mainline-modules.sh b/scripts/build-mainline-modules.sh index 0813f1a10..18174a452 100755 --- a/scripts/build-mainline-modules.sh +++ b/scripts/build-mainline-modules.sh @@ -36,8 +36,9 @@ MODULES_SDK_AND_EXPORTS=( # List of libraries installed on the platform that are needed for ART chroot # testing. PLATFORM_LIBRARIES=( - liblog + heapprofd_client_api libartpalette-system + liblog ) # We want to create apex modules for all supported architectures. diff --git a/sdk/bp_test.go b/sdk/bp_test.go index e1edc5131..a7164a5e9 100644 --- a/sdk/bp_test.go +++ b/sdk/bp_test.go @@ -54,7 +54,7 @@ func propertyStructFixture() interface{} { return str } -func checkPropertySetFixture(h *TestHelper, val interface{}, hasTags bool) { +func checkPropertySetFixture(h android.TestHelper, val interface{}, hasTags bool) { set := val.(*bpPropertySet) h.AssertDeepEquals("wrong x value", "taxi", set.getValue("x")) h.AssertDeepEquals("wrong y value", 1729, set.getValue("y")) @@ -73,7 +73,7 @@ func checkPropertySetFixture(h *TestHelper, val interface{}, hasTags bool) { } func TestAddPropertySimple(t *testing.T) { - h := &TestHelper{t} + h := android.TestHelper{t} set := newPropertySet() for name, val := range map[string]interface{}{ "x": "taxi", @@ -92,7 +92,7 @@ func TestAddPropertySimple(t *testing.T) { } func TestAddPropertySubset(t *testing.T) { - h := &TestHelper{t} + h := android.TestHelper{t} getFixtureMap := map[string]func() interface{}{ "property set": propertySetFixture, "property struct": propertyStructFixture, @@ -139,7 +139,7 @@ func TestAddPropertySubset(t *testing.T) { } func TestAddPropertySetNew(t *testing.T) { - h := &TestHelper{t} + h := android.TestHelper{t} set := newPropertySet() subset := set.AddPropertySet("sub") subset.AddProperty("new", "d^^b") @@ -147,7 +147,7 @@ func TestAddPropertySetNew(t *testing.T) { } func TestAddPropertySetExisting(t *testing.T) { - h := &TestHelper{t} + h := android.TestHelper{t} set := propertySetFixture().(*bpPropertySet) subset := set.AddPropertySet("sub") subset.AddProperty("new", "d^^b") @@ -181,7 +181,7 @@ func (t removeFredTransformation) transformPropertySetAfterContents(name string, func TestTransformRemoveProperty(t *testing.T) { - helper := &TestHelper{t} + helper := android.TestHelper{t} set := newPropertySet() set.AddProperty("name", "name") @@ -196,7 +196,7 @@ func TestTransformRemoveProperty(t *testing.T) { func TestTransformRemovePropertySet(t *testing.T) { - helper := &TestHelper{t} + helper := android.TestHelper{t} set := newPropertySet() set.AddProperty("name", "name") diff --git a/sdk/cc_sdk_test.go b/sdk/cc_sdk_test.go index 359177771..6da135a32 100644 --- a/sdk/cc_sdk_test.go +++ b/sdk/cc_sdk_test.go @@ -101,7 +101,7 @@ func TestSdkCompileMultilibOverride(t *testing.T) { } `) - result.CheckSnapshot("mysdk", "", + CheckSnapshot(result, "mysdk", "", checkUnversionedAndroidBpContents(` // This is auto-generated. DO NOT EDIT. @@ -353,7 +353,7 @@ func TestSnapshotWithObject(t *testing.T) { } `) - result.CheckSnapshot("mysdk", "", + CheckSnapshot(result, "mysdk", "", checkUnversionedAndroidBpContents(` // This is auto-generated. DO NOT EDIT. @@ -440,7 +440,7 @@ func TestSnapshotWithCcDuplicateHeaders(t *testing.T) { } `) - result.CheckSnapshot("mysdk", "", + CheckSnapshot(result, "mysdk", "", checkAllCopyRules(` myinclude/Test.h -> include/myinclude/Test.h .intermediates/mynativelib1/android_arm64_armv8-a_shared/mynativelib1.so -> arm64/lib/mynativelib1.so @@ -486,7 +486,7 @@ func TestSnapshotWithCcExportGeneratedHeaders(t *testing.T) { } `) - result.CheckSnapshot("mysdk", "", + CheckSnapshot(result, "mysdk", "", checkUnversionedAndroidBpContents(` // This is auto-generated. DO NOT EDIT. @@ -556,7 +556,7 @@ func TestSnapshotWithCcSharedLibraryCommonProperties(t *testing.T) { } `) - result.CheckSnapshot("mysdk", "", + CheckSnapshot(result, "mysdk", "", checkUnversionedAndroidBpContents(` // This is auto-generated. DO NOT EDIT. @@ -615,7 +615,7 @@ func TestSnapshotWithCcBinary(t *testing.T) { } `) - result.CheckSnapshot("mymodule_exports", "", + CheckSnapshot(result, "mymodule_exports", "", checkUnversionedAndroidBpContents(` // This is auto-generated. DO NOT EDIT. @@ -700,7 +700,7 @@ func TestMultipleHostOsTypesSnapshotWithCcBinary(t *testing.T) { } `) - result.CheckSnapshot("myexports", "", + CheckSnapshot(result, "myexports", "", checkUnversionedAndroidBpContents(` // This is auto-generated. DO NOT EDIT. @@ -853,7 +853,7 @@ func TestSnapshotWithSingleHostOsType(t *testing.T) { result := runTests(t, ctx, config) - result.CheckSnapshot("myexports", "", + CheckSnapshot(result, "myexports", "", checkUnversionedAndroidBpContents(` // This is auto-generated. DO NOT EDIT. @@ -991,7 +991,7 @@ func TestSnapshotWithCcStaticNocrtBinary(t *testing.T) { } `) - result.CheckSnapshot("mymodule_exports", "", + CheckSnapshot(result, "mymodule_exports", "", checkUnversionedAndroidBpContents(` // This is auto-generated. DO NOT EDIT. @@ -1099,7 +1099,7 @@ func TestSnapshotWithCcSharedLibrary(t *testing.T) { } `) - result.CheckSnapshot("mysdk", "", + CheckSnapshot(result, "mysdk", "", checkUnversionedAndroidBpContents(` // This is auto-generated. DO NOT EDIT. @@ -1200,7 +1200,7 @@ func TestSnapshotWithCcSharedLibrarySharedLibs(t *testing.T) { } `) - result.CheckSnapshot("mysdk", "", + CheckSnapshot(result, "mysdk", "", checkUnversionedAndroidBpContents(` // This is auto-generated. DO NOT EDIT. @@ -1297,7 +1297,7 @@ func TestHostSnapshotWithCcSharedLibrary(t *testing.T) { } `) - result.CheckSnapshot("mysdk", "", + CheckSnapshot(result, "mysdk", "", checkUnversionedAndroidBpContents(` // This is auto-generated. DO NOT EDIT. @@ -1424,7 +1424,7 @@ func TestMultipleHostOsTypesSnapshotWithCcSharedLibrary(t *testing.T) { } `) - result.CheckSnapshot("mysdk", "", + CheckSnapshot(result, "mysdk", "", checkUnversionedAndroidBpContents(` // This is auto-generated. DO NOT EDIT. @@ -1552,7 +1552,7 @@ func TestSnapshotWithCcStaticLibrary(t *testing.T) { } `) - result.CheckSnapshot("myexports", "", + CheckSnapshot(result, "myexports", "", checkUnversionedAndroidBpContents(` // This is auto-generated. DO NOT EDIT. @@ -1615,7 +1615,7 @@ func TestHostSnapshotWithCcStaticLibrary(t *testing.T) { } `) - result.CheckSnapshot("myexports", "", + CheckSnapshot(result, "myexports", "", checkUnversionedAndroidBpContents(` // This is auto-generated. DO NOT EDIT. @@ -1729,7 +1729,7 @@ func TestSnapshotWithCcLibrary(t *testing.T) { } `) - result.CheckSnapshot("myexports", "", + CheckSnapshot(result, "myexports", "", checkUnversionedAndroidBpContents(` // This is auto-generated. DO NOT EDIT. @@ -1843,7 +1843,7 @@ func TestHostSnapshotWithMultiLib64(t *testing.T) { } `) - result.CheckSnapshot("myexports", "", + CheckSnapshot(result, "myexports", "", checkUnversionedAndroidBpContents(` // This is auto-generated. DO NOT EDIT. @@ -1940,7 +1940,7 @@ func TestSnapshotWithCcHeadersLibrary(t *testing.T) { } `) - result.CheckSnapshot("mysdk", "", + CheckSnapshot(result, "mysdk", "", checkUnversionedAndroidBpContents(` // This is auto-generated. DO NOT EDIT. @@ -1978,7 +1978,7 @@ func TestHostSnapshotWithCcHeadersLibrary(t *testing.T) { } `) - result.CheckSnapshot("mysdk", "", + CheckSnapshot(result, "mysdk", "", checkUnversionedAndroidBpContents(` // This is auto-generated. DO NOT EDIT. @@ -2080,7 +2080,7 @@ func TestDeviceAndHostSnapshotWithCcHeadersLibrary(t *testing.T) { } `) - result.CheckSnapshot("mysdk", "", + CheckSnapshot(result, "mysdk", "", checkUnversionedAndroidBpContents(` // This is auto-generated. DO NOT EDIT. @@ -2193,7 +2193,7 @@ func TestSystemSharedLibPropagation(t *testing.T) { } `) - result.CheckSnapshot("mysdk", "", + CheckSnapshot(result, "mysdk", "", checkUnversionedAndroidBpContents(` // This is auto-generated. DO NOT EDIT. @@ -2266,7 +2266,7 @@ cc_prebuilt_library_shared { } `) - result.CheckSnapshot("mysdk", "", + CheckSnapshot(result, "mysdk", "", checkUnversionedAndroidBpContents(` // This is auto-generated. DO NOT EDIT. @@ -2377,7 +2377,7 @@ func TestStubsLibrary(t *testing.T) { } `) - result.CheckSnapshot("mysdk", "", + CheckSnapshot(result, "mysdk", "", checkUnversionedAndroidBpContents(` // This is auto-generated. DO NOT EDIT. @@ -2430,7 +2430,7 @@ func TestDeviceAndHostSnapshotWithStubsLibrary(t *testing.T) { } `) - result.CheckSnapshot("mysdk", "", + CheckSnapshot(result, "mysdk", "", checkUnversionedAndroidBpContents(` // This is auto-generated. DO NOT EDIT. @@ -2543,7 +2543,7 @@ func TestUniqueHostSoname(t *testing.T) { } `) - result.CheckSnapshot("mysdk", "", + CheckSnapshot(result, "mysdk", "", checkUnversionedAndroidBpContents(` // This is auto-generated. DO NOT EDIT. @@ -2658,7 +2658,7 @@ func TestNoSanitizerMembers(t *testing.T) { } `) - result.CheckSnapshot("mysdk", "", + CheckSnapshot(result, "mysdk", "", checkUnversionedAndroidBpContents(` // This is auto-generated. DO NOT EDIT. diff --git a/sdk/exports.go b/sdk/exports.go index d3130574e..9a0ba4e32 100644 --- a/sdk/exports.go +++ b/sdk/exports.go @@ -17,8 +17,12 @@ package sdk import "android/soong/android" func init() { - android.RegisterModuleType("module_exports", ModuleExportsFactory) - android.RegisterModuleType("module_exports_snapshot", ModuleExportsSnapshotsFactory) + registerModuleExportsBuildComponents(android.InitRegistrationContext) +} + +func registerModuleExportsBuildComponents(ctx android.RegistrationContext) { + ctx.RegisterModuleType("module_exports", ModuleExportsFactory) + ctx.RegisterModuleType("module_exports_snapshot", ModuleExportsSnapshotsFactory) } // module_exports defines the exports of a mainline module. The exports are Soong modules diff --git a/sdk/exports_test.go b/sdk/exports_test.go index 1c59244d8..54a40d272 100644 --- a/sdk/exports_test.go +++ b/sdk/exports_test.go @@ -42,7 +42,7 @@ func TestModuleExportsSnapshot(t *testing.T) { "package/Android.bp": []byte(packageBp), }) - result.CheckSnapshot("myexports", "package", + CheckSnapshot(result, "myexports", "package", checkAndroidBpContents(` // This is auto-generated. DO NOT EDIT. diff --git a/sdk/java_sdk_test.go b/sdk/java_sdk_test.go index 111b22c68..ef8e4a00d 100644 --- a/sdk/java_sdk_test.go +++ b/sdk/java_sdk_test.go @@ -125,9 +125,9 @@ func TestSdkDependsOnSourceEvenWhenPrebuiltPreferred(t *testing.T) { `) // Make sure that the mysdk module depends on "sdkmember" and not "prebuilt_sdkmember". - java.CheckModuleDependencies(t, result.ctx, "mysdk", "android_common", []string{"sdkmember"}) + java.CheckModuleDependencies(t, result.TestContext, "mysdk", "android_common", []string{"sdkmember"}) - result.CheckSnapshot("mysdk", "", + CheckSnapshot(result, "mysdk", "", checkAndroidBpContents(`// This is auto-generated. DO NOT EDIT. java_import { @@ -224,11 +224,11 @@ func TestBasicSdkWithJavaLibrary(t *testing.T) { } `) - sdkMemberV1 := result.ctx.ModuleForTests("sdkmember_mysdk_1", "android_common").Rule("combineJar").Output - sdkMemberV2 := result.ctx.ModuleForTests("sdkmember_mysdk_2", "android_common").Rule("combineJar").Output + sdkMemberV1 := result.ModuleForTests("sdkmember_mysdk_1", "android_common").Rule("combineJar").Output + sdkMemberV2 := result.ModuleForTests("sdkmember_mysdk_2", "android_common").Rule("combineJar").Output - javalibForMyApex := result.ctx.ModuleForTests("myjavalib", "android_common_apex10000_mysdk_1") - javalibForMyApex2 := result.ctx.ModuleForTests("myjavalib", "android_common_apex10000_mysdk_2") + javalibForMyApex := result.ModuleForTests("myjavalib", "android_common_apex10000_mysdk_1") + javalibForMyApex2 := result.ModuleForTests("myjavalib", "android_common_apex10000_mysdk_2") // Depending on the uses_sdks value, different libs are linked ensureListContains(t, pathsToStrings(javalibForMyApex.Rule("javac").Implicits), sdkMemberV1.String()) @@ -255,7 +255,7 @@ func TestSnapshotWithJavaHeaderLibrary(t *testing.T) { } `) - result.CheckSnapshot("mysdk", "", + CheckSnapshot(result, "mysdk", "", checkAndroidBpContents(` // This is auto-generated. DO NOT EDIT. @@ -312,7 +312,7 @@ func TestHostSnapshotWithJavaHeaderLibrary(t *testing.T) { } `) - result.CheckSnapshot("mysdk", "", + CheckSnapshot(result, "mysdk", "", checkAndroidBpContents(` // This is auto-generated. DO NOT EDIT. @@ -369,7 +369,7 @@ func TestDeviceAndHostSnapshotWithJavaHeaderLibrary(t *testing.T) { } `) - result.CheckSnapshot("mysdk", "", + CheckSnapshot(result, "mysdk", "", checkAndroidBpContents(` // This is auto-generated. DO NOT EDIT. @@ -440,7 +440,7 @@ func TestSnapshotWithJavaImplLibrary(t *testing.T) { } `) - result.CheckSnapshot("myexports", "", + CheckSnapshot(result, "myexports", "", checkAndroidBpContents(` // This is auto-generated. DO NOT EDIT. @@ -496,7 +496,7 @@ func TestSnapshotWithJavaBootLibrary(t *testing.T) { } `) - result.CheckSnapshot("myexports", "", + CheckSnapshot(result, "myexports", "", checkAndroidBpContents(` // This is auto-generated. DO NOT EDIT. @@ -551,7 +551,7 @@ func TestHostSnapshotWithJavaImplLibrary(t *testing.T) { } `) - result.CheckSnapshot("myexports", "", + CheckSnapshot(result, "myexports", "", checkAndroidBpContents(` // This is auto-generated. DO NOT EDIT. @@ -607,7 +607,7 @@ func TestSnapshotWithJavaTest(t *testing.T) { } `) - result.CheckSnapshot("myexports", "", + CheckSnapshot(result, "myexports", "", checkAndroidBpContents(` // This is auto-generated. DO NOT EDIT. @@ -662,7 +662,7 @@ func TestHostSnapshotWithJavaTest(t *testing.T) { } `) - result.CheckSnapshot("myexports", "", + CheckSnapshot(result, "myexports", "", checkAndroidBpContents(` // This is auto-generated. DO NOT EDIT. @@ -731,7 +731,7 @@ func TestSnapshotWithJavaSystemModules(t *testing.T) { } `) - result.CheckSnapshot("mysdk", "", + CheckSnapshot(result, "mysdk", "", checkAndroidBpContents(` // This is auto-generated. DO NOT EDIT. @@ -827,7 +827,7 @@ func TestHostSnapshotWithJavaSystemModules(t *testing.T) { } `) - result.CheckSnapshot("mysdk", "", + CheckSnapshot(result, "mysdk", "", checkAndroidBpContents(` // This is auto-generated. DO NOT EDIT. @@ -918,7 +918,7 @@ func TestDeviceAndHostSnapshotWithOsSpecificMembers(t *testing.T) { } `) - result.CheckSnapshot("myexports", "", + CheckSnapshot(result, "myexports", "", checkAndroidBpContents(` // This is auto-generated. DO NOT EDIT. @@ -1032,7 +1032,7 @@ func TestSnapshotWithJavaSdkLibrary(t *testing.T) { } `) - result.CheckSnapshot("mysdk", "", + CheckSnapshot(result, "mysdk", "", checkAndroidBpContents(` // This is auto-generated. DO NOT EDIT. @@ -1133,7 +1133,7 @@ func TestSnapshotWithJavaSdkLibrary_SdkVersion_None(t *testing.T) { } `) - result.CheckSnapshot("mysdk", "", + CheckSnapshot(result, "mysdk", "", checkAndroidBpContents(` // This is auto-generated. DO NOT EDIT. @@ -1202,7 +1202,7 @@ func TestSnapshotWithJavaSdkLibrary_SdkVersion_ForScope(t *testing.T) { } `) - result.CheckSnapshot("mysdk", "", + CheckSnapshot(result, "mysdk", "", checkAndroidBpContents(` // This is auto-generated. DO NOT EDIT. @@ -1274,7 +1274,7 @@ func TestSnapshotWithJavaSdkLibrary_ApiScopes(t *testing.T) { } `) - result.CheckSnapshot("mysdk", "", + CheckSnapshot(result, "mysdk", "", checkAndroidBpContents(` // This is auto-generated. DO NOT EDIT. @@ -1367,7 +1367,7 @@ func TestSnapshotWithJavaSdkLibrary_ModuleLib(t *testing.T) { } `) - result.CheckSnapshot("mysdk", "", + CheckSnapshot(result, "mysdk", "", checkAndroidBpContents(` // This is auto-generated. DO NOT EDIT. @@ -1475,7 +1475,7 @@ func TestSnapshotWithJavaSdkLibrary_SystemServer(t *testing.T) { } `) - result.CheckSnapshot("mysdk", "", + CheckSnapshot(result, "mysdk", "", checkAndroidBpContents(` // This is auto-generated. DO NOT EDIT. @@ -1563,7 +1563,7 @@ func TestSnapshotWithJavaSdkLibrary_NamingScheme(t *testing.T) { } `) - result.CheckSnapshot("mysdk", "", + CheckSnapshot(result, "mysdk", "", checkAndroidBpContents(` // This is auto-generated. DO NOT EDIT. @@ -1639,7 +1639,7 @@ func TestSnapshotWithJavaSdkLibrary_DoctagFiles(t *testing.T) { } `) - result.CheckSnapshot("mysdk", "", + CheckSnapshot(result, "mysdk", "", checkAndroidBpContents(` // This is auto-generated. DO NOT EDIT. diff --git a/sdk/sdk.go b/sdk/sdk.go index f3d075022..2c84a2e88 100644 --- a/sdk/sdk.go +++ b/sdk/sdk.go @@ -33,10 +33,14 @@ func init() { pctx.Import("android/soong/android") pctx.Import("android/soong/java/config") - android.RegisterModuleType("sdk", SdkModuleFactory) - android.RegisterModuleType("sdk_snapshot", SnapshotModuleFactory) - android.PreDepsMutators(RegisterPreDepsMutators) - android.PostDepsMutators(RegisterPostDepsMutators) + registerSdkBuildComponents(android.InitRegistrationContext) +} + +func registerSdkBuildComponents(ctx android.RegistrationContext) { + ctx.RegisterModuleType("sdk", SdkModuleFactory) + ctx.RegisterModuleType("sdk_snapshot", SnapshotModuleFactory) + ctx.PreDepsMutators(RegisterPreDepsMutators) + ctx.PostDepsMutators(RegisterPostDepsMutators) } type sdk struct { diff --git a/sdk/sdk_test.go b/sdk/sdk_test.go index c4dc41beb..65a9001e6 100644 --- a/sdk/sdk_test.go +++ b/sdk/sdk_test.go @@ -169,7 +169,7 @@ func TestSnapshotVisibility(t *testing.T) { "package/Android.bp": []byte(packageBp), }) - result.CheckSnapshot("mysdk", "package", + CheckSnapshot(result, "mysdk", "package", checkAndroidBpContents(` // This is auto-generated. DO NOT EDIT. @@ -309,18 +309,15 @@ func TestPrebuiltVisibilityProperty_AddPrivate(t *testing.T) { `) } -func TestSDkInstall(t *testing.T) { +func TestSdkInstall(t *testing.T) { sdk := ` sdk { name: "mysdk", } ` - result := testSdkWithFs(t, ``, - map[string][]byte{ - "Android.bp": []byte(sdk), - }) + result := testSdkWithFs(t, sdk, nil) - result.CheckSnapshot("mysdk", "", + CheckSnapshot(result, "mysdk", "", checkAllOtherCopyRules(`.intermediates/mysdk/common_os/mysdk-current.zip -> mysdk-current.zip`), ) } @@ -390,7 +387,7 @@ func TestCommonValueOptimization(t *testing.T) { extractor := newCommonValueExtractor(common) - h := TestHelper{t} + h := android.TestHelper{t} err := extractor.extractCommonProperties(common, structs) h.AssertDeepEquals("unexpected error", nil, err) @@ -465,7 +462,7 @@ func TestCommonValueOptimization_InvalidArchSpecificVariants(t *testing.T) { extractor := newCommonValueExtractor(common) - h := TestHelper{t} + h := android.TestHelper{t} err := extractor.extractCommonProperties(common, structs) h.AssertErrorMessageEquals("unexpected error", `field "S_Common" is not tagged as "arch_variant" but has arch specific properties: diff --git a/sdk/testing.go b/sdk/testing.go index 7a2540a27..3fb27ca27 100644 --- a/sdk/testing.go +++ b/sdk/testing.go @@ -19,7 +19,6 @@ import ( "io/ioutil" "os" "path/filepath" - "reflect" "strings" "testing" @@ -122,12 +121,8 @@ func testSdkContext(bp string, fs map[string][]byte, extraOsTypes []android.OsTy ctx.PostDepsMutators(apex.RegisterPostDepsMutators) // from this package - ctx.RegisterModuleType("sdk", SdkModuleFactory) - ctx.RegisterModuleType("sdk_snapshot", SnapshotModuleFactory) - ctx.RegisterModuleType("module_exports", ModuleExportsFactory) - ctx.RegisterModuleType("module_exports_snapshot", ModuleExportsSnapshotsFactory) - ctx.PreDepsMutators(RegisterPreDepsMutators) - ctx.PostDepsMutators(RegisterPostDepsMutators) + registerModuleExportsBuildComponents(ctx) + registerSdkBuildComponents(ctx) ctx.Register() @@ -141,9 +136,8 @@ func runTests(t *testing.T, ctx *android.TestContext, config android.Config) *te _, errs = ctx.PrepareBuildActions(config) android.FailIfErrored(t, errs) return &testSdkResult{ - TestHelper: TestHelper{t: t}, - ctx: ctx, - config: config, + TestHelper: android.TestHelper{T: t}, + TestContext: ctx, } } @@ -185,74 +179,24 @@ func pathsToStrings(paths android.Paths) []string { return ret } -// Provides general test support. -type TestHelper struct { - t *testing.T -} - -func (h *TestHelper) AssertStringEquals(message string, expected string, actual string) { - h.t.Helper() - if actual != expected { - h.t.Errorf("%s: expected %s, actual %s", message, expected, actual) - } -} - -func (h *TestHelper) AssertErrorMessageEquals(message string, expected string, actual error) { - h.t.Helper() - if actual == nil { - h.t.Errorf("Expected error but was nil") - } else if actual.Error() != expected { - h.t.Errorf("%s: expected %s, actual %s", message, expected, actual.Error()) - } -} - -func (h *TestHelper) AssertTrimmedStringEquals(message string, expected string, actual string) { - h.t.Helper() - expected = strings.TrimSpace(expected) - actual = strings.TrimSpace(actual) - if actual != expected { - h.t.Errorf("%s: expected:\n%s\nactual:\n%s\n", message, expected, actual) - } -} - -func (h *TestHelper) AssertDeepEquals(message string, expected interface{}, actual interface{}) { - h.t.Helper() - if !reflect.DeepEqual(actual, expected) { - h.t.Errorf("%s: expected %#v, actual %#v", message, expected, actual) - } -} - -func (h *TestHelper) AssertPanic(message string, funcThatShouldPanic func()) { - h.t.Helper() - panicked := false - func() { - defer func() { - if x := recover(); x != nil { - panicked = true - } - }() - funcThatShouldPanic() - }() - if !panicked { - h.t.Error(message) - } -} - // Encapsulates result of processing an SDK definition. Provides support for // checking the state of the build structures. type testSdkResult struct { - TestHelper - ctx *android.TestContext - config android.Config + android.TestHelper + *android.TestContext } -// Analyse the sdk build rules to extract information about what it is doing. +func (result *testSdkResult) Module(name string, variant string) android.Module { + return result.ModuleForTests(name, variant).Module() +} +// Analyse the sdk build rules to extract information about what it is doing. +// // e.g. find the src/dest pairs from each cp command, the various zip files // generated, etc. -func (r *testSdkResult) getSdkSnapshotBuildInfo(sdk *sdk) *snapshotBuildInfo { +func getSdkSnapshotBuildInfo(result *testSdkResult, sdk *sdk) *snapshotBuildInfo { info := &snapshotBuildInfo{ - r: r, + r: result, androidBpContents: sdk.GetAndroidBpContentsForTests(), androidUnversionedBpContents: sdk.GetUnversionedAndroidBpContentsForTests(), androidVersionedBpContents: sdk.GetVersionedAndroidBpContentsForTests(), @@ -295,7 +239,7 @@ func (r *testSdkResult) getSdkSnapshotBuildInfo(sdk *sdk) *snapshotBuildInfo { info.intermediateZip = info.outputZip mergeInput := android.NormalizePathForTesting(bp.Input) if info.intermediateZip != mergeInput { - r.t.Errorf("Expected intermediate zip %s to be an input to merge zips but found %s instead", + result.Errorf("Expected intermediate zip %s to be an input to merge zips but found %s instead", info.intermediateZip, mergeInput) } @@ -314,28 +258,20 @@ func (r *testSdkResult) getSdkSnapshotBuildInfo(sdk *sdk) *snapshotBuildInfo { return info } -func (r *testSdkResult) Module(name string, variant string) android.Module { - return r.ctx.ModuleForTests(name, variant).Module() -} - -func (r *testSdkResult) ModuleForTests(name string, variant string) android.TestingModule { - return r.ctx.ModuleForTests(name, variant) -} - // Check the snapshot build rules. // // Takes a list of functions which check different facets of the snapshot build rules. // Allows each test to customize what is checked without duplicating lots of code // or proliferating check methods of different flavors. -func (r *testSdkResult) CheckSnapshot(name string, dir string, checkers ...snapshotBuildInfoChecker) { - r.t.Helper() +func CheckSnapshot(result *testSdkResult, name string, dir string, checkers ...snapshotBuildInfoChecker) { + result.Helper() // The sdk CommonOS variant is always responsible for generating the snapshot. variant := android.CommonOS.Name - sdk := r.Module(name, variant).(*sdk) + sdk := result.Module(name, variant).(*sdk) - snapshotBuildInfo := r.getSdkSnapshotBuildInfo(sdk) + snapshotBuildInfo := getSdkSnapshotBuildInfo(result, sdk) // Check state of the snapshot build. for _, checker := range checkers { @@ -347,7 +283,7 @@ func (r *testSdkResult) CheckSnapshot(name string, dir string, checkers ...snaps if dir != "" { dir = filepath.Clean(dir) + "/" } - r.AssertStringEquals("Snapshot zip file in wrong place", + result.AssertStringEquals("Snapshot zip file in wrong place", fmt.Sprintf(".intermediates/%s%s/%s/%s-current.zip", dir, name, variant, name), actual) // Populate a mock filesystem with the files that would have been copied by @@ -358,7 +294,7 @@ func (r *testSdkResult) CheckSnapshot(name string, dir string, checkers ...snaps } // Process the generated bp file to make sure it is valid. - testSdkWithFs(r.t, snapshotBuildInfo.androidBpContents, fs) + testSdkWithFs(result.T, snapshotBuildInfo.androidBpContents, fs) } type snapshotBuildInfoChecker func(info *snapshotBuildInfo) @@ -368,7 +304,7 @@ type snapshotBuildInfoChecker func(info *snapshotBuildInfo) // Both the expected and actual string are both trimmed before comparing. func checkAndroidBpContents(expected string) snapshotBuildInfoChecker { return func(info *snapshotBuildInfo) { - info.r.t.Helper() + info.r.Helper() info.r.AssertTrimmedStringEquals("Android.bp contents do not match", expected, info.androidBpContents) } } @@ -380,7 +316,7 @@ func checkAndroidBpContents(expected string) snapshotBuildInfoChecker { // Both the expected and actual string are both trimmed before comparing. func checkUnversionedAndroidBpContents(expected string) snapshotBuildInfoChecker { return func(info *snapshotBuildInfo) { - info.r.t.Helper() + info.r.Helper() info.r.AssertTrimmedStringEquals("unversioned Android.bp contents do not match", expected, info.androidUnversionedBpContents) } } @@ -395,7 +331,7 @@ func checkUnversionedAndroidBpContents(expected string) snapshotBuildInfoChecker // Both the expected and actual string are both trimmed before comparing. func checkVersionedAndroidBpContents(expected string) snapshotBuildInfoChecker { return func(info *snapshotBuildInfo) { - info.r.t.Helper() + info.r.Helper() info.r.AssertTrimmedStringEquals("versioned Android.bp contents do not match", expected, info.androidVersionedBpContents) } } @@ -407,14 +343,14 @@ func checkVersionedAndroidBpContents(expected string) snapshotBuildInfoChecker { // before comparing. func checkAllCopyRules(expected string) snapshotBuildInfoChecker { return func(info *snapshotBuildInfo) { - info.r.t.Helper() + info.r.Helper() info.r.AssertTrimmedStringEquals("Incorrect copy rules", expected, info.copyRules) } } func checkAllOtherCopyRules(expected string) snapshotBuildInfoChecker { return func(info *snapshotBuildInfo) { - info.r.t.Helper() + info.r.Helper() info.r.AssertTrimmedStringEquals("Incorrect copy rules", expected, info.otherCopyRules) } } @@ -422,9 +358,9 @@ func checkAllOtherCopyRules(expected string) snapshotBuildInfoChecker { // Check that the specified paths match the list of zips to merge with the intermediate zip. func checkMergeZips(expected ...string) snapshotBuildInfoChecker { return func(info *snapshotBuildInfo) { - info.r.t.Helper() + info.r.Helper() if info.intermediateZip == "" { - info.r.t.Errorf("No intermediate zip file was created") + info.r.Errorf("No intermediate zip file was created") } info.r.AssertDeepEquals("mismatching merge zip files", expected, info.mergeZips) diff --git a/sh/sh_binary.go b/sh/sh_binary.go index 031cd4717..49f4961f2 100644 --- a/sh/sh_binary.go +++ b/sh/sh_binary.go @@ -40,14 +40,32 @@ var pctx = android.NewPackageContext("android/soong/sh") func init() { pctx.Import("android/soong/android") - android.RegisterModuleType("sh_binary", ShBinaryFactory) - android.RegisterModuleType("sh_binary_host", ShBinaryHostFactory) - android.RegisterModuleType("sh_test", ShTestFactory) - android.RegisterModuleType("sh_test_host", ShTestHostFactory) + registerShBuildComponents(android.InitRegistrationContext) android.RegisterBp2BuildMutator("sh_binary", ShBinaryBp2Build) } +func registerShBuildComponents(ctx android.RegistrationContext) { + ctx.RegisterModuleType("sh_binary", ShBinaryFactory) + ctx.RegisterModuleType("sh_binary_host", ShBinaryHostFactory) + ctx.RegisterModuleType("sh_test", ShTestFactory) + ctx.RegisterModuleType("sh_test_host", ShTestHostFactory) +} + +// Test fixture preparer that will register most sh build components. +// +// Singletons and mutators should only be added here if they are needed for a majority of sh +// module types, otherwise they should be added under a separate preparer to allow them to be +// selected only when needed to reduce test execution time. +// +// Module types do not have much of an overhead unless they are used so this should include as many +// module types as possible. The exceptions are those module types that require mutators and/or +// singletons in order to function in which case they should be kept together in a separate +// preparer. +var PrepareForTestWithShBuildComponents = android.GroupFixturePreparers( + android.FixtureRegisterWithContext(registerShBuildComponents), +) + type shBinaryProperties struct { // Source file of this prebuilt. Src *string `android:"path,arch_variant"` diff --git a/sh/sh_binary_test.go b/sh/sh_binary_test.go index f48f7fb29..7a24168e5 100644 --- a/sh/sh_binary_test.go +++ b/sh/sh_binary_test.go @@ -37,28 +37,32 @@ func TestMain(m *testing.M) { os.Exit(run()) } -func testShBinary(t *testing.T, bp string) (*android.TestContext, android.Config) { - fs := map[string][]byte{ +var shFixtureFactory = android.NewFixtureFactory( + &buildDir, + cc.PrepareForTestWithCcBuildComponents, + PrepareForTestWithShBuildComponents, + android.FixtureMergeMockFs(android.MockFS{ "test.sh": nil, "testdata/data1": nil, "testdata/sub/data2": nil, - } - - config := android.TestArchConfig(buildDir, nil, bp, fs) - - ctx := android.NewTestArchContext(config) - ctx.RegisterModuleType("sh_test", ShTestFactory) - ctx.RegisterModuleType("sh_test_host", ShTestHostFactory) - - cc.RegisterRequiredBuildComponentsForTest(ctx) + }), +) - ctx.Register() - _, errs := ctx.ParseFileList(".", []string{"Android.bp"}) - android.FailIfErrored(t, errs) - _, errs = ctx.PrepareBuildActions(config) - android.FailIfErrored(t, errs) +// testShBinary runs tests using the shFixtureFactory +// +// Do not add any new usages of this, instead use the shFixtureFactory directly as it makes it much +// easier to customize the test behavior. +// +// If it is necessary to customize the behavior of an existing test that uses this then please first +// convert the test to using shFixtureFactory first and then in a following change add the +// appropriate fixture preparers. Keeping the conversion change separate makes it easy to verify +// that it did not change the test behavior unexpectedly. +// +// deprecated +func testShBinary(t *testing.T, bp string) (*android.TestContext, android.Config) { + result := shFixtureFactory.RunTestWithBp(t, bp) - return ctx, config + return result.TestContext, result.Config } func TestShTestSubDir(t *testing.T) { diff --git a/ui/build/config.go b/ui/build/config.go index 15da1bc8c..1152cd790 100644 --- a/ui/build/config.go +++ b/ui/build/config.go @@ -56,7 +56,6 @@ type configImpl struct { katiSuffix string targetDevice string targetDeviceDir string - fullBuild bool // Autodetected totalRAM uint64 @@ -792,14 +791,6 @@ func (c *configImpl) SetTargetDevice(device string) { c.targetDevice = device } -func (c *configImpl) FullBuild() bool { - return c.fullBuild -} - -func (c *configImpl) SetFullBuild(fullBuild bool) { - c.fullBuild = fullBuild -} - func (c *configImpl) TargetBuildVariant() string { if v, ok := c.environ.Get("TARGET_BUILD_VARIANT"); ok { return v diff --git a/ui/build/dumpvars.go b/ui/build/dumpvars.go index be6f00a18..fe0aca983 100644 --- a/ui/build/dumpvars.go +++ b/ui/build/dumpvars.go @@ -214,9 +214,6 @@ func runMakeProductConfig(ctx Context, config Config) { // So that later Kati runs can find BoardConfig.mk faster "TARGET_DEVICE_DIR", - // To decide whether to skip the old installed cleanup step. - "FULL_BUILD", - // Whether --werror_overriding_commands will work "BUILD_BROKEN_DUP_RULES", @@ -281,7 +278,6 @@ func runMakeProductConfig(ctx Context, config Config) { config.SetNinjaArgs(strings.Fields(makeVars["NINJA_GOALS"])) config.SetTargetDevice(makeVars["TARGET_DEVICE"]) config.SetTargetDeviceDir(makeVars["TARGET_DEVICE_DIR"]) - config.SetFullBuild(makeVars["FULL_BUILD"] == "true") config.SetBuildBrokenDupRules(makeVars["BUILD_BROKEN_DUP_RULES"] == "true") config.SetBuildBrokenUsesNetwork(makeVars["BUILD_BROKEN_USES_NETWORK"] == "true") diff --git a/ui/build/kati.go b/ui/build/kati.go index 668b20eed..06ec64607 100644 --- a/ui/build/kati.go +++ b/ui/build/kati.go @@ -229,11 +229,7 @@ func runKatiBuild(ctx Context, config Config) { // Cleanup steps. cleanCopyHeaders(ctx, config) - // Skip the old installed file cleanup step for few non-full build goals as we don't create - // an installed file list for them. - if config.FullBuild() { - cleanOldInstalledFiles(ctx, config) - } + cleanOldInstalledFiles(ctx, config) } // Clean out obsolete header files on the disk that were *not copied* during the diff --git a/ui/build/soong.go b/ui/build/soong.go index c2fa427bf..884e95741 100644 --- a/ui/build/soong.go +++ b/ui/build/soong.go @@ -116,7 +116,7 @@ func runSoong(ctx Context, config Config) { envFile := filepath.Join(config.SoongOutDir(), "soong.environment.used") getenv := func(k string) string { - v, _ := config.Environment().Get(k) + v, _ := soongBuildEnv.Get(k) return v } if stale, _ := shared.StaleEnvFile(envFile, getenv); stale { @@ -170,12 +170,20 @@ func runSoong(ctx Context, config Config) { "--frontend_file", fifo, "-f", filepath.Join(config.SoongOutDir(), file)) - cmd.Environment.Set("SOONG_OUTDIR", config.SoongOutDir()) + var ninjaEnv Environment + + // This is currently how the command line to invoke soong_build finds the + // root of the source tree and the output root + ninjaEnv.Set("TOP", os.Getenv("TOP")) + ninjaEnv.Set("SOONG_OUTDIR", config.SoongOutDir()) + + // For debugging if os.Getenv("SOONG_DELVE") != "" { - // SOONG_DELVE is already in cmd.Environment - cmd.Environment.Set("SOONG_DELVE_PATH", shared.ResolveDelveBinary()) + ninjaEnv.Set("SOONG_DELVE", os.Getenv("SOONG_DELVE")) + ninjaEnv.Set("SOONG_DELVE_PATH", shared.ResolveDelveBinary()) } + cmd.Environment = &ninjaEnv cmd.Sandbox = soongSandbox cmd.RunAndStreamOrFatal() } diff --git a/vnames.go.json b/vnames.go.json deleted file mode 100644 index f8c6b7fbc..000000000 --- a/vnames.go.json +++ /dev/null @@ -1,8 +0,0 @@ -[ - { - "pattern": "(.*)", - "vname": { - "path": "@1@" - } - } -] |