xref: /aosp_15_r20/build/soong/android/all_teams_test.go (revision 333d2b3687b3a337dbcca9d65000bca186795e39)
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