From c560309e30b07000d135f19d5f1dc209fbaa8240 Mon Sep 17 00:00:00 2001 From: Ronald Braunstein Date: Wed, 27 Mar 2024 06:46:47 -0700 Subject: [PATCH] Add test-only and test-target fields to all_teams proto. The `test-only` flag designates the module contains test-only, not production code. In order to generate code-coverage reports, we wanted a way to filter out code (like java_library) that is test-only and doesn't need to be in the report. The XXX_test modules will have test-only set automatically. For modules like `java_library`, users will be a able to set this in the Android.bp file. As a follow-up, I'll run some queries to find modules that are only reachable from top level test targets and mark them test-only as appropriate. `test-only` is being added to the team.proto and will be written via the `all_teams` target. Currently, it is challenging to find "all top level test targets". I'm adding another field to mark the target as a "top level test target" if it is a XXX_test or XXX_test_host module. The goal is to mark all modules the user intended to run as a test, either with tradefed or directly as a native test. I added 'module-type/kind' to the proto so I can do some queries: gqui from "flatten(out/soong/ownership/all_teams.pb, teams)" proto team.proto:AllTeams 'select teams.kind, count(*) where teams.top_level_target = true group by teams.kind' +--------------+----------+ | teams.kind | count(*) | +--------------+----------+ | android_test | 1379 | | art_cc_test | 56 | | cc_benchmark | 68 | | cc_fuzz | 515 | | cc_test | 3519 | | cc_test_host | 6 | | java_fuzz | 5 | | java_test | 773 | +--------------+----------+ % gqui from "flatten(~/aosp-main-with-phones/out/soong/ownership/all_teams.pb, teams)" proto team.proto:AllTeams 'select teams.kind ,count(*) where teams.test_only = true group by teams.kind' +--------------------------+----------+ | teams.kind | count(*) | +--------------------------+----------+ | android_test | 1379 | | android_test_helper_app | 1678 | | art_cc_test | 56 | | art_cc_test_library | 13 | | cc_benchmark | 68 | | cc_fuzz | 515 | | cc_test | 3519 | | cc_test_host | 6 | | cc_test_library | 484 | | java_library | 2 | | java_test | 773 | | java_test_helper_library | 29 | +--------------------------+----------+ All modules can be seen here: https://docs.google.com/spreadsheets/d/1Zqbh7lDDdlI1xVmrN9fZ8bm8XD7EoORjjiPqbMvAKgQ/edit#gid=396553017 FOLLOW UP cls: *) Add more top level tests, like sh_test and python_test *) Add validation so that only modules currently marked test-only can depend on modules marked test-only *) Remove test_spec, code_metadata, TestModuleProviderKey: aosp/2928500 Test: go test ./java ./cc ./android Test: m blueprint_tests Test: m nothing --no-skip-soong-tests !! android already failing on selects_test Test: m all_teams && gqui from "flatten(out/soong/ownership/all_teams.pb, teams)" Change-Id: Ib97dca60989aa9d7f000727c92af2e354926f072 --- android/Android.bp | 2 + android/all_teams.go | 106 +++++++++++++++++++--------------- android/all_teams_test.go | 63 +++++++++++++++++--- android/shared_properties.go | 26 +++++++++ android/team.go | 9 +++ android/team_proto/team.pb.go | 62 +++++++++++++++----- android/team_proto/team.proto | 10 ++++ android/team_test.go | 25 ++++---- 8 files changed, 220 insertions(+), 83 deletions(-) create mode 100644 android/shared_properties.go diff --git a/android/Android.bp b/android/Android.bp index bf7804ae5..4c59592c8 100644 --- a/android/Android.bp +++ b/android/Android.bp @@ -89,6 +89,7 @@ bootstrap_go_package { "sandbox.go", "sdk.go", "sdk_version.go", + "shared_properties.go", "singleton.go", "singleton_module.go", "soong_config_modules.go", @@ -102,6 +103,7 @@ bootstrap_go_package { "visibility.go", ], testSrcs: [ + "all_teams_test.go", "android_test.go", "androidmk_test.go", "apex_test.go", diff --git a/android/all_teams.go b/android/all_teams.go index b177e20e7..0c433a6cb 100644 --- a/android/all_teams.go +++ b/android/all_teams.go @@ -23,9 +23,18 @@ func registerAllTeamBuildComponents(ctx RegistrationContext) { } // For each module, list the team or the bpFile the module is defined in. -type moduleTeamInfo struct { +type moduleTeamAndTestInfo struct { + // Name field from bp file for the team teamName string - bpFile string + // Blueprint file the module is located in. + bpFile string + // Is this module only used by tests. + testOnly bool + // Is this a directly testable target by running the module directly + // or via tradefed. + topLevelTestTarget bool + // String name indicating the module, like `java_library` for reporting. + kind string } type allTeamsSingleton struct { @@ -37,16 +46,16 @@ type allTeamsSingleton struct { // Map of all team modules we visit during GenerateBuildActions teams map[string]teamProperties // Keeps track of team information or bp file for each module we visit. - teams_for_mods map[string]moduleTeamInfo + teams_for_mods map[string]moduleTeamAndTestInfo } // See if there is a package module for the given bpFilePath with a team defined, if so return the team. // If not ascend up to the parent directory and do the same. -func (this *allTeamsSingleton) lookupDefaultTeam(bpFilePath string) (teamProperties, bool) { +func (t *allTeamsSingleton) lookupDefaultTeam(bpFilePath string) (teamProperties, bool) { // return the Default_team listed in the package if is there. - if p, ok := this.packages[bpFilePath]; ok { - if t := p.Default_team; t != nil { - return this.teams[*p.Default_team], true + if p, ok := t.packages[bpFilePath]; ok { + if defaultTeam := p.Default_team; defaultTeam != nil { + return t.teams[*defaultTeam], true } } // Strip a directory and go up. @@ -57,72 +66,79 @@ func (this *allTeamsSingleton) lookupDefaultTeam(bpFilePath string) (teamPropert if current == "." { return teamProperties{}, false } - return this.lookupDefaultTeam(filepath.Join(parent, base)) + return t.lookupDefaultTeam(filepath.Join(parent, base)) } -// Create a rule to run a tool to collect all the intermediate files -// which list the team per module into one proto file. -func (this *allTeamsSingleton) GenerateBuildActions(ctx SingletonContext) { - this.packages = make(map[string]packageProperties) - this.teams = make(map[string]teamProperties) - this.teams_for_mods = make(map[string]moduleTeamInfo) +// Visit all modules and collect all teams and use WriteFileRuleVerbatim +// to write it out. +func (t *allTeamsSingleton) GenerateBuildActions(ctx SingletonContext) { + t.packages = make(map[string]packageProperties) + t.teams = make(map[string]teamProperties) + t.teams_for_mods = make(map[string]moduleTeamAndTestInfo) ctx.VisitAllModules(func(module Module) { bpFile := ctx.BlueprintFile(module) + testModInfo := TestModuleInformation{} + if tmi, ok := SingletonModuleProvider(ctx, module, TestOnlyProviderKey); ok { + testModInfo = tmi + } + // Package Modules and Team Modules are stored in a map so we can look them up by name for // modules without a team. if pack, ok := module.(*packageModule); ok { - // Packages don't have names, use the blueprint file as the key. we can't get qualifiedModuleId in this context. + // Packages don't have names, use the blueprint file as the key. we can't get qualifiedModuleId in t context. pkgKey := bpFile - this.packages[pkgKey] = pack.properties + t.packages[pkgKey] = pack.properties return } if team, ok := module.(*teamModule); ok { - this.teams[team.Name()] = team.properties + t.teams[team.Name()] = team.properties return } - // If a team name is given for a module, store it. - // Otherwise store the bpFile so we can do a package walk later. - if module.base().Team() != "" { - this.teams_for_mods[module.Name()] = moduleTeamInfo{teamName: module.base().Team(), bpFile: bpFile} - } else { - this.teams_for_mods[module.Name()] = moduleTeamInfo{bpFile: bpFile} + entry := moduleTeamAndTestInfo{ + bpFile: bpFile, + testOnly: testModInfo.TestOnly, + topLevelTestTarget: testModInfo.TopLevelTarget, + kind: ctx.ModuleType(module), + teamName: module.base().Team(), } + t.teams_for_mods[module.Name()] = entry + }) // Visit all modules again and lookup the team name in the package or parent package if the team // isn't assignged at the module level. - allTeams := this.lookupTeamForAllModules() + allTeams := t.lookupTeamForAllModules() - this.outputPath = PathForOutput(ctx, ownershipDirectory, allTeamsFile) + t.outputPath = PathForOutput(ctx, ownershipDirectory, allTeamsFile) data, err := proto.Marshal(allTeams) if err != nil { ctx.Errorf("Unable to marshal team data. %s", err) } - WriteFileRuleVerbatim(ctx, this.outputPath, string(data)) - ctx.Phony("all_teams", this.outputPath) + WriteFileRuleVerbatim(ctx, t.outputPath, string(data)) + ctx.Phony("all_teams", t.outputPath) } -func (this *allTeamsSingleton) MakeVars(ctx MakeVarsContext) { - ctx.DistForGoal("all_teams", this.outputPath) +func (t *allTeamsSingleton) MakeVars(ctx MakeVarsContext) { + ctx.DistForGoal("all_teams", t.outputPath) } // Visit every (non-package, non-team) module and write out a proto containing // either the declared team data for that module or the package default team data for that module. -func (this *allTeamsSingleton) lookupTeamForAllModules() *team_proto.AllTeams { - teamsProto := make([]*team_proto.Team, len(this.teams_for_mods)) - for i, moduleName := range SortedKeys(this.teams_for_mods) { - m, _ := this.teams_for_mods[moduleName] +func (t *allTeamsSingleton) lookupTeamForAllModules() *team_proto.AllTeams { + teamsProto := make([]*team_proto.Team, len(t.teams_for_mods)) + for i, moduleName := range SortedKeys(t.teams_for_mods) { + m, _ := t.teams_for_mods[moduleName] teamName := m.teamName var teamProperties teamProperties found := false if teamName != "" { - teamProperties, found = this.teams[teamName] + teamProperties, found = t.teams[teamName] } else { - teamProperties, found = this.lookupDefaultTeam(m.bpFile) + teamProperties, found = t.lookupDefaultTeam(m.bpFile) } trendy_team_id := "" @@ -130,22 +146,18 @@ func (this *allTeamsSingleton) lookupTeamForAllModules() *team_proto.AllTeams { trendy_team_id = *teamProperties.Trendy_team_id } - var files []string teamData := new(team_proto.Team) + *teamData = team_proto.Team{ + TargetName: proto.String(moduleName), + Path: proto.String(m.bpFile), + TestOnly: proto.Bool(m.testOnly), + TopLevelTarget: proto.Bool(m.topLevelTestTarget), + Kind: proto.String(m.kind), + } if trendy_team_id != "" { - *teamData = team_proto.Team{ - TrendyTeamId: proto.String(trendy_team_id), - TargetName: proto.String(moduleName), - Path: proto.String(m.bpFile), - File: files, - } + teamData.TrendyTeamId = proto.String(trendy_team_id) } else { // Clients rely on the TrendyTeamId optional field not being set. - *teamData = team_proto.Team{ - TargetName: proto.String(moduleName), - Path: proto.String(m.bpFile), - File: files, - } } teamsProto[i] = teamData } diff --git a/android/all_teams_test.go b/android/all_teams_test.go index a02b86e06..9c2b38e42 100644 --- a/android/all_teams_test.go +++ b/android/all_teams_test.go @@ -24,9 +24,8 @@ import ( func TestAllTeams(t *testing.T) { t.Parallel() ctx := GroupFixturePreparers( - PrepareForTestWithTeamBuildComponents, + prepareForTestWithTeamAndFakes, FixtureRegisterWithContext(func(ctx RegistrationContext) { - ctx.RegisterModuleType("fake", fakeModuleFactory) ctx.RegisterParallelSingletonType("all_teams", AllTeamsFactory) }), ).RunTestWithBp(t, ` @@ -51,6 +50,12 @@ func TestAllTeams(t *testing.T) { fake { name: "noteam", + test_only: true, + } + fake { + name: "test-and-team-and-top", + test_only: true, + team: "team2", } `) @@ -59,16 +64,31 @@ func TestAllTeams(t *testing.T) { // map of module name -> trendy team name. actualTeams := make(map[string]*string) + actualTests := []string{} + actualTopLevelTests := []string{} + for _, teamProto := range teams.Teams { actualTeams[teamProto.GetTargetName()] = teamProto.TrendyTeamId + if teamProto.GetTestOnly() { + actualTests = append(actualTests, teamProto.GetTargetName()) + } + if teamProto.GetTopLevelTarget() { + actualTopLevelTests = append(actualTopLevelTests, teamProto.GetTargetName()) + } } expectedTeams := map[string]*string{ - "main_test": proto.String("cool_team"), - "tool": proto.String("22222"), - "noteam": nil, + "main_test": proto.String("cool_team"), + "tool": proto.String("22222"), + "test-and-team-and-top": proto.String("22222"), + "noteam": nil, } + expectedTests := []string{ + "noteam", + "test-and-team-and-top", + } AssertDeepEquals(t, "compare maps", expectedTeams, actualTeams) + AssertDeepEquals(t, "test matchup", expectedTests, actualTests) } func getTeamProtoOutput(t *testing.T, ctx *TestResult) *team_proto.AllTeams { @@ -171,10 +191,9 @@ func TestPackageLookup(t *testing.T) { } ` ctx := GroupFixturePreparers( - PrepareForTestWithTeamBuildComponents, + prepareForTestWithTeamAndFakes, PrepareForTestWithPackageModule, FixtureRegisterWithContext(func(ctx RegistrationContext) { - ctx.RegisterModuleType("fake", fakeModuleFactory) ctx.RegisterParallelSingletonType("all_teams", AllTeamsFactory) }), FixtureAddTextFile("Android.bp", rootBp), @@ -206,3 +225,33 @@ func TestPackageLookup(t *testing.T) { } AssertDeepEquals(t, "compare maps", expectedTeams, actualTeams) } + +type fakeForTests struct { + ModuleBase + + sourceProperties SourceProperties +} + +func fakeFactory() Module { + module := &fakeForTests{} + module.AddProperties(&module.sourceProperties) + InitAndroidModule(module) + + return module +} + +var prepareForTestWithTeamAndFakes = GroupFixturePreparers( + FixtureRegisterWithContext(RegisterTeamBuildComponents), + FixtureRegisterWithContext(func(ctx RegistrationContext) { + ctx.RegisterModuleType("fake", fakeFactory) + }), +) + +func (f *fakeForTests) GenerateAndroidBuildActions(ctx ModuleContext) { + if Bool(f.sourceProperties.Test_only) { + SetProvider(ctx, TestOnlyProviderKey, TestModuleInformation{ + TestOnly: Bool(f.sourceProperties.Test_only), + TopLevelTarget: false, + }) + } +} diff --git a/android/shared_properties.go b/android/shared_properties.go new file mode 100644 index 000000000..84d68fa14 --- /dev/null +++ b/android/shared_properties.go @@ -0,0 +1,26 @@ +// Copyright 2024 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 + +// For storing user-supplied properties about source code on a module to be queried later. +type SourceProperties struct { + // Indicates that the module and its source code are only used in tests, not + // production code. Used by coverage reports and potentially other tools. + Test_only *bool + // Used internally to write if this is a top level test target. + // i.e. something that can be run directly or through tradefed as a test. + // `java_library` would be false, `java_test` would be true. + Top_level_test_target bool `blueprint:"mutated"` +} diff --git a/android/team.go b/android/team.go index df61f4021..c273dc647 100644 --- a/android/team.go +++ b/android/team.go @@ -14,6 +14,8 @@ package android +import "github.com/google/blueprint" + func init() { RegisterTeamBuildComponents(InitRegistrationContext) } @@ -37,6 +39,13 @@ type teamModule struct { properties teamProperties } +type TestModuleInformation struct { + TestOnly bool + TopLevelTarget bool +} + +var TestOnlyProviderKey = blueprint.NewProvider[TestModuleInformation]() + // Real work is done for the module that depends on us. // If needed, the team can serialize the config to json/proto file as well. func (t *teamModule) GenerateAndroidBuildActions(ctx ModuleContext) {} diff --git a/android/team_proto/team.pb.go b/android/team_proto/team.pb.go index 61260cf78..8414d176a 100644 --- a/android/team_proto/team.pb.go +++ b/android/team_proto/team.pb.go @@ -46,6 +46,13 @@ type Team struct { TrendyTeamId *string `protobuf:"bytes,3,opt,name=trendy_team_id,json=trendyTeamId" json:"trendy_team_id,omitempty"` // OPTIONAL: Files directly owned by this module. File []string `protobuf:"bytes,4,rep,name=file" json:"file,omitempty"` + // OPTIONAL: Is this a test-only module. + TestOnly *bool `protobuf:"varint,5,opt,name=test_only,json=testOnly" json:"test_only,omitempty"` + // OPTIONAL: Is this intended to be run as a test target. + // This target can be run directly as a test or passed to tradefed. + TopLevelTarget *bool `protobuf:"varint,6,opt,name=top_level_target,json=topLevelTarget" json:"top_level_target,omitempty"` + // OPTIONAL: Name of module kind, i.e. java_library + Kind *string `protobuf:"bytes,7,opt,name=kind" json:"kind,omitempty"` } func (x *Team) Reset() { @@ -108,6 +115,27 @@ func (x *Team) GetFile() []string { return nil } +func (x *Team) GetTestOnly() bool { + if x != nil && x.TestOnly != nil { + return *x.TestOnly + } + return false +} + +func (x *Team) GetTopLevelTarget() bool { + if x != nil && x.TopLevelTarget != nil { + return *x.TopLevelTarget + } + return false +} + +func (x *Team) GetKind() string { + if x != nil && x.Kind != nil { + return *x.Kind + } + return "" +} + type AllTeams struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -159,20 +187,26 @@ var File_team_proto protoreflect.FileDescriptor var file_team_proto_rawDesc = []byte{ 0x0a, 0x0a, 0x74, 0x65, 0x61, 0x6d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0a, 0x74, 0x65, - 0x61, 0x6d, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x75, 0x0a, 0x04, 0x54, 0x65, 0x61, 0x6d, - 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, 0x12, 0x12, 0x0a, 0x04, 0x66, - 0x69, 0x6c, 0x65, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x04, 0x66, 0x69, 0x6c, 0x65, 0x22, - 0x32, 0x0a, 0x08, 0x41, 0x6c, 0x6c, 0x54, 0x65, 0x61, 0x6d, 0x73, 0x12, 0x26, 0x0a, 0x05, 0x74, - 0x65, 0x61, 0x6d, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x74, 0x65, 0x61, - 0x6d, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x54, 0x65, 0x61, 0x6d, 0x52, 0x05, 0x74, 0x65, - 0x61, 0x6d, 0x73, 0x42, 0x22, 0x5a, 0x20, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2f, 0x73, - 0x6f, 0x6f, 0x6e, 0x67, 0x2f, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2f, 0x74, 0x65, 0x61, - 0x6d, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x61, 0x6d, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xd0, 0x01, 0x0a, 0x04, 0x54, 0x65, 0x61, + 0x6d, 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, 0x12, 0x12, 0x0a, 0x04, + 0x66, 0x69, 0x6c, 0x65, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x04, 0x66, 0x69, 0x6c, 0x65, + 0x12, 0x1b, 0x0a, 0x09, 0x74, 0x65, 0x73, 0x74, 0x5f, 0x6f, 0x6e, 0x6c, 0x79, 0x18, 0x05, 0x20, + 0x01, 0x28, 0x08, 0x52, 0x08, 0x74, 0x65, 0x73, 0x74, 0x4f, 0x6e, 0x6c, 0x79, 0x12, 0x28, 0x0a, + 0x10, 0x74, 0x6f, 0x70, 0x5f, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x5f, 0x74, 0x61, 0x72, 0x67, 0x65, + 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x74, 0x6f, 0x70, 0x4c, 0x65, 0x76, 0x65, + 0x6c, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x18, + 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x22, 0x32, 0x0a, 0x08, 0x41, + 0x6c, 0x6c, 0x54, 0x65, 0x61, 0x6d, 0x73, 0x12, 0x26, 0x0a, 0x05, 0x74, 0x65, 0x61, 0x6d, 0x73, + 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x74, 0x65, 0x61, 0x6d, 0x5f, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x2e, 0x54, 0x65, 0x61, 0x6d, 0x52, 0x05, 0x74, 0x65, 0x61, 0x6d, 0x73, 0x42, + 0x22, 0x5a, 0x20, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2f, 0x73, 0x6f, 0x6f, 0x6e, 0x67, + 0x2f, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2f, 0x74, 0x65, 0x61, 0x6d, 0x5f, 0x70, 0x72, + 0x6f, 0x74, 0x6f, } var ( diff --git a/android/team_proto/team.proto b/android/team_proto/team.proto index 401eccc6e..69ebf4332 100644 --- a/android/team_proto/team.proto +++ b/android/team_proto/team.proto @@ -27,6 +27,16 @@ message Team { // OPTIONAL: Files directly owned by this module. repeated string file = 4; + + // OPTIONAL: Is this a test-only module. + optional bool test_only = 5; + + // OPTIONAL: Is this intended to be run as a test target. + // This target can be run directly as a test or passed to tradefed. + optional bool top_level_target = 6; + + // OPTIONAL: Name of module kind, i.e. java_library + optional string kind = 7; } message AllTeams { diff --git a/android/team_test.go b/android/team_test.go index 75b3e9fbb..ccfcaaa66 100644 --- a/android/team_test.go +++ b/android/team_test.go @@ -27,16 +27,19 @@ func fakeModuleFactory() Module { return module } +var prepareForTestWithTeamAndFakeBuildComponents = GroupFixturePreparers( + FixtureRegisterWithContext(RegisterTeamBuildComponents), + FixtureRegisterWithContext(func(ctx RegistrationContext) { + ctx.RegisterModuleType("fake", fakeModuleFactory) + }), +) + func (*fakeModuleForTests) GenerateAndroidBuildActions(ModuleContext) {} func TestTeam(t *testing.T) { t.Parallel() - ctx := GroupFixturePreparers( - PrepareForTestWithTeamBuildComponents, - FixtureRegisterWithContext(func(ctx RegistrationContext) { - ctx.RegisterModuleType("fake", fakeModuleFactory) - }), - ).RunTestWithBp(t, ` + ctx := prepareForTestWithTeamAndFakeBuildComponents. + RunTestWithBp(t, ` fake { name: "main_test", team: "someteam", @@ -66,12 +69,7 @@ func TestTeam(t *testing.T) { func TestMissingTeamFails(t *testing.T) { t.Parallel() - GroupFixturePreparers( - PrepareForTestWithTeamBuildComponents, - FixtureRegisterWithContext(func(ctx RegistrationContext) { - ctx.RegisterModuleType("fake", fakeModuleFactory) - }), - ). + prepareForTestWithTeamAndFakeBuildComponents. ExtendWithErrorHandler(FixtureExpectsAtLeastOneErrorMatchingPattern("depends on undefined module \"ring-bearer")). RunTestWithBp(t, ` fake { @@ -86,9 +84,6 @@ func TestPackageBadTeamNameFails(t *testing.T) { GroupFixturePreparers( PrepareForTestWithTeamBuildComponents, PrepareForTestWithPackageModule, - FixtureRegisterWithContext(func(ctx RegistrationContext) { - ctx.RegisterModuleType("fake", fakeModuleFactory) - }), ). ExtendWithErrorHandler(FixtureExpectsAtLeastOneErrorMatchingPattern("depends on undefined module \"ring-bearer")). RunTestWithBp(t, `