123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703 |
- // Copyright 2019 Google Inc. All rights reserved.
- //
- // Licensed under the Apache License, Version 2.0 (the "License");
- // you may not use this file except in compliance with the License.
- // You may obtain a copy of the License at
- //
- // http://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing, software
- // distributed under the License is distributed on an "AS IS" BASIS,
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- // See the License for the specific language governing permissions and
- // limitations under the License.
- package android
- import (
- "fmt"
- "path/filepath"
- "testing"
- )
- type soongConfigTestDefaultsModule struct {
- ModuleBase
- DefaultsModuleBase
- }
- func soongConfigTestDefaultsModuleFactory() Module {
- m := &soongConfigTestDefaultsModule{}
- m.AddProperties(&soongConfigTestModuleProperties{})
- InitDefaultsModule(m)
- return m
- }
- type soongConfigTestModule struct {
- ModuleBase
- DefaultableModuleBase
- props soongConfigTestModuleProperties
- outputPath ModuleOutPath
- }
- type soongConfigTestModuleProperties struct {
- Cflags []string
- }
- func soongConfigTestModuleFactory() Module {
- m := &soongConfigTestModule{}
- m.AddProperties(&m.props)
- InitAndroidModule(m)
- InitDefaultableModule(m)
- return m
- }
- func (t *soongConfigTestModule) GenerateAndroidBuildActions(ctx ModuleContext) {
- t.outputPath = PathForModuleOut(ctx, "test")
- }
- var prepareForSoongConfigTestModule = FixtureRegisterWithContext(func(ctx RegistrationContext) {
- ctx.RegisterModuleType("test_defaults", soongConfigTestDefaultsModuleFactory)
- ctx.RegisterModuleType("test", soongConfigTestModuleFactory)
- })
- func TestSoongConfigModule(t *testing.T) {
- configBp := `
- soong_config_module_type {
- name: "acme_test",
- module_type: "test",
- config_namespace: "acme",
- variables: ["board", "feature1", "FEATURE3", "unused_string_var"],
- bool_variables: ["feature2", "unused_feature", "always_true"],
- value_variables: ["size", "unused_size"],
- properties: ["cflags", "srcs", "defaults"],
- }
- soong_config_string_variable {
- name: "board",
- values: ["soc_a", "soc_b", "soc_c", "soc_d"],
- }
- soong_config_string_variable {
- name: "unused_string_var",
- values: ["a", "b"],
- }
- soong_config_bool_variable {
- name: "feature1",
- }
- soong_config_bool_variable {
- name: "FEATURE3",
- }
- `
- importBp := `
- soong_config_module_type_import {
- from: "SoongConfig.bp",
- module_types: ["acme_test"],
- }
- `
- bp := `
- test_defaults {
- name: "foo_defaults",
- cflags: ["DEFAULT"],
- }
- acme_test {
- name: "foo",
- cflags: ["-DGENERIC"],
- defaults: ["foo_defaults"],
- soong_config_variables: {
- board: {
- soc_a: {
- cflags: ["-DSOC_A"],
- },
- soc_b: {
- cflags: ["-DSOC_B"],
- },
- soc_c: {},
- conditions_default: {
- cflags: ["-DSOC_CONDITIONS_DEFAULT"],
- },
- },
- size: {
- cflags: ["-DSIZE=%s"],
- conditions_default: {
- cflags: ["-DSIZE=CONDITIONS_DEFAULT"],
- },
- },
- feature1: {
- conditions_default: {
- cflags: ["-DF1_CONDITIONS_DEFAULT"],
- },
- cflags: ["-DFEATURE1"],
- },
- feature2: {
- cflags: ["-DFEATURE2"],
- conditions_default: {
- cflags: ["-DF2_CONDITIONS_DEFAULT"],
- },
- },
- FEATURE3: {
- cflags: ["-DFEATURE3"],
- },
- },
- }
- test_defaults {
- name: "foo_defaults_a",
- cflags: ["DEFAULT_A"],
- }
- test_defaults {
- name: "foo_defaults_b",
- cflags: ["DEFAULT_B"],
- }
- test_defaults {
- name: "foo_defaults_always_true",
- cflags: ["DEFAULT_ALWAYS_TRUE"],
- }
- acme_test {
- name: "foo_with_defaults",
- cflags: ["-DGENERIC"],
- defaults: ["foo_defaults"],
- soong_config_variables: {
- board: {
- soc_a: {
- cflags: ["-DSOC_A"],
- defaults: ["foo_defaults_a"],
- },
- soc_b: {
- cflags: ["-DSOC_B"],
- defaults: ["foo_defaults_b"],
- },
- soc_c: {},
- },
- size: {
- cflags: ["-DSIZE=%s"],
- },
- feature1: {
- cflags: ["-DFEATURE1"],
- },
- feature2: {
- cflags: ["-DFEATURE2"],
- },
- FEATURE3: {
- cflags: ["-DFEATURE3"],
- },
- always_true: {
- defaults: ["foo_defaults_always_true"],
- conditions_default: {
- // verify that conditions_default is skipped if the
- // soong config variable is true by specifying a
- // non-existent module in conditions_default
- defaults: ["//nonexistent:defaults"],
- }
- },
- },
- }
- `
- fixtureForVendorVars := func(vars map[string]map[string]string) FixturePreparer {
- return FixtureModifyProductVariables(func(variables FixtureProductVariables) {
- variables.VendorVars = vars
- })
- }
- run := func(t *testing.T, bp string, fs MockFS) {
- testCases := []struct {
- name string
- preparer FixturePreparer
- fooExpectedFlags []string
- fooDefaultsExpectedFlags []string
- }{
- {
- name: "withValues",
- preparer: fixtureForVendorVars(map[string]map[string]string{
- "acme": {
- "board": "soc_a",
- "size": "42",
- "feature1": "true",
- "feature2": "false",
- // FEATURE3 unset
- "unused_feature": "true", // unused
- "unused_size": "1", // unused
- "unused_string_var": "a", // unused
- "always_true": "true",
- },
- }),
- fooExpectedFlags: []string{
- "DEFAULT",
- "-DGENERIC",
- "-DF2_CONDITIONS_DEFAULT",
- "-DSIZE=42",
- "-DSOC_A",
- "-DFEATURE1",
- },
- fooDefaultsExpectedFlags: []string{
- "DEFAULT_A",
- "DEFAULT_ALWAYS_TRUE",
- "DEFAULT",
- "-DGENERIC",
- "-DSIZE=42",
- "-DSOC_A",
- "-DFEATURE1",
- },
- },
- {
- name: "empty_prop_for_string_var",
- preparer: fixtureForVendorVars(map[string]map[string]string{
- "acme": {
- "board": "soc_c",
- "always_true": "true",
- }}),
- fooExpectedFlags: []string{
- "DEFAULT",
- "-DGENERIC",
- "-DF2_CONDITIONS_DEFAULT",
- "-DSIZE=CONDITIONS_DEFAULT",
- "-DF1_CONDITIONS_DEFAULT",
- },
- fooDefaultsExpectedFlags: []string{
- "DEFAULT_ALWAYS_TRUE",
- "DEFAULT",
- "-DGENERIC",
- },
- },
- {
- name: "unused_string_var",
- preparer: fixtureForVendorVars(map[string]map[string]string{
- "acme": {
- "board": "soc_d",
- "always_true": "true",
- }}),
- fooExpectedFlags: []string{
- "DEFAULT",
- "-DGENERIC",
- "-DF2_CONDITIONS_DEFAULT",
- "-DSIZE=CONDITIONS_DEFAULT",
- "-DSOC_CONDITIONS_DEFAULT", // foo does not contain a prop "soc_d", so we use the default
- "-DF1_CONDITIONS_DEFAULT",
- },
- fooDefaultsExpectedFlags: []string{
- "DEFAULT_ALWAYS_TRUE",
- "DEFAULT",
- "-DGENERIC",
- },
- },
- {
- name: "conditions_default",
- preparer: fixtureForVendorVars(map[string]map[string]string{
- "acme": {
- "always_true": "true",
- }}),
- fooExpectedFlags: []string{
- "DEFAULT",
- "-DGENERIC",
- "-DF2_CONDITIONS_DEFAULT",
- "-DSIZE=CONDITIONS_DEFAULT",
- "-DSOC_CONDITIONS_DEFAULT",
- "-DF1_CONDITIONS_DEFAULT",
- },
- fooDefaultsExpectedFlags: []string{
- "DEFAULT_ALWAYS_TRUE",
- "DEFAULT",
- "-DGENERIC",
- },
- },
- }
- for _, tc := range testCases {
- t.Run(tc.name, func(t *testing.T) {
- result := GroupFixturePreparers(
- tc.preparer,
- PrepareForTestWithDefaults,
- PrepareForTestWithSoongConfigModuleBuildComponents,
- prepareForSoongConfigTestModule,
- fs.AddToFixture(),
- FixtureWithRootAndroidBp(bp),
- ).RunTest(t)
- foo := result.ModuleForTests("foo", "").Module().(*soongConfigTestModule)
- AssertDeepEquals(t, "foo cflags", tc.fooExpectedFlags, foo.props.Cflags)
- fooDefaults := result.ModuleForTests("foo_with_defaults", "").Module().(*soongConfigTestModule)
- AssertDeepEquals(t, "foo_with_defaults cflags", tc.fooDefaultsExpectedFlags, fooDefaults.props.Cflags)
- })
- }
- }
- t.Run("single file", func(t *testing.T) {
- run(t, configBp+bp, nil)
- })
- t.Run("import", func(t *testing.T) {
- run(t, importBp+bp, map[string][]byte{
- "SoongConfig.bp": []byte(configBp),
- })
- })
- }
- func TestNonExistentPropertyInSoongConfigModule(t *testing.T) {
- bp := `
- soong_config_module_type {
- name: "acme_test",
- module_type: "test",
- config_namespace: "acme",
- bool_variables: ["feature1"],
- properties: ["made_up_property"],
- }
- acme_test {
- name: "foo",
- cflags: ["-DGENERIC"],
- soong_config_variables: {
- feature1: {
- made_up_property: true,
- },
- },
- }
- `
- fixtureForVendorVars := func(vars map[string]map[string]string) FixturePreparer {
- return FixtureModifyProductVariables(func(variables FixtureProductVariables) {
- variables.VendorVars = vars
- })
- }
- GroupFixturePreparers(
- fixtureForVendorVars(map[string]map[string]string{"acme": {"feature1": "1"}}),
- PrepareForTestWithDefaults,
- PrepareForTestWithSoongConfigModuleBuildComponents,
- prepareForSoongConfigTestModule,
- FixtureWithRootAndroidBp(bp),
- ).ExtendWithErrorHandler(FixtureExpectsAllErrorsToMatchAPattern([]string{
- // TODO(b/171232169): improve the error message for non-existent properties
- `unrecognized property "soong_config_variables`,
- })).RunTest(t)
- }
- func TestDuplicateStringValueInSoongConfigStringVariable(t *testing.T) {
- bp := `
- soong_config_string_variable {
- name: "board",
- values: ["soc_a", "soc_b", "soc_c", "soc_a"],
- }
- soong_config_module_type {
- name: "acme_test",
- module_type: "test",
- config_namespace: "acme",
- variables: ["board"],
- properties: ["cflags", "srcs", "defaults"],
- }
- `
- fixtureForVendorVars := func(vars map[string]map[string]string) FixturePreparer {
- return FixtureModifyProductVariables(func(variables FixtureProductVariables) {
- variables.VendorVars = vars
- })
- }
- GroupFixturePreparers(
- fixtureForVendorVars(map[string]map[string]string{"acme": {"feature1": "1"}}),
- PrepareForTestWithDefaults,
- PrepareForTestWithSoongConfigModuleBuildComponents,
- prepareForSoongConfigTestModule,
- FixtureWithRootAndroidBp(bp),
- ).ExtendWithErrorHandler(FixtureExpectsAllErrorsToMatchAPattern([]string{
- // TODO(b/171232169): improve the error message for non-existent properties
- `Android.bp: soong_config_string_variable: values property error: duplicate value: "soc_a"`,
- })).RunTest(t)
- }
- type soongConfigTestSingletonModule struct {
- SingletonModuleBase
- props soongConfigTestSingletonModuleProperties
- }
- type soongConfigTestSingletonModuleProperties struct {
- Fragments []struct {
- Apex string
- Module string
- }
- }
- func soongConfigTestSingletonModuleFactory() SingletonModule {
- m := &soongConfigTestSingletonModule{}
- m.AddProperties(&m.props)
- InitAndroidModule(m)
- return m
- }
- func (t *soongConfigTestSingletonModule) GenerateAndroidBuildActions(ModuleContext) {}
- func (t *soongConfigTestSingletonModule) GenerateSingletonBuildActions(SingletonContext) {}
- var prepareForSoongConfigTestSingletonModule = FixtureRegisterWithContext(func(ctx RegistrationContext) {
- ctx.RegisterSingletonModuleType("test_singleton", soongConfigTestSingletonModuleFactory)
- })
- func TestSoongConfigModuleSingletonModule(t *testing.T) {
- bp := `
- soong_config_module_type {
- name: "acme_test_singleton",
- module_type: "test_singleton",
- config_namespace: "acme",
- bool_variables: ["coyote"],
- properties: ["fragments"],
- }
- acme_test_singleton {
- name: "wiley",
- fragments: [
- {
- apex: "com.android.acme",
- module: "road-runner",
- },
- ],
- soong_config_variables: {
- coyote: {
- fragments: [
- {
- apex: "com.android.acme",
- module: "wiley",
- },
- ],
- },
- },
- }
- `
- for _, test := range []struct {
- coyote bool
- expectedFragments string
- }{
- {
- coyote: false,
- expectedFragments: "[{Apex:com.android.acme Module:road-runner}]",
- },
- {
- coyote: true,
- expectedFragments: "[{Apex:com.android.acme Module:road-runner} {Apex:com.android.acme Module:wiley}]",
- },
- } {
- t.Run(fmt.Sprintf("coyote:%t", test.coyote), func(t *testing.T) {
- result := GroupFixturePreparers(
- PrepareForTestWithSoongConfigModuleBuildComponents,
- prepareForSoongConfigTestSingletonModule,
- FixtureWithRootAndroidBp(bp),
- FixtureModifyProductVariables(func(variables FixtureProductVariables) {
- variables.VendorVars = map[string]map[string]string{
- "acme": {
- "coyote": fmt.Sprintf("%t", test.coyote),
- },
- }
- }),
- ).RunTest(t)
- // Make sure that the singleton was created.
- result.SingletonForTests("test_singleton")
- m := result.ModuleForTests("wiley", "").module.(*soongConfigTestSingletonModule)
- AssertStringEquals(t, "fragments", test.expectedFragments, fmt.Sprintf("%+v", m.props.Fragments))
- })
- }
- }
- func TestSoongConfigModuleTrace(t *testing.T) {
- bp := `
- soong_config_module_type {
- name: "acme_test",
- module_type: "test",
- config_namespace: "acme",
- variables: ["board", "feature1", "FEATURE3", "unused_string_var"],
- bool_variables: ["feature2", "unused_feature", "always_true"],
- value_variables: ["size", "unused_size"],
- properties: ["cflags", "srcs", "defaults"],
- }
- soong_config_module_type {
- name: "acme_test_defaults",
- module_type: "test_defaults",
- config_namespace: "acme",
- variables: ["board", "feature1", "FEATURE3", "unused_string_var"],
- bool_variables: ["feature2", "unused_feature", "always_true"],
- value_variables: ["size", "unused_size"],
- properties: ["cflags", "srcs", "defaults"],
- }
- soong_config_string_variable {
- name: "board",
- values: ["soc_a", "soc_b", "soc_c"],
- }
- soong_config_string_variable {
- name: "unused_string_var",
- values: ["a", "b"],
- }
- soong_config_bool_variable {
- name: "feature1",
- }
- soong_config_bool_variable {
- name: "FEATURE3",
- }
- test_defaults {
- name: "test_defaults",
- cflags: ["DEFAULT"],
- }
- test {
- name: "normal",
- defaults: ["test_defaults"],
- }
- acme_test {
- name: "board_1",
- defaults: ["test_defaults"],
- soong_config_variables: {
- board: {
- soc_a: {
- cflags: ["-DSOC_A"],
- },
- },
- },
- }
- acme_test {
- name: "board_2",
- defaults: ["test_defaults"],
- soong_config_variables: {
- board: {
- soc_a: {
- cflags: ["-DSOC_A"],
- },
- },
- },
- }
- acme_test {
- name: "size",
- defaults: ["test_defaults"],
- soong_config_variables: {
- size: {
- cflags: ["-DSIZE=%s"],
- },
- },
- }
- acme_test {
- name: "board_and_size",
- defaults: ["test_defaults"],
- soong_config_variables: {
- board: {
- soc_a: {
- cflags: ["-DSOC_A"],
- },
- },
- size: {
- cflags: ["-DSIZE=%s"],
- },
- },
- }
- acme_test_defaults {
- name: "board_defaults",
- soong_config_variables: {
- board: {
- soc_a: {
- cflags: ["-DSOC_A"],
- },
- },
- },
- }
- acme_test_defaults {
- name: "size_defaults",
- soong_config_variables: {
- size: {
- cflags: ["-DSIZE=%s"],
- },
- },
- }
- test {
- name: "board_and_size_with_defaults",
- defaults: ["board_defaults", "size_defaults"],
- }
- `
- fixtureForVendorVars := func(vars map[string]map[string]string) FixturePreparer {
- return FixtureModifyProductVariables(func(variables FixtureProductVariables) {
- variables.VendorVars = vars
- })
- }
- preparer := fixtureForVendorVars(map[string]map[string]string{
- "acme": {
- "board": "soc_a",
- "size": "42",
- "feature1": "true",
- "feature2": "false",
- // FEATURE3 unset
- "unused_feature": "true", // unused
- "unused_size": "1", // unused
- "unused_string_var": "a", // unused
- "always_true": "true",
- },
- })
- t.Run("soong config trace hash", func(t *testing.T) {
- result := GroupFixturePreparers(
- preparer,
- PrepareForTestWithDefaults,
- PrepareForTestWithSoongConfigModuleBuildComponents,
- prepareForSoongConfigTestModule,
- FixtureRegisterWithContext(func(ctx RegistrationContext) {
- ctx.FinalDepsMutators(registerSoongConfigTraceMutator)
- }),
- FixtureWithRootAndroidBp(bp),
- ).RunTest(t)
- // Hashes of modules not using soong config should be empty
- normal := result.ModuleForTests("normal", "").Module().(*soongConfigTestModule)
- AssertDeepEquals(t, "normal hash", normal.base().commonProperties.SoongConfigTraceHash, "")
- AssertDeepEquals(t, "normal hash out", normal.outputPath.RelativeToTop().String(), "out/soong/.intermediates/normal/test")
- board1 := result.ModuleForTests("board_1", "").Module().(*soongConfigTestModule)
- board2 := result.ModuleForTests("board_2", "").Module().(*soongConfigTestModule)
- size := result.ModuleForTests("size", "").Module().(*soongConfigTestModule)
- // Trace mutator sets soong config trace hash correctly
- board1Hash := board1.base().commonProperties.SoongConfigTrace.hash()
- board1Output := board1.outputPath.RelativeToTop().String()
- AssertDeepEquals(t, "board hash calc", board1Hash, board1.base().commonProperties.SoongConfigTraceHash)
- AssertDeepEquals(t, "board hash path", board1Output, filepath.Join("out/soong/.intermediates/board_1", board1Hash, "test"))
- sizeHash := size.base().commonProperties.SoongConfigTrace.hash()
- sizeOutput := size.outputPath.RelativeToTop().String()
- AssertDeepEquals(t, "size hash calc", sizeHash, size.base().commonProperties.SoongConfigTraceHash)
- AssertDeepEquals(t, "size hash path", sizeOutput, filepath.Join("out/soong/.intermediates/size", sizeHash, "test"))
- // Trace should be identical for modules using the same set of variables
- AssertDeepEquals(t, "board trace", board1.base().commonProperties.SoongConfigTrace, board2.base().commonProperties.SoongConfigTrace)
- AssertDeepEquals(t, "board hash", board1.base().commonProperties.SoongConfigTraceHash, board2.base().commonProperties.SoongConfigTraceHash)
- // Trace hash should be different for different sets of soong variables
- AssertBoolEquals(t, "board hash not equal to size hash", board1.base().commonProperties.SoongConfigTraceHash == size.commonProperties.SoongConfigTraceHash, false)
- boardSize := result.ModuleForTests("board_and_size", "").Module().(*soongConfigTestModule)
- boardSizeDefaults := result.ModuleForTests("board_and_size_with_defaults", "").Module()
- // Trace should propagate
- AssertDeepEquals(t, "board_size hash calc", boardSize.base().commonProperties.SoongConfigTrace.hash(), boardSize.base().commonProperties.SoongConfigTraceHash)
- AssertDeepEquals(t, "board_size trace", boardSize.base().commonProperties.SoongConfigTrace, boardSizeDefaults.base().commonProperties.SoongConfigTrace)
- AssertDeepEquals(t, "board_size hash", boardSize.base().commonProperties.SoongConfigTraceHash, boardSizeDefaults.base().commonProperties.SoongConfigTraceHash)
- })
- }
|