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/neverallow_test.go b/android/neverallow_test.go new file mode 100644 index 000000000..19eeb222d --- /dev/null +++ b/android/neverallow_test.go @@ -0,0 +1,195 @@ +// 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: "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/testing.go b/android/testing.go index 6e80c5326..f5d33e11a 100644 --- a/android/testing.go +++ b/android/testing.go @@ -17,6 +17,7 @@ package android import ( "fmt" "path/filepath" + "regexp" "strings" "testing" @@ -163,3 +164,26 @@ func FailIfErrored(t *testing.T, errs []error) { 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 632960568..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" @@ -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,29 +1063,6 @@ func TestLinkReordering(t *testing.T) { } } -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)