diff options
author | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2024-01-10 18:43:21 +0000 |
---|---|---|
committer | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2024-01-10 18:43:21 +0000 |
commit | cf842918674ced70cfa9568615924cd1c9b469f2 (patch) | |
tree | 52c13b8caed332da12472d13f47aeb7dbc02b4cd | |
parent | 417e1f85b28181319d86bcb3f133f46f824fb475 (diff) | |
parent | 4025ba3d32954c1dd2c9fa736dbd18ecd4bacc1e (diff) | |
download | soong-aml_tz5_341510010.tar.gz |
Snap for 11296156 from 4025ba3d32954c1dd2c9fa736dbd18ecd4bacc1e to mainline-tzdata5-releaseaml_tz5_341510070aml_tz5_341510050aml_tz5_341510010aml_tz5_341510010
Change-Id: I3b061666a38fbbc6749d4dce27fd1b400eaecc98
-rw-r--r-- | apex/apex.go | 3 | ||||
-rw-r--r-- | apex/apex_test.go | 25 | ||||
-rw-r--r-- | cc/Android.bp | 1 | ||||
-rw-r--r-- | cc/cc.go | 11 | ||||
-rw-r--r-- | cc/fuzz.go | 1 | ||||
-rw-r--r-- | cc/test.go | 2 | ||||
-rw-r--r-- | java/Android.bp | 2 | ||||
-rwxr-xr-x | java/app.go | 2 | ||||
-rw-r--r-- | java/bootclasspath_fragment.go | 2 | ||||
-rw-r--r-- | java/java.go | 4 | ||||
-rw-r--r-- | java/robolectric.go | 2 | ||||
-rw-r--r-- | java/test_spec_test.go | 133 | ||||
-rw-r--r-- | python/Android.bp | 1 | ||||
-rw-r--r-- | python/test.go | 2 | ||||
-rw-r--r-- | rust/Android.bp | 1 | ||||
-rw-r--r-- | rust/rust.go | 9 | ||||
-rw-r--r-- | rust/test.go | 2 | ||||
-rw-r--r-- | sh/Android.bp | 1 | ||||
-rw-r--r-- | sh/sh_binary.go | 2 | ||||
-rw-r--r-- | testing/Android.bp | 21 | ||||
-rw-r--r-- | testing/all_test_specs.go | 45 | ||||
-rw-r--r-- | testing/init.go | 33 | ||||
-rw-r--r-- | testing/test.go | 21 | ||||
-rw-r--r-- | testing/test_spec.go | 127 | ||||
-rw-r--r-- | testing/test_spec_proto/Android.bp | 29 | ||||
-rw-r--r-- | testing/test_spec_proto/OWNERS | 4 | ||||
-rw-r--r-- | testing/test_spec_proto/go.mod | 2 | ||||
-rw-r--r-- | testing/test_spec_proto/regen.sh | 3 | ||||
-rw-r--r-- | testing/test_spec_proto/test_spec.pb.go | 244 | ||||
-rw-r--r-- | testing/test_spec_proto/test_spec.proto | 33 |
30 files changed, 760 insertions, 8 deletions
diff --git a/apex/apex.go b/apex/apex.go index fca09440f..1f2da5f1a 100644 --- a/apex/apex.go +++ b/apex/apex.go @@ -2217,6 +2217,9 @@ func (vctx *visitorContext) normalizeFileInfo(mctx android.ModuleContext) { // If a module is directly included and also transitively depended on // consider it as directly included. e.transitiveDep = e.transitiveDep && f.transitiveDep + // If a module is added as both a JNI library and a regular shared library, consider it as a + // JNI library. + e.isJniLib = e.isJniLib || f.isJniLib encountered[dest] = e } } diff --git a/apex/apex_test.go b/apex/apex_test.go index 2eb359329..38d9106f6 100644 --- a/apex/apex_test.go +++ b/apex/apex_test.go @@ -7843,7 +7843,8 @@ func TestApexWithJniLibs(t *testing.T) { apex { name: "myapex", key: "myapex.key", - jni_libs: ["mylib", "libfoo.rust"], + binaries: ["mybin"], + jni_libs: ["mylib", "mylib3", "libfoo.rust"], updatable: false, } @@ -7870,6 +7871,24 @@ func TestApexWithJniLibs(t *testing.T) { apex_available: [ "myapex" ], } + // Used as both a JNI library and a regular shared library. + cc_library { + name: "mylib3", + srcs: ["mylib.cpp"], + system_shared_libs: [], + stl: "none", + apex_available: [ "myapex" ], + } + + cc_binary { + name: "mybin", + srcs: ["mybin.cpp"], + shared_libs: ["mylib3"], + system_shared_libs: [], + stl: "none", + apex_available: [ "myapex" ], + } + rust_ffi_shared { name: "libfoo.rust", crate_name: "foo", @@ -7893,10 +7912,12 @@ func TestApexWithJniLibs(t *testing.T) { rule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexManifestRule") // Notice mylib2.so (transitive dep) is not added as a jni_lib - ensureEquals(t, rule.Args["opt"], "-a jniLibs libfoo.rust.so mylib.so") + ensureEquals(t, rule.Args["opt"], "-a jniLibs libfoo.rust.so mylib.so mylib3.so") ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{ + "bin/mybin", "lib64/mylib.so", "lib64/mylib2.so", + "lib64/mylib3.so", "lib64/libfoo.rust.so", "lib64/libc++.so", // auto-added to libfoo.rust by Soong "lib64/liblog.so", // auto-added to libfoo.rust by Soong diff --git a/cc/Android.bp b/cc/Android.bp index f49dc1a9e..b12bdceff 100644 --- a/cc/Android.bp +++ b/cc/Android.bp @@ -18,6 +18,7 @@ bootstrap_go_package { "soong-genrule", "soong-multitree", "soong-snapshot", + "soong-testing", "soong-tradefed", ], srcs: [ @@ -24,6 +24,7 @@ import ( "strconv" "strings" + "android/soong/testing" "github.com/google/blueprint" "github.com/google/blueprint/proptools" @@ -835,9 +836,10 @@ type Module struct { Properties BaseProperties // initialize before calling Init - hod android.HostOrDeviceSupported - multilib android.Multilib - bazelable bool + hod android.HostOrDeviceSupported + multilib android.Multilib + bazelable bool + testModule bool // Allowable SdkMemberTypes of this module type. sdkMemberTypes []android.SdkMemberType @@ -2104,6 +2106,9 @@ func (c *Module) GenerateAndroidBuildActions(actx android.ModuleContext) { } } } + if c.testModule { + ctx.SetProvider(testing.TestModuleProviderKey, testing.TestModuleProviderData{}) + } c.maybeInstall(ctx, apexInfo) } diff --git a/cc/fuzz.go b/cc/fuzz.go index 7aa8b91c7..452cf356a 100644 --- a/cc/fuzz.go +++ b/cc/fuzz.go @@ -95,6 +95,7 @@ func fuzzMutatorDeps(mctx android.TopDownMutatorContext) { // your device, or $ANDROID_PRODUCT_OUT/data/fuzz in your build tree. func LibFuzzFactory() android.Module { module := NewFuzzer(android.HostAndDeviceSupported) + module.testModule = true return module.Init() } diff --git a/cc/test.go b/cc/test.go index 27de06b07..db78d6c33 100644 --- a/cc/test.go +++ b/cc/test.go @@ -154,6 +154,7 @@ func TestLibraryFactory() android.Module { // binary. func BenchmarkFactory() android.Module { module := NewBenchmark(android.HostAndDeviceSupported) + module.testModule = true return module.Init() } @@ -482,6 +483,7 @@ func NewTest(hod android.HostOrDeviceSupported, bazelable bool) *Module { module, binary := newBinary(hod, bazelable) module.bazelable = bazelable module.multilib = android.MultilibBoth + module.testModule = true binary.baseInstaller = NewTestInstaller() test := &testBinary{ diff --git a/java/Android.bp b/java/Android.bp index 4af2a14eb..2ad7a7a30 100644 --- a/java/Android.bp +++ b/java/Android.bp @@ -15,6 +15,7 @@ bootstrap_go_package { "soong-dexpreopt", "soong-genrule", "soong-java-config", + "soong-testing", "soong-provenance", "soong-python", "soong-remoteexec", @@ -109,6 +110,7 @@ bootstrap_go_package { "sdk_library_test.go", "system_modules_test.go", "systemserver_classpath_fragment_test.go", + "test_spec_test.go", ], pluginFor: ["soong_build"], } diff --git a/java/app.go b/java/app.go index 254906d2e..e026feab5 100755 --- a/java/app.go +++ b/java/app.go @@ -21,6 +21,7 @@ import ( "path/filepath" "strings" + "android/soong/testing" "github.com/google/blueprint" "github.com/google/blueprint/proptools" @@ -1124,6 +1125,7 @@ func (a *AndroidTest) GenerateAndroidBuildActions(ctx android.ModuleContext) { a.testConfig = a.FixTestConfig(ctx, testConfig) a.extraTestConfigs = android.PathsForModuleSrc(ctx, a.testProperties.Test_options.Extra_test_configs) a.data = android.PathsForModuleSrc(ctx, a.testProperties.Data) + ctx.SetProvider(testing.TestModuleProviderKey, testing.TestModuleProviderData{}) } func (a *AndroidTest) FixTestConfig(ctx android.ModuleContext, testConfig android.Path) android.Path { diff --git a/java/bootclasspath_fragment.go b/java/bootclasspath_fragment.go index 108fdd483..f815954e4 100644 --- a/java/bootclasspath_fragment.go +++ b/java/bootclasspath_fragment.go @@ -23,6 +23,7 @@ import ( "android/soong/android" "android/soong/dexpreopt" + "android/soong/testing" "github.com/google/blueprint/proptools" @@ -564,6 +565,7 @@ func (b *BootclasspathFragmentModule) GenerateAndroidBuildActions(ctx android.Mo if ctx.Module() != ctx.FinalModule() { b.HideFromMake() } + ctx.SetProvider(testing.TestModuleProviderKey, testing.TestModuleProviderData{}) } // shouldCopyBootFilesToPredefinedLocations determines whether the current module should copy boot diff --git a/java/java.go b/java/java.go index 9161b2253..c8817e1cb 100644 --- a/java/java.go +++ b/java/java.go @@ -26,7 +26,7 @@ import ( "android/soong/bazel" "android/soong/bazel/cquery" "android/soong/remoteexec" - + "android/soong/testing" "github.com/google/blueprint" "github.com/google/blueprint/proptools" @@ -1199,10 +1199,12 @@ func (j *TestHost) GenerateAndroidBuildActions(ctx android.ModuleContext) { } j.Test.generateAndroidBuildActionsWithConfig(ctx, configs) + ctx.SetProvider(testing.TestModuleProviderKey, testing.TestModuleProviderData{}) } func (j *Test) GenerateAndroidBuildActions(ctx android.ModuleContext) { j.generateAndroidBuildActionsWithConfig(ctx, nil) + ctx.SetProvider(testing.TestModuleProviderKey, testing.TestModuleProviderData{}) } func (j *Test) generateAndroidBuildActionsWithConfig(ctx android.ModuleContext, configs []tradefed.Config) { diff --git a/java/robolectric.go b/java/robolectric.go index 008b8b1c9..f394006c4 100644 --- a/java/robolectric.go +++ b/java/robolectric.go @@ -22,6 +22,7 @@ import ( "android/soong/android" "android/soong/java/config" + "android/soong/testing" "android/soong/tradefed" "github.com/google/blueprint/proptools" @@ -235,6 +236,7 @@ func (r *robolectricTest) GenerateAndroidBuildActions(ctx android.ModuleContext) } r.installFile = ctx.InstallFile(installPath, ctx.ModuleName()+".jar", r.combinedJar, installDeps...) + ctx.SetProvider(testing.TestModuleProviderKey, testing.TestModuleProviderData{}) } func generateRoboTestConfig(ctx android.ModuleContext, outputFile android.WritablePath, diff --git a/java/test_spec_test.go b/java/test_spec_test.go new file mode 100644 index 000000000..39aff4cef --- /dev/null +++ b/java/test_spec_test.go @@ -0,0 +1,133 @@ +package java + +import ( + "strings" + "testing" + + "android/soong/android" + soongTesting "android/soong/testing" + "android/soong/testing/test_spec_proto" + "google.golang.org/protobuf/proto" +) + +func TestTestSpec(t *testing.T) { + bp := `test_spec { + name: "module-name", + teamId: "12345", + tests: [ + "java-test-module-name-one", + "java-test-module-name-two" + ] + } + + java_test { + name: "java-test-module-name-one", + } + + java_test { + name: "java-test-module-name-two", + }` + result := runTest(t, android.FixtureExpectsNoErrors, bp) + + module := result.ModuleForTests( + "module-name", "", + ).Module().(*soongTesting.TestSpecModule) + + // Check that the provider has the right contents + data := result.ModuleProvider( + module, soongTesting.TestSpecProviderKey, + ).(soongTesting.TestSpecProviderData) + if !strings.HasSuffix( + data.IntermediatePath.String(), "/intermediateTestSpecMetadata.pb", + ) { + t.Errorf( + "Missing intermediates path in provider: %s", + data.IntermediatePath.String(), + ) + } + + buildParamsSlice := module.BuildParamsForTests() + var metadata = "" + for _, params := range buildParamsSlice { + if params.Rule.String() == "android/soong/android.writeFile" { + metadata = params.Args["content"] + } + } + + metadataList := make([]*test_spec_proto.TestSpec_OwnershipMetadata, 0, 2) + teamId := "12345" + bpFilePath := "Android.bp" + targetNames := []string{ + "java-test-module-name-one", "java-test-module-name-two", + } + + for _, test := range targetNames { + targetName := test + metadata := test_spec_proto.TestSpec_OwnershipMetadata{ + TrendyTeamId: &teamId, + TargetName: &targetName, + Path: &bpFilePath, + } + metadataList = append(metadataList, &metadata) + } + testSpecMetadata := test_spec_proto.TestSpec{OwnershipMetadataList: metadataList} + protoData, _ := proto.Marshal(&testSpecMetadata) + rawData := string(protoData) + formattedData := strings.ReplaceAll(rawData, "\n", "\\n") + expectedMetadata := "'" + formattedData + "\\n'" + + if metadata != expectedMetadata { + t.Errorf( + "Retrieved metadata: %s is not equal to expectedMetadata: %s", metadata, + expectedMetadata, + ) + } + + // Tests for all_test_spec singleton. + singleton := result.SingletonForTests("all_test_specs") + rule := singleton.Rule("all_test_specs_rule") + prebuiltOs := result.Config.PrebuiltOS() + expectedCmd := "out/soong/host/" + prebuiltOs + "/bin/metadata -rule test_spec -inputFile out/soong/all_test_spec_paths.rsp -outputFile out/soong/ownership/all_test_specs.pb" + expectedOutputFile := "out/soong/ownership/all_test_specs.pb" + expectedInputFile := "out/soong/.intermediates/module-name/intermediateTestSpecMetadata.pb" + if !strings.Contains( + strings.TrimSpace(rule.Output.String()), + expectedOutputFile, + ) { + t.Errorf( + "Retrieved singletonOutputFile: %s is not equal to expectedSingletonOutputFile: %s", + rule.Output.String(), expectedOutputFile, + ) + } + + if !strings.Contains( + strings.TrimSpace(rule.Inputs[0].String()), + expectedInputFile, + ) { + t.Errorf( + "Retrieved singletonInputFile: %s is not equal to expectedSingletonInputFile: %s", + rule.Inputs[0].String(), expectedInputFile, + ) + } + + if !strings.Contains( + strings.TrimSpace(rule.RuleParams.Command), + expectedCmd, + ) { + t.Errorf( + "Retrieved cmd: %s is not equal to expectedCmd: %s", + rule.RuleParams.Command, expectedCmd, + ) + } +} + +func runTest( + t *testing.T, errorHandler android.FixtureErrorHandler, bp string, +) *android.TestResult { + return android.GroupFixturePreparers( + soongTesting.PrepareForTestWithTestSpecBuildComponents, + PrepareForIntegrationTestWithJava, + ). + ExtendWithErrorHandler(errorHandler). + RunTestWithBp(t, bp) +} diff --git a/python/Android.bp b/python/Android.bp index 75786733a..87810c9ed 100644 --- a/python/Android.bp +++ b/python/Android.bp @@ -10,6 +10,7 @@ bootstrap_go_package { "soong-android", "soong-tradefed", "soong-cc", + "soong-testing", ], srcs: [ "binary.go", diff --git a/python/test.go b/python/test.go index 31da17e61..18da72a1d 100644 --- a/python/test.go +++ b/python/test.go @@ -17,6 +17,7 @@ package python import ( "fmt" + "android/soong/testing" "github.com/google/blueprint/proptools" "android/soong/android" @@ -159,6 +160,7 @@ func (p *PythonTestModule) GenerateAndroidBuildActions(ctx android.ModuleContext p.data = append(p.data, android.DataPath{SrcPath: javaDataSrcPath}) } } + ctx.SetProvider(testing.TestModuleProviderKey, testing.TestModuleProviderData{}) } func (p *PythonTestModule) AndroidMkEntries() []android.AndroidMkEntries { diff --git a/rust/Android.bp b/rust/Android.bp index b01a94ad0..c5b200019 100644 --- a/rust/Android.bp +++ b/rust/Android.bp @@ -12,6 +12,7 @@ bootstrap_go_package { "soong-cc", "soong-rust-config", "soong-snapshot", + "soong-testing", ], srcs: [ "afdo.go", diff --git a/rust/rust.go b/rust/rust.go index 7b520cdb0..77bb8b609 100644 --- a/rust/rust.go +++ b/rust/rust.go @@ -19,6 +19,7 @@ import ( "fmt" "strings" + "android/soong/testing" "github.com/google/blueprint" "github.com/google/blueprint/proptools" @@ -139,8 +140,9 @@ type Module struct { Properties BaseProperties - hod android.HostOrDeviceSupported - multilib android.Multilib + hod android.HostOrDeviceSupported + multilib android.Multilib + testModule bool makeLinkType string @@ -1007,6 +1009,9 @@ func (mod *Module) GenerateAndroidBuildActions(actx android.ModuleContext) { ctx.Phony("rust", ctx.RustModule().OutputFile().Path()) } + if mod.testModule { + ctx.SetProvider(testing.TestModuleProviderKey, testing.TestModuleProviderData{}) + } } func (mod *Module) deps(ctx DepsContext) Deps { diff --git a/rust/test.go b/rust/test.go index 4b5296e54..7ffc36767 100644 --- a/rust/test.go +++ b/rust/test.go @@ -222,11 +222,13 @@ func RustTestFactory() android.Module { // rustTestHostMultilib load hook to set MultilibFirst for the // host target. android.AddLoadHook(module, rustTestHostMultilib) + module.testModule = true return module.Init() } func RustTestHostFactory() android.Module { module, _ := NewRustTest(android.HostSupported) + module.testModule = true return module.Init() } diff --git a/sh/Android.bp b/sh/Android.bp index f9198dc4f..2341a128b 100644 --- a/sh/Android.bp +++ b/sh/Android.bp @@ -10,6 +10,7 @@ bootstrap_go_package { "soong", "soong-android", "soong-cc", + "soong-testing", "soong-tradefed", ], srcs: [ diff --git a/sh/sh_binary.go b/sh/sh_binary.go index c921ca68a..d224fdfa4 100644 --- a/sh/sh_binary.go +++ b/sh/sh_binary.go @@ -20,6 +20,7 @@ import ( "sort" "strings" + "android/soong/testing" "github.com/google/blueprint" "github.com/google/blueprint/proptools" @@ -426,6 +427,7 @@ func (s *ShTest) GenerateAndroidBuildActions(ctx android.ModuleContext) { ctx.PropertyErrorf(property, "%q of type %q is not supported", dep.Name(), ctx.OtherModuleType(dep)) } }) + ctx.SetProvider(testing.TestModuleProviderKey, testing.TestModuleProviderData{}) } func (s *ShTest) InstallInData() bool { diff --git a/testing/Android.bp b/testing/Android.bp new file mode 100644 index 000000000..18dccb305 --- /dev/null +++ b/testing/Android.bp @@ -0,0 +1,21 @@ +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + +bootstrap_go_package { + name: "soong-testing", + pkgPath: "android/soong/testing", + deps: [ + "blueprint", + "soong-android", + "soong-testing-test_spec_proto", + + ], + srcs: [ + "all_test_specs.go", + "test_spec.go", + "init.go", + "test.go", + ], + pluginFor: ["soong_build"], +} diff --git a/testing/all_test_specs.go b/testing/all_test_specs.go new file mode 100644 index 000000000..9d4645b37 --- /dev/null +++ b/testing/all_test_specs.go @@ -0,0 +1,45 @@ +package testing + +import ( + "android/soong/android" +) + +const ownershipDirectory = "ownership" +const fileContainingFilePaths = "all_test_spec_paths.rsp" +const allTestSpecsFile = "all_test_specs.pb" + +func AllTestSpecsFactory() android.Singleton { + return &allTestSpecsSingleton{} +} + +type allTestSpecsSingleton struct { + // Path where the collected metadata is stored after successful validation. + outputPath android.OutputPath +} + +func (this *allTestSpecsSingleton) GenerateBuildActions(ctx android.SingletonContext) { + var intermediateMetadataPaths android.Paths + + ctx.VisitAllModules(func(module android.Module) { + if !ctx.ModuleHasProvider(module, TestSpecProviderKey) { + return + } + intermediateMetadataPaths = append(intermediateMetadataPaths, ctx.ModuleProvider(module, TestSpecProviderKey).(TestSpecProviderData).IntermediatePath) + }) + + rspFile := android.PathForOutput(ctx, fileContainingFilePaths) + this.outputPath = android.PathForOutput(ctx, ownershipDirectory, allTestSpecsFile) + + rule := android.NewRuleBuilder(pctx, ctx) + cmd := rule.Command(). + BuiltTool("metadata"). + FlagWithArg("-rule ", "test_spec"). + FlagWithRspFileInputList("-inputFile ", rspFile, intermediateMetadataPaths) + cmd.FlagWithOutput("-outputFile ", this.outputPath) + rule.Build("all_test_specs_rule", "Generate all test specifications") + ctx.Phony("all_test_specs", this.outputPath) +} + +func (this *allTestSpecsSingleton) MakeVars(ctx android.MakeVarsContext) { + ctx.DistForGoal("test_specs", this.outputPath) +} diff --git a/testing/init.go b/testing/init.go new file mode 100644 index 000000000..1ab689215 --- /dev/null +++ b/testing/init.go @@ -0,0 +1,33 @@ +// Copyright 2022 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 testing + +import ( + "android/soong/android" +) + +var ( + pctx = android.NewPackageContext("android/soong/testing") +) + +func init() { + RegisterBuildComponents(android.InitRegistrationContext) + pctx.HostBinToolVariable("metadata", "metadata") +} + +func RegisterBuildComponents(ctx android.RegistrationContext) { + ctx.RegisterModuleType("test_spec", TestSpecFactory) + ctx.RegisterSingletonType("all_test_specs", AllTestSpecsFactory) +} diff --git a/testing/test.go b/testing/test.go new file mode 100644 index 000000000..44824e4db --- /dev/null +++ b/testing/test.go @@ -0,0 +1,21 @@ +// Copyright 2023 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 testing + +import ( + "android/soong/android" +) + +var PrepareForTestWithTestSpecBuildComponents = android.FixtureRegisterWithContext(RegisterBuildComponents) diff --git a/testing/test_spec.go b/testing/test_spec.go new file mode 100644 index 000000000..c370f7174 --- /dev/null +++ b/testing/test_spec.go @@ -0,0 +1,127 @@ +// Copyright 2020 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 testing + +import ( + "path/filepath" + "strconv" + + "android/soong/android" + "android/soong/testing/test_spec_proto" + "github.com/google/blueprint" + "google.golang.org/protobuf/proto" +) + +// ErrTestModuleDataNotFound is the error message for missing test module provider data. +const ErrTestModuleDataNotFound = "The module '%s' does not provide test specification data. Hint: This issue could arise if either the module is not a valid testing module or if it lacks the required 'TestModuleProviderKey' provider.\n" + +func TestSpecFactory() android.Module { + module := &TestSpecModule{} + + android.InitAndroidModule(module) + android.InitDefaultableModule(module) + module.AddProperties(&module.properties) + + return module +} + +type TestSpecModule struct { + android.ModuleBase + android.DefaultableModuleBase + android.BazelModuleBase + + // Properties for "test_spec" + properties struct { + // Specifies the name of the test config. + Name string + // Specifies the team ID. + TeamId string + // Specifies the list of tests covered under this module. + Tests []string + } +} + +type testsDepTagType struct { + blueprint.BaseDependencyTag +} + +var testsDepTag = testsDepTagType{} + +func (module *TestSpecModule) DepsMutator(ctx android.BottomUpMutatorContext) { + // Validate Properties + if len(module.properties.TeamId) == 0 { + ctx.PropertyErrorf("TeamId", "Team Id not found in the test_spec module. Hint: Maybe the TeamId property hasn't been properly specified.") + } + if !isInt(module.properties.TeamId) { + ctx.PropertyErrorf("TeamId", "Invalid value for Team ID. The Team ID must be an integer.") + } + if len(module.properties.Tests) == 0 { + ctx.PropertyErrorf("Tests", "Expected to attribute some test but none found. Hint: Maybe the test property hasn't been properly specified.") + } + ctx.AddDependency(ctx.Module(), testsDepTag, module.properties.Tests...) +} +func isInt(s string) bool { + _, err := strconv.Atoi(s) + return err == nil +} + +// Provider published by TestSpec +type TestSpecProviderData struct { + IntermediatePath android.WritablePath +} + +var TestSpecProviderKey = blueprint.NewProvider(TestSpecProviderData{}) + +type TestModuleProviderData struct { +} + +var TestModuleProviderKey = blueprint.NewProvider(TestModuleProviderData{}) + +func (module *TestSpecModule) GenerateAndroidBuildActions(ctx android.ModuleContext) { + for _, m := range ctx.GetDirectDepsWithTag(testsDepTag) { + if !ctx.OtherModuleHasProvider(m, TestModuleProviderKey) { + ctx.ModuleErrorf(ErrTestModuleDataNotFound, m.Name()) + } + } + bpFilePath := filepath.Join(ctx.ModuleDir(), ctx.BlueprintsFile()) + metadataList := make( + []*test_spec_proto.TestSpec_OwnershipMetadata, 0, + len(module.properties.Tests), + ) + for _, test := range module.properties.Tests { + targetName := test + metadata := test_spec_proto.TestSpec_OwnershipMetadata{ + TrendyTeamId: &module.properties.TeamId, + TargetName: &targetName, + Path: &bpFilePath, + } + metadataList = append(metadataList, &metadata) + } + intermediatePath := android.PathForModuleOut( + ctx, "intermediateTestSpecMetadata.pb", + ) + testSpecMetadata := test_spec_proto.TestSpec{OwnershipMetadataList: metadataList} + protoData, err := proto.Marshal(&testSpecMetadata) + if err != nil { + ctx.ModuleErrorf("Error: %s", err.Error()) + } + android.WriteFileRule(ctx, intermediatePath, string(protoData)) + + ctx.SetProvider( + TestSpecProviderKey, TestSpecProviderData{ + IntermediatePath: intermediatePath, + }, + ) +} diff --git a/testing/test_spec_proto/Android.bp b/testing/test_spec_proto/Android.bp new file mode 100644 index 000000000..1cac492f1 --- /dev/null +++ b/testing/test_spec_proto/Android.bp @@ -0,0 +1,29 @@ +// Copyright 2022 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 { + default_applicable_licenses: ["Android-Apache-2.0"], +} + +bootstrap_go_package { + name: "soong-testing-test_spec_proto", + pkgPath: "android/soong/testing/test_spec_proto", + deps: [ + "golang-protobuf-reflect-protoreflect", + "golang-protobuf-runtime-protoimpl", + ], + srcs: [ + "test_spec.pb.go", + ], +} diff --git a/testing/test_spec_proto/OWNERS b/testing/test_spec_proto/OWNERS new file mode 100644 index 000000000..03bcdf1c4 --- /dev/null +++ b/testing/test_spec_proto/OWNERS @@ -0,0 +1,4 @@ +dariofreni@google.com +joeo@google.com +ronish@google.com +caditya@google.com diff --git a/testing/test_spec_proto/go.mod b/testing/test_spec_proto/go.mod new file mode 100644 index 000000000..482cdbbd1 --- /dev/null +++ b/testing/test_spec_proto/go.mod @@ -0,0 +1,2 @@ +module test_spec_proto +go 1.18
\ No newline at end of file diff --git a/testing/test_spec_proto/regen.sh b/testing/test_spec_proto/regen.sh new file mode 100644 index 000000000..2cf820375 --- /dev/null +++ b/testing/test_spec_proto/regen.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +aprotoc --go_out=paths=source_relative:. test_spec.proto diff --git a/testing/test_spec_proto/test_spec.pb.go b/testing/test_spec_proto/test_spec.pb.go new file mode 100644 index 000000000..5cce60029 --- /dev/null +++ b/testing/test_spec_proto/test_spec.pb.go @@ -0,0 +1,244 @@ +// 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. + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.30.0 +// protoc v3.21.12 +// source: test_spec.proto + +package test_spec_proto + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type TestSpec struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // List of all test targets and their metadata. + OwnershipMetadataList []*TestSpec_OwnershipMetadata `protobuf:"bytes,1,rep,name=ownership_metadata_list,json=ownershipMetadataList" json:"ownership_metadata_list,omitempty"` +} + +func (x *TestSpec) Reset() { + *x = TestSpec{} + if protoimpl.UnsafeEnabled { + mi := &file_test_spec_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *TestSpec) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*TestSpec) ProtoMessage() {} + +func (x *TestSpec) ProtoReflect() protoreflect.Message { + mi := &file_test_spec_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use TestSpec.ProtoReflect.Descriptor instead. +func (*TestSpec) Descriptor() ([]byte, []int) { + return file_test_spec_proto_rawDescGZIP(), []int{0} +} + +func (x *TestSpec) GetOwnershipMetadataList() []*TestSpec_OwnershipMetadata { + if x != nil { + return x.OwnershipMetadataList + } + return nil +} + +type TestSpec_OwnershipMetadata struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + TargetName *string `protobuf:"bytes,1,opt,name=target_name,json=targetName" json:"target_name,omitempty"` + Path *string `protobuf:"bytes,2,opt,name=path" json:"path,omitempty"` + TrendyTeamId *string `protobuf:"bytes,3,opt,name=trendy_team_id,json=trendyTeamId" json:"trendy_team_id,omitempty"` +} + +func (x *TestSpec_OwnershipMetadata) Reset() { + *x = TestSpec_OwnershipMetadata{} + if protoimpl.UnsafeEnabled { + mi := &file_test_spec_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *TestSpec_OwnershipMetadata) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*TestSpec_OwnershipMetadata) ProtoMessage() {} + +func (x *TestSpec_OwnershipMetadata) ProtoReflect() protoreflect.Message { + mi := &file_test_spec_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use TestSpec_OwnershipMetadata.ProtoReflect.Descriptor instead. +func (*TestSpec_OwnershipMetadata) Descriptor() ([]byte, []int) { + return file_test_spec_proto_rawDescGZIP(), []int{0, 0} +} + +func (x *TestSpec_OwnershipMetadata) GetTargetName() string { + if x != nil && x.TargetName != nil { + return *x.TargetName + } + return "" +} + +func (x *TestSpec_OwnershipMetadata) GetPath() string { + if x != nil && x.Path != nil { + return *x.Path + } + return "" +} + +func (x *TestSpec_OwnershipMetadata) GetTrendyTeamId() string { + if x != nil && x.TrendyTeamId != nil { + return *x.TrendyTeamId + } + return "" +} + +var File_test_spec_proto protoreflect.FileDescriptor + +var file_test_spec_proto_rawDesc = []byte{ + 0x0a, 0x0f, 0x74, 0x65, 0x73, 0x74, 0x5f, 0x73, 0x70, 0x65, 0x63, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x12, 0x0f, 0x74, 0x65, 0x73, 0x74, 0x5f, 0x73, 0x70, 0x65, 0x63, 0x5f, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x22, 0xdf, 0x01, 0x0a, 0x08, 0x54, 0x65, 0x73, 0x74, 0x53, 0x70, 0x65, 0x63, 0x12, + 0x63, 0x0a, 0x17, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x5f, 0x6d, 0x65, 0x74, + 0x61, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x2b, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x5f, 0x73, 0x70, 0x65, 0x63, 0x5f, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x2e, 0x54, 0x65, 0x73, 0x74, 0x53, 0x70, 0x65, 0x63, 0x2e, 0x4f, 0x77, 0x6e, 0x65, + 0x72, 0x73, 0x68, 0x69, 0x70, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x15, 0x6f, + 0x77, 0x6e, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, + 0x4c, 0x69, 0x73, 0x74, 0x1a, 0x6e, 0x0a, 0x11, 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x73, 0x68, 0x69, + 0x70, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x1f, 0x0a, 0x0b, 0x74, 0x61, 0x72, + 0x67, 0x65, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, + 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, + 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x12, 0x24, + 0x0a, 0x0e, 0x74, 0x72, 0x65, 0x6e, 0x64, 0x79, 0x5f, 0x74, 0x65, 0x61, 0x6d, 0x5f, 0x69, 0x64, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x74, 0x72, 0x65, 0x6e, 0x64, 0x79, 0x54, 0x65, + 0x61, 0x6d, 0x49, 0x64, 0x42, 0x27, 0x5a, 0x25, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2f, + 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x2f, 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x2f, 0x74, 0x65, + 0x73, 0x74, 0x5f, 0x73, 0x70, 0x65, 0x63, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, +} + +var ( + file_test_spec_proto_rawDescOnce sync.Once + file_test_spec_proto_rawDescData = file_test_spec_proto_rawDesc +) + +func file_test_spec_proto_rawDescGZIP() []byte { + file_test_spec_proto_rawDescOnce.Do(func() { + file_test_spec_proto_rawDescData = protoimpl.X.CompressGZIP(file_test_spec_proto_rawDescData) + }) + return file_test_spec_proto_rawDescData +} + +var file_test_spec_proto_msgTypes = make([]protoimpl.MessageInfo, 2) +var file_test_spec_proto_goTypes = []interface{}{ + (*TestSpec)(nil), // 0: test_spec_proto.TestSpec + (*TestSpec_OwnershipMetadata)(nil), // 1: test_spec_proto.TestSpec.OwnershipMetadata +} +var file_test_spec_proto_depIdxs = []int32{ + 1, // 0: test_spec_proto.TestSpec.ownership_metadata_list:type_name -> test_spec_proto.TestSpec.OwnershipMetadata + 1, // [1:1] is the sub-list for method output_type + 1, // [1:1] is the sub-list for method input_type + 1, // [1:1] is the sub-list for extension type_name + 1, // [1:1] is the sub-list for extension extendee + 0, // [0:1] is the sub-list for field type_name +} + +func init() { file_test_spec_proto_init() } +func file_test_spec_proto_init() { + if File_test_spec_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_test_spec_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*TestSpec); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_test_spec_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*TestSpec_OwnershipMetadata); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_test_spec_proto_rawDesc, + NumEnums: 0, + NumMessages: 2, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_test_spec_proto_goTypes, + DependencyIndexes: file_test_spec_proto_depIdxs, + MessageInfos: file_test_spec_proto_msgTypes, + }.Build() + File_test_spec_proto = out.File + file_test_spec_proto_rawDesc = nil + file_test_spec_proto_goTypes = nil + file_test_spec_proto_depIdxs = nil +} diff --git a/testing/test_spec_proto/test_spec.proto b/testing/test_spec_proto/test_spec.proto new file mode 100644 index 000000000..86bc78954 --- /dev/null +++ b/testing/test_spec_proto/test_spec.proto @@ -0,0 +1,33 @@ +// 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. + +syntax = "proto2"; +package test_spec_proto; +option go_package = "android/soong/testing/test_spec_proto"; + +message TestSpec { + + message OwnershipMetadata { + // REQUIRED: Name of the build target + optional string target_name = 1; + + // REQUIRED: Code location of the target. + // To be used to support legacy/backup systems that use OWNERS file and is + // also required for our dashboard to support per code location basis UI + optional string path = 2; + + // REQUIRED: Team ID of the team that owns this target. + optional string trendy_team_id = 3; + } + + // List of all test targets and their metadata. + repeated OwnershipMetadata ownership_metadata_list = 1; +} |