Merge "Add proto for Test ownership metadata." into main am: d97bf36469

Original change: https://android-review.googlesource.com/c/platform/build/soong/+/2774872

Change-Id: Idae0ffe939cb25b9c8626a39d036535691ee38f5
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
Aditya Choudhary 2023-11-15 11:19:37 +00:00 committed by Automerger Merge Worker
commit beff7f2a0a
18 changed files with 504 additions and 0 deletions

View file

@ -15,6 +15,7 @@ bootstrap_go_package {
"soong-dexpreopt",
"soong-genrule",
"soong-java-config",
"soong-testing",
"soong-provenance",
"soong-python",
"soong-remoteexec",

View file

@ -22,6 +22,7 @@ import (
"path/filepath"
"strings"
"android/soong/testing"
"github.com/google/blueprint"
"github.com/google/blueprint/proptools"
@ -1193,6 +1194,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 {

View file

@ -23,6 +23,7 @@ import (
"android/soong/android"
"android/soong/dexpreopt"
"android/soong/testing"
"github.com/google/blueprint/proptools"
@ -505,6 +506,7 @@ func (b *BootclasspathFragmentModule) GenerateAndroidBuildActions(ctx android.Mo
if ctx.Module() != ctx.FinalModule() {
b.HideFromMake()
}
ctx.SetProvider(testing.TestModuleProviderKey, testing.TestModuleProviderData{})
}
// getProfileProviderApex returns the name of the apex that provides a boot image profile, or an

View file

@ -27,6 +27,7 @@ import (
"android/soong/bazel"
"android/soong/bazel/cquery"
"android/soong/remoteexec"
"android/soong/testing"
"android/soong/ui/metrics/bp2build_metrics_proto"
"github.com/google/blueprint"
@ -1228,10 +1229,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) {

View file

@ -22,6 +22,7 @@ import (
"android/soong/android"
"android/soong/java/config"
"android/soong/testing"
"android/soong/tradefed"
"github.com/google/blueprint/proptools"
@ -253,6 +254,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,

View file

@ -10,6 +10,7 @@ bootstrap_go_package {
"soong-android",
"soong-tradefed",
"soong-cc",
"soong-testing",
],
srcs: [
"binary.go",

View file

@ -17,6 +17,7 @@ package python
import (
"fmt"
"android/soong/testing"
"github.com/google/blueprint/proptools"
"android/soong/android"
@ -205,6 +206,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 {

View file

@ -11,6 +11,7 @@ bootstrap_go_package {
"soong-android",
"soong-cc",
"soong-java",
"soong-testing",
"soong-tradefed",
],
srcs: [

View file

@ -20,6 +20,7 @@ import (
"sort"
"strings"
"android/soong/testing"
"github.com/google/blueprint"
"github.com/google/blueprint/proptools"
@ -452,6 +453,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 {

19
testing/Android.bp Normal file
View file

@ -0,0 +1,19 @@
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: [
"test_spec.go",
"init.go",
],
pluginFor: ["soong_build"],
}

27
testing/init.go Normal file
View file

@ -0,0 +1,27 @@
// 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"
)
func init() {
RegisterBuildComponents(android.InitRegistrationContext)
}
func RegisterBuildComponents(ctx android.RegistrationContext) {
ctx.RegisterModuleType("test_spec", TestSpecFactory)
}

127
testing/test_spec.go Normal file
View file

@ -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,
},
)
}

View file

@ -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",
],
}

View file

@ -0,0 +1,4 @@
dariofreni@google.com
joeo@google.com
ronish@google.com
caditya@google.com

View file

@ -0,0 +1,2 @@
module test_spec_proto
go 1.18

View file

@ -0,0 +1,3 @@
#!/bin/bash
aprotoc --go_out=paths=source_relative:. test_spec.proto

View file

@ -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
}

View file

@ -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;
}