// 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 import ( "android/soong/android/team_proto" "log" "testing" "google.golang.org/protobuf/proto" ) func TestAllTeams(t *testing.T) { t.Parallel() ctx := GroupFixturePreparers( prepareForTestWithTeamAndFakes, // This adds two variants, one armv7-a-neon, one armv8-a PrepareForTestWithArchMutator, FixtureRegisterWithContext(func(ctx RegistrationContext) { ctx.RegisterParallelSingletonType("all_teams", AllTeamsFactory) }), ).RunTestWithBp(t, ` fake { name: "main_test", team: "someteam", } team { name: "someteam", trendy_team_id: "cool_team", } team { name: "team2", trendy_team_id: "22222", } fake { name: "tool", team: "team2", } fake { name: "noteam", test_only: true, } // write the test-only provider value once fake { name: "test-and-team-and-top1", test_only: true, team: "team2", arch: {arm: { skip: false}, arm64: { skip: true}}, } // write the test-only provider once, but on the other arch fake { name: "test-and-team-and-top2", test_only: true, team: "team2", arch: {arm: { skip: true}, arm64: { skip: false}}, } // write the test-only provider value twice fake { name: "test-and-team-and-top3", test_only: true, team: "team2", } // Don't write the test-only provider value fake { name: "test-and-team-and-top4", test_only: true, team: "team2", arch: {arm: { skip: true}, arm64: { skip: true}}, } `) var teams *team_proto.AllTeams teams = getTeamProtoOutput(t, ctx) // map of module name -> trendy team name. actualTeams := make(map[string]string) actualTests := []string{} actualTopLevelTests := []string{} for _, teamProto := range teams.Teams { if teamProto.TrendyTeamId != nil { actualTeams[teamProto.GetTargetName()] = *teamProto.TrendyTeamId } else { actualTeams[teamProto.GetTargetName()] = "" } if teamProto.GetTestOnly() { actualTests = append(actualTests, teamProto.GetTargetName()) } if teamProto.GetTopLevelTarget() { actualTopLevelTests = append(actualTopLevelTests, teamProto.GetTargetName()) } } expectedTeams := map[string]string{ "main_test": "cool_team", "tool": "22222", "test-and-team-and-top1": "22222", "test-and-team-and-top2": "22222", "test-and-team-and-top3": "22222", "test-and-team-and-top4": "22222", "noteam": "", } expectedTests := []string{ "noteam", "test-and-team-and-top1", "test-and-team-and-top2", "test-and-team-and-top3", // There should be no test-and-team-top4 as we skip writing all variants // test-only for all variants } AssertDeepEquals(t, "compare maps", expectedTeams, actualTeams) AssertDeepEquals(t, "test matchup", expectedTests, actualTests) } func getTeamProtoOutput(t *testing.T, ctx *TestResult) *team_proto.AllTeams { teams := new(team_proto.AllTeams) config := ctx.SingletonForTests("all_teams") allOutputs := config.AllOutputs() protoPath := allOutputs[0] out := config.MaybeOutput(protoPath) outProto := []byte(ContentFromFileRuleForTests(t, ctx.TestContext, out)) if err := proto.Unmarshal(outProto, teams); err != nil { log.Fatalln("Failed to parse teams proto:", err) } return teams } // Android.bp // // team: team_top // // # dir1 has no modules with teams, // # but has a dir with no Android.bp // dir1/Android.bp // // module_dir1 // // # dirs without and Android.bp should be fine. // dir1/dir2/dir3/Android.bp // // package {} // module_dir123 // // teams_dir/Android.bp // // module_with_team1: team1 // team1: 111 // // # team comes from upper package default // teams_dir/deeper/Android.bp // // module2_with_team1: team1 // // package_defaults/Android.bp // package_defaults/pd2/Android.bp // // package{ default_team: team_top} // module_pd2 ## should get team_top // // package_defaults/pd2/pd3/Android.bp // // module_pd3 ## should get team_top func TestPackageLookup(t *testing.T) { t.Parallel() rootBp := ` team { name: "team_top", trendy_team_id: "trendy://team_top", } ` dir1Bp := ` fake { name: "module_dir1", } ` dir3Bp := ` package {} fake { name: "module_dir123", } ` teamsDirBp := ` fake { name: "module_with_team1", team: "team1" } team { name: "team1", trendy_team_id: "111", } ` teamsDirDeeper := ` fake { name: "module2_with_team1", team: "team1" } ` // create an empty one. packageDefaultsBp := "" packageDefaultspd2 := ` package { default_team: "team_top"} fake { name: "modulepd2", } ` packageDefaultspd3 := ` fake { name: "modulepd3", } fake { name: "modulepd3b", team: "team1" } ` ctx := GroupFixturePreparers( prepareForTestWithTeamAndFakes, PrepareForTestWithPackageModule, FixtureRegisterWithContext(func(ctx RegistrationContext) { ctx.RegisterParallelSingletonType("all_teams", AllTeamsFactory) }), FixtureAddTextFile("Android.bp", rootBp), FixtureAddTextFile("dir1/Android.bp", dir1Bp), FixtureAddTextFile("dir1/dir2/dir3/Android.bp", dir3Bp), FixtureAddTextFile("teams_dir/Android.bp", teamsDirBp), FixtureAddTextFile("teams_dir/deeper/Android.bp", teamsDirDeeper), FixtureAddTextFile("package_defaults/Android.bp", packageDefaultsBp), FixtureAddTextFile("package_defaults/pd2/Android.bp", packageDefaultspd2), FixtureAddTextFile("package_defaults/pd2/pd3/Android.bp", packageDefaultspd3), ).RunTest(t) var teams *team_proto.AllTeams teams = getTeamProtoOutput(t, ctx) // map of module name -> trendy team name. actualTeams := make(map[string]*string) for _, teamProto := range teams.Teams { actualTeams[teamProto.GetTargetName()] = teamProto.TrendyTeamId } expectedTeams := map[string]*string{ "module_with_team1": proto.String("111"), "module2_with_team1": proto.String("111"), "modulepd2": proto.String("trendy://team_top"), "modulepd3": proto.String("trendy://team_top"), "modulepd3b": proto.String("111"), "module_dir1": nil, "module_dir123": nil, } AssertDeepEquals(t, "compare maps", expectedTeams, actualTeams) } type fakeForTests struct { ModuleBase sourceProperties SourceProperties props struct { // If true, don't write test-only value in provider Skip bool `android:"arch_variant"` } } func fakeFactory() Module { module := &fakeForTests{} module.AddProperties(&module.sourceProperties, &module.props) InitAndroidArchModule(module, HostAndDeviceSupported, MultilibBoth) 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) && !f.props.Skip, TopLevelTarget: false, }) } }