1// Copyright 2024 Google Inc. All rights reserved. 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14package android 15 16import ( 17 "android/soong/android/team_proto" 18 "log" 19 "testing" 20 21 "google.golang.org/protobuf/proto" 22) 23 24func TestAllTeams(t *testing.T) { 25 t.Parallel() 26 ctx := GroupFixturePreparers( 27 prepareForTestWithTeamAndFakes, 28 // This adds two variants, one armv7-a-neon, one armv8-a 29 PrepareForTestWithArchMutator, 30 FixtureRegisterWithContext(func(ctx RegistrationContext) { 31 ctx.RegisterParallelSingletonType("all_teams", AllTeamsFactory) 32 }), 33 ).RunTestWithBp(t, ` 34 fake { 35 name: "main_test", 36 team: "someteam", 37 } 38 team { 39 name: "someteam", 40 trendy_team_id: "cool_team", 41 } 42 43 team { 44 name: "team2", 45 trendy_team_id: "22222", 46 } 47 48 fake { 49 name: "tool", 50 team: "team2", 51 } 52 53 fake { 54 name: "noteam", 55 test_only: true, 56 } 57 // write the test-only provider value once 58 fake { 59 name: "test-and-team-and-top1", 60 test_only: true, 61 team: "team2", 62 arch: {arm: { skip: false}, 63 arm64: { skip: true}}, 64 } 65 // write the test-only provider once, but on the other arch 66 fake { 67 name: "test-and-team-and-top2", 68 test_only: true, 69 team: "team2", 70 arch: {arm: { skip: true}, 71 arm64: { skip: false}}, 72 } 73 // write the test-only provider value twice 74 fake { 75 name: "test-and-team-and-top3", 76 test_only: true, 77 team: "team2", 78 } 79 // Don't write the test-only provider value 80 fake { 81 name: "test-and-team-and-top4", 82 test_only: true, 83 team: "team2", 84 arch: {arm: { skip: true}, 85 arm64: { skip: true}}, 86 } 87 `) 88 89 var teams *team_proto.AllTeams 90 teams = getTeamProtoOutput(t, ctx) 91 92 // map of module name -> trendy team name. 93 actualTeams := make(map[string]string) 94 actualTests := []string{} 95 actualTopLevelTests := []string{} 96 97 for _, teamProto := range teams.Teams { 98 if teamProto.TrendyTeamId != nil { 99 actualTeams[teamProto.GetTargetName()] = *teamProto.TrendyTeamId 100 } else { 101 actualTeams[teamProto.GetTargetName()] = "" 102 } 103 if teamProto.GetTestOnly() { 104 actualTests = append(actualTests, teamProto.GetTargetName()) 105 } 106 if teamProto.GetTopLevelTarget() { 107 actualTopLevelTests = append(actualTopLevelTests, teamProto.GetTargetName()) 108 } 109 } 110 expectedTeams := map[string]string{ 111 "main_test": "cool_team", 112 "tool": "22222", 113 "test-and-team-and-top1": "22222", 114 "test-and-team-and-top2": "22222", 115 "test-and-team-and-top3": "22222", 116 "test-and-team-and-top4": "22222", 117 "noteam": "", 118 } 119 120 expectedTests := []string{ 121 "noteam", 122 "test-and-team-and-top1", 123 "test-and-team-and-top2", 124 "test-and-team-and-top3", 125 // There should be no test-and-team-top4 as we skip writing all variants 126 // test-only for all variants 127 } 128 AssertDeepEquals(t, "compare maps", expectedTeams, actualTeams) 129 AssertDeepEquals(t, "test matchup", expectedTests, actualTests) 130} 131 132func getTeamProtoOutput(t *testing.T, ctx *TestResult) *team_proto.AllTeams { 133 teams := new(team_proto.AllTeams) 134 config := ctx.SingletonForTests("all_teams") 135 allOutputs := config.AllOutputs() 136 137 protoPath := allOutputs[0] 138 139 out := config.MaybeOutput(protoPath) 140 outProto := []byte(ContentFromFileRuleForTests(t, ctx.TestContext, out)) 141 if err := proto.Unmarshal(outProto, teams); err != nil { 142 log.Fatalln("Failed to parse teams proto:", err) 143 } 144 return teams 145} 146 147// Android.bp 148// 149// team: team_top 150// 151// # dir1 has no modules with teams, 152// # but has a dir with no Android.bp 153// dir1/Android.bp 154// 155// module_dir1 156// 157// # dirs without and Android.bp should be fine. 158// dir1/dir2/dir3/Android.bp 159// 160// package {} 161// module_dir123 162// 163// teams_dir/Android.bp 164// 165// module_with_team1: team1 166// team1: 111 167// 168// # team comes from upper package default 169// teams_dir/deeper/Android.bp 170// 171// module2_with_team1: team1 172// 173// package_defaults/Android.bp 174// package_defaults/pd2/Android.bp 175// 176// package{ default_team: team_top} 177// module_pd2 ## should get team_top 178// 179// package_defaults/pd2/pd3/Android.bp 180// 181// module_pd3 ## should get team_top 182func TestPackageLookup(t *testing.T) { 183 t.Parallel() 184 rootBp := ` 185 team { 186 name: "team_top", 187 trendy_team_id: "trendy://team_top", 188 } ` 189 190 dir1Bp := ` 191 fake { 192 name: "module_dir1", 193 } ` 194 dir3Bp := ` 195 package {} 196 fake { 197 name: "module_dir123", 198 } ` 199 teamsDirBp := ` 200 fake { 201 name: "module_with_team1", 202 team: "team1" 203 204 } 205 team { 206 name: "team1", 207 trendy_team_id: "111", 208 } ` 209 teamsDirDeeper := ` 210 fake { 211 name: "module2_with_team1", 212 team: "team1" 213 } ` 214 // create an empty one. 215 packageDefaultsBp := "" 216 packageDefaultspd2 := ` 217 package { default_team: "team_top"} 218 fake { 219 name: "modulepd2", 220 } ` 221 222 packageDefaultspd3 := ` 223 fake { 224 name: "modulepd3", 225 } 226 fake { 227 name: "modulepd3b", 228 team: "team1" 229 } ` 230 231 ctx := GroupFixturePreparers( 232 prepareForTestWithTeamAndFakes, 233 PrepareForTestWithPackageModule, 234 FixtureRegisterWithContext(func(ctx RegistrationContext) { 235 ctx.RegisterParallelSingletonType("all_teams", AllTeamsFactory) 236 }), 237 FixtureAddTextFile("Android.bp", rootBp), 238 FixtureAddTextFile("dir1/Android.bp", dir1Bp), 239 FixtureAddTextFile("dir1/dir2/dir3/Android.bp", dir3Bp), 240 FixtureAddTextFile("teams_dir/Android.bp", teamsDirBp), 241 FixtureAddTextFile("teams_dir/deeper/Android.bp", teamsDirDeeper), 242 FixtureAddTextFile("package_defaults/Android.bp", packageDefaultsBp), 243 FixtureAddTextFile("package_defaults/pd2/Android.bp", packageDefaultspd2), 244 FixtureAddTextFile("package_defaults/pd2/pd3/Android.bp", packageDefaultspd3), 245 ).RunTest(t) 246 247 var teams *team_proto.AllTeams 248 teams = getTeamProtoOutput(t, ctx) 249 250 // map of module name -> trendy team name. 251 actualTeams := make(map[string]*string) 252 for _, teamProto := range teams.Teams { 253 actualTeams[teamProto.GetTargetName()] = teamProto.TrendyTeamId 254 } 255 expectedTeams := map[string]*string{ 256 "module_with_team1": proto.String("111"), 257 "module2_with_team1": proto.String("111"), 258 "modulepd2": proto.String("trendy://team_top"), 259 "modulepd3": proto.String("trendy://team_top"), 260 "modulepd3b": proto.String("111"), 261 "module_dir1": nil, 262 "module_dir123": nil, 263 } 264 AssertDeepEquals(t, "compare maps", expectedTeams, actualTeams) 265} 266 267func TestPackageLookupForIncludedBlueprintFiles(t *testing.T) { 268 t.Parallel() 269 rootBp := ` 270 package { default_team: "team_top"} 271 team { 272 name: "team_top", 273 trendy_team_id: "trendy://team_top", 274 } 275 build = ["include.bp"] 276 ` 277 includeBp := ` 278 fake { 279 name: "IncludedModule", 280 } ` 281 282 ctx := GroupFixturePreparers( 283 prepareForTestWithTeamAndFakes, 284 PrepareForTestWithPackageModule, 285 FixtureRegisterWithContext(func(ctx RegistrationContext) { 286 ctx.RegisterParallelSingletonType("all_teams", AllTeamsFactory) 287 }), 288 FixtureAddTextFile("Android.bp", rootBp), 289 FixtureAddTextFile("include.bp", includeBp), 290 ).RunTest(t) 291 292 var teams *team_proto.AllTeams 293 teams = getTeamProtoOutput(t, ctx) 294 295 // map of module name -> trendy team name. 296 actualTeams := make(map[string]*string) 297 for _, teamProto := range teams.Teams { 298 actualTeams[teamProto.GetTargetName()] = teamProto.TrendyTeamId 299 } 300 expectedTeams := map[string]*string{ 301 "IncludedModule": proto.String("trendy://team_top"), 302 } 303 AssertDeepEquals(t, "compare maps", expectedTeams, actualTeams) 304} 305 306func TestPackageLookupForIncludedBlueprintFilesWithPackageInChildBlueprint(t *testing.T) { 307 t.Parallel() 308 rootBp := ` 309 team { 310 name: "team_top", 311 trendy_team_id: "trendy://team_top", 312 } 313 build = ["include.bp"] 314 ` 315 includeBp := ` 316 package { default_team: "team_top"} 317 fake { 318 name: "IncludedModule", 319 } ` 320 321 ctx := GroupFixturePreparers( 322 prepareForTestWithTeamAndFakes, 323 PrepareForTestWithPackageModule, 324 FixtureRegisterWithContext(func(ctx RegistrationContext) { 325 ctx.RegisterParallelSingletonType("all_teams", AllTeamsFactory) 326 }), 327 FixtureAddTextFile("Android.bp", rootBp), 328 FixtureAddTextFile("include.bp", includeBp), 329 ).RunTest(t) 330 331 var teams *team_proto.AllTeams 332 teams = getTeamProtoOutput(t, ctx) 333 334 // map of module name -> trendy team name. 335 actualTeams := make(map[string]*string) 336 for _, teamProto := range teams.Teams { 337 actualTeams[teamProto.GetTargetName()] = teamProto.TrendyTeamId 338 } 339 expectedTeams := map[string]*string{ 340 "IncludedModule": proto.String("trendy://team_top"), 341 } 342 AssertDeepEquals(t, "compare maps", expectedTeams, actualTeams) 343} 344 345type fakeForTests struct { 346 ModuleBase 347 348 sourceProperties SourceProperties 349 props struct { 350 // If true, don't write test-only value in provider 351 Skip bool `android:"arch_variant"` 352 } 353} 354 355func fakeFactory() Module { 356 module := &fakeForTests{} 357 module.AddProperties(&module.sourceProperties, &module.props) 358 InitAndroidArchModule(module, HostAndDeviceSupported, MultilibBoth) 359 360 return module 361} 362 363var prepareForTestWithTeamAndFakes = GroupFixturePreparers( 364 FixtureRegisterWithContext(RegisterTeamBuildComponents), 365 FixtureRegisterWithContext(func(ctx RegistrationContext) { 366 ctx.RegisterModuleType("fake", fakeFactory) 367 }), 368) 369 370func (f *fakeForTests) GenerateAndroidBuildActions(ctx ModuleContext) { 371 if Bool(f.sourceProperties.Test_only) { 372 SetProvider(ctx, TestOnlyProviderKey, TestModuleInformation{ 373 TestOnly: Bool(f.sourceProperties.Test_only) && !f.props.Skip, 374 TopLevelTarget: false, 375 }) 376 } 377} 378