diff --git a/Android.bp b/Android.bp index 1d2c5167f..00db8f2da 100644 --- a/Android.bp +++ b/Android.bp @@ -71,6 +71,7 @@ bootstrap_go_package { "android/config_test.go", "android/expand_test.go", "android/namespace_test.go", + "android/neverallow_test.go", "android/paths_test.go", "android/prebuilt_test.go", "android/util_test.go", diff --git a/android/namespace_test.go b/android/namespace_test.go index a6fc9d592..8bec0add1 100644 --- a/android/namespace_test.go +++ b/android/namespace_test.go @@ -628,7 +628,7 @@ func setupTestExpectErrs(bps map[string]string) (ctx *TestContext, errs []error) func setupTest(t *testing.T, bps map[string]string) (ctx *TestContext) { ctx, errs := setupTestExpectErrs(bps) - failIfErrored(t, errs) + FailIfErrored(t, errs) return ctx } @@ -692,12 +692,3 @@ func newTestModule() Module { InitAndroidModule(m) return m } - -func failIfErrored(t *testing.T, errs []error) { - if len(errs) > 0 { - for _, err := range errs { - t.Error(err) - } - t.FailNow() - } -} diff --git a/android/neverallow.go b/android/neverallow.go index 3c6c0041a..ec440d5cc 100644 --- a/android/neverallow.go +++ b/android/neverallow.go @@ -46,9 +46,15 @@ func registerNeverallowMutator(ctx RegisterMutatorsContext) { } var neverallows = []*rule{ - neverallow().in("vendor", "device").with("vndk.enabled", "true"). + neverallow(). + in("vendor", "device"). + with("vndk.enabled", "true"). + without("vendor", "true"). because("the VNDK can never contain a library that is device dependent."), - neverallow().with("vndk.enabled", "true").without("owner", ""). + neverallow(). + with("vndk.enabled", "true"). + without("vendor", "true"). + without("owner", ""). because("a VNDK module can never have an owner."), neverallow().notIn("libcore", "development").with("no_standard_libs", "true"), diff --git a/android/neverallow_test.go b/android/neverallow_test.go new file mode 100644 index 000000000..a27836543 --- /dev/null +++ b/android/neverallow_test.go @@ -0,0 +1,217 @@ +// Copyright 2018 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 ( + "io/ioutil" + "os" + "testing" +) + +var neverallowTests = []struct { + name string + fs map[string][]byte + expectedError string +}{ + { + name: "no vndk.enabled under vendor directory", + fs: map[string][]byte{ + "vendor/Blueprints": []byte(` + cc_library { + name: "libvndk", + vendor_available: true, + vndk: { + enabled: true, + }, + }`), + }, + expectedError: "VNDK can never contain a library that is device dependent", + }, + { + name: "no vndk.enabled under device directory", + fs: map[string][]byte{ + "device/Blueprints": []byte(` + cc_library { + name: "libvndk", + vendor_available: true, + vndk: { + enabled: true, + }, + }`), + }, + expectedError: "VNDK can never contain a library that is device dependent", + }, + { + name: "vndk-ext under vendor or device directory", + fs: map[string][]byte{ + "device/Blueprints": []byte(` + cc_library { + name: "libvndk1_ext", + vendor: true, + vndk: { + enabled: true, + }, + }`), + "vendor/Blueprints": []byte(` + cc_library { + name: "libvndk2_ext", + vendor: true, + vndk: { + enabled: true, + }, + }`), + }, + expectedError: "", + }, + + { + name: "no enforce_vintf_manifest.cflags", + fs: map[string][]byte{ + "Blueprints": []byte(` + cc_library { + name: "libexample", + product_variables: { + enforce_vintf_manifest: { + cflags: ["-DSHOULD_NOT_EXIST"], + }, + }, + }`), + }, + expectedError: "manifest enforcement should be independent", + }, + { + name: "libhidltransport enforce_vintf_manifest.cflags", + fs: map[string][]byte{ + "Blueprints": []byte(` + cc_library { + name: "libhidltransport", + product_variables: { + enforce_vintf_manifest: { + cflags: ["-DSHOULD_NOT_EXIST"], + }, + }, + }`), + }, + expectedError: "", + }, + + { + name: "no treble_linker_namespaces.cflags", + fs: map[string][]byte{ + "Blueprints": []byte(` + cc_library { + name: "libexample", + product_variables: { + treble_linker_namespaces: { + cflags: ["-DSHOULD_NOT_EXIST"], + }, + }, + }`), + }, + expectedError: "nothing should care if linker namespaces are enabled or not", + }, + { + name: "libc_bionic_ndk treble_linker_namespaces.cflags", + fs: map[string][]byte{ + "Blueprints": []byte(` + cc_library { + name: "libc_bionic_ndk", + product_variables: { + treble_linker_namespaces: { + cflags: ["-DSHOULD_NOT_EXIST"], + }, + }, + }`), + }, + expectedError: "", + }, +} + +func TestNeverallow(t *testing.T) { + buildDir, err := ioutil.TempDir("", "soong_neverallow_test") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(buildDir) + + config := TestConfig(buildDir, nil) + + for _, test := range neverallowTests { + t.Run(test.name, func(t *testing.T) { + _, errs := testNeverallow(t, config, test.fs) + + if test.expectedError == "" { + FailIfErrored(t, errs) + } else { + FailIfNoMatchingErrors(t, test.expectedError, errs) + } + }) + } +} + +func testNeverallow(t *testing.T, config Config, fs map[string][]byte) (*TestContext, []error) { + ctx := NewTestContext() + ctx.RegisterModuleType("cc_library", ModuleFactoryAdaptor(newMockCcLibraryModule)) + ctx.PostDepsMutators(registerNeverallowMutator) + ctx.Register() + + ctx.MockFileSystem(fs) + + _, errs := ctx.ParseBlueprintsFiles("Blueprints") + if len(errs) > 0 { + return ctx, errs + } + + _, errs = ctx.PrepareBuildActions(config) + return ctx, errs +} + +type mockProperties struct { + Vendor_available *bool + + Vndk struct { + Enabled *bool + Support_system_process *bool + Extends *string + } + + Product_variables struct { + Enforce_vintf_manifest struct { + Cflags []string + } + + Treble_linker_namespaces struct { + Cflags []string + } + } +} + +type mockCcLibraryModule struct { + ModuleBase + properties mockProperties +} + +func newMockCcLibraryModule() Module { + m := &mockCcLibraryModule{} + m.AddProperties(&m.properties) + InitAndroidModule(m) + return m +} + +func (p *mockCcLibraryModule) DepsMutator(ctx BottomUpMutatorContext) { +} + +func (p *mockCcLibraryModule) GenerateAndroidBuildActions(ModuleContext) { +} diff --git a/android/prebuilt_test.go b/android/prebuilt_test.go index 93f580535..69ce16a3c 100644 --- a/android/prebuilt_test.go +++ b/android/prebuilt_test.go @@ -138,9 +138,9 @@ func TestPrebuilts(t *testing.T) { }) _, errs := ctx.ParseBlueprintsFiles("Blueprints") - fail(t, errs) + FailIfErrored(t, errs) _, errs = ctx.PrepareBuildActions(config) - fail(t, errs) + FailIfErrored(t, errs) foo := ctx.ModuleForTests("foo", "") @@ -231,12 +231,3 @@ func (s *sourceModule) DepsMutator(ctx BottomUpMutatorContext) { func (s *sourceModule) GenerateAndroidBuildActions(ctx ModuleContext) { } - -func fail(t *testing.T, errs []error) { - if len(errs) > 0 { - for _, err := range errs { - t.Error(err) - } - t.FailNow() - } -} diff --git a/android/testing.go b/android/testing.go index ae012b06e..f5d33e11a 100644 --- a/android/testing.go +++ b/android/testing.go @@ -17,7 +17,9 @@ package android import ( "fmt" "path/filepath" + "regexp" "strings" + "testing" "github.com/google/blueprint" ) @@ -152,3 +154,36 @@ func (m TestingModule) Output(file string) BuildParams { panic(fmt.Errorf("couldn't find output %q.\nall outputs: %v", file, searchedOutputs)) } + +func FailIfErrored(t *testing.T, errs []error) { + t.Helper() + if len(errs) > 0 { + for _, err := range errs { + t.Error(err) + } + t.FailNow() + } +} + +func FailIfNoMatchingErrors(t *testing.T, pattern string, errs []error) { + t.Helper() + + matcher, err := regexp.Compile(pattern) + if err != nil { + t.Errorf("failed to compile regular expression %q because %s", pattern, err) + } + + found := false + for _, err := range errs { + if matcher.FindStringIndex(err.Error()) != nil { + found = true + break + } + } + if !found { + t.Errorf("missing the expected error %q (checked %d error(s))", pattern, len(errs)) + for i, err := range errs { + t.Errorf("errs[%d] = %s", i, err) + } + } +} diff --git a/cc/cc_test.go b/cc/cc_test.go index 19e4703b3..2efee59d6 100644 --- a/cc/cc_test.go +++ b/cc/cc_test.go @@ -22,7 +22,6 @@ import ( "io/ioutil" "os" "reflect" - "regexp" "sort" "strings" "testing" @@ -147,9 +146,9 @@ func testCcWithConfig(t *testing.T, bp string, config android.Config) *android.T ctx := createTestContext(t, config, bp) _, errs := ctx.ParseFileList(".", []string{"Android.bp"}) - failIfErrored(t, errs) + android.FailIfErrored(t, errs) _, errs = ctx.PrepareBuildActions(config) - failIfErrored(t, errs) + android.FailIfErrored(t, errs) return ctx } @@ -178,13 +177,13 @@ func testCcError(t *testing.T, pattern string, bp string) { _, errs := ctx.ParseFileList(".", []string{"Android.bp"}) if len(errs) > 0 { - failIfNoMatchingErrors(t, pattern, errs) + android.FailIfNoMatchingErrors(t, pattern, errs) return } _, errs = ctx.PrepareBuildActions(config) if len(errs) > 0 { - failIfNoMatchingErrors(t, pattern, errs) + android.FailIfNoMatchingErrors(t, pattern, errs) return } @@ -1064,38 +1063,6 @@ func TestLinkReordering(t *testing.T) { } } -func failIfErrored(t *testing.T, errs []error) { - if len(errs) > 0 { - for _, err := range errs { - t.Error(err) - } - t.FailNow() - } -} - -func failIfNoMatchingErrors(t *testing.T, pattern string, errs []error) { - matcher, err := regexp.Compile(pattern) - if err != nil { - t.Errorf("failed to compile regular expression %q because %s", pattern, err) - } - - found := false - - for _, err := range errs { - if matcher.FindStringIndex(err.Error()) != nil { - found = true - break - } - } - - if !found { - t.Errorf("missing the expected error %q (checked %d error(s))", pattern, len(errs)) - for i, err := range errs { - t.Errorf("errs[%d] = %s", i, err) - } - } -} - func getOutputPaths(ctx *android.TestContext, variant string, moduleNames []string) (paths android.Paths) { for _, moduleName := range moduleNames { module := ctx.ModuleForTests(moduleName, variant).Module().(*Module) diff --git a/cc/test_data_test.go b/cc/test_data_test.go index 434edcdf6..4a7b0f756 100644 --- a/cc/test_data_test.go +++ b/cc/test_data_test.go @@ -135,9 +135,9 @@ func TestDataTests(t *testing.T) { ctx.Register() _, errs := ctx.ParseBlueprintsFiles("Blueprints") - fail(t, errs) + android.FailIfErrored(t, errs) _, errs = ctx.PrepareBuildActions(config) - fail(t, errs) + android.FailIfErrored(t, errs) foo := ctx.ModuleForTests("foo", "") @@ -186,12 +186,3 @@ func (test *testDataTest) DepsMutator(ctx android.BottomUpMutatorContext) { func (test *testDataTest) GenerateAndroidBuildActions(ctx android.ModuleContext) { test.data = ctx.ExpandSources(test.Properties.Data, nil) } - -func fail(t *testing.T, errs []error) { - if len(errs) > 0 { - for _, err := range errs { - t.Error(err) - } - t.FailNow() - } -} diff --git a/java/java_test.go b/java/java_test.go index 5d6a6e0e8..6ef406f76 100644 --- a/java/java_test.go +++ b/java/java_test.go @@ -190,9 +190,9 @@ func testContext(config android.Config, bp string, func run(t *testing.T, ctx *android.TestContext, config android.Config) { t.Helper() _, errs := ctx.ParseFileList(".", []string{"Android.bp"}) - fail(t, errs) + android.FailIfErrored(t, errs) _, errs = ctx.PrepareBuildActions(config) - fail(t, errs) + android.FailIfErrored(t, errs) } func testJava(t *testing.T, bp string) *android.TestContext { @@ -977,13 +977,3 @@ func TestExcludeFileGroupInSrcs(t *testing.T) { t.Errorf(`foo inputs %v != ["java-fg/c.java"]`, javac.Inputs) } } - -func fail(t *testing.T, errs []error) { - t.Helper() - if len(errs) > 0 { - for _, err := range errs { - t.Error(err) - } - t.FailNow() - } -} diff --git a/python/python_test.go b/python/python_test.go index 67b19827c..9ef6cb097 100644 --- a/python/python_test.go +++ b/python/python_test.go @@ -342,7 +342,7 @@ func TestPythonModule(t *testing.T) { ctx.Register() ctx.MockFileSystem(d.mockFiles) _, testErrs := ctx.ParseBlueprintsFiles(bpFile) - fail(t, testErrs) + android.FailIfErrored(t, testErrs) _, actErrs := ctx.PrepareBuildActions(config) if len(actErrs) > 0 { testErrs = append(testErrs, expectErrors(t, actErrs, d.errors)...) @@ -356,7 +356,7 @@ func TestPythonModule(t *testing.T) { e.depsSrcsZips)...) } } - fail(t, testErrs) + android.FailIfErrored(t, testErrs) }) } } @@ -442,12 +442,3 @@ func setupBuildEnv(t *testing.T) (config android.Config, buildDir string) { func tearDownBuildEnv(buildDir string) { os.RemoveAll(buildDir) } - -func fail(t *testing.T, errs []error) { - if len(errs) > 0 { - for _, err := range errs { - t.Error(err) - } - t.FailNow() - } -}