xref: /aosp_15_r20/build/soong/android/packaging_test.go (revision 333d2b3687b3a337dbcca9d65000bca186795e39)
1// Copyright 2020 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.
14
15package android
16
17import (
18	"strings"
19	"testing"
20
21	"github.com/google/blueprint"
22	"github.com/google/blueprint/proptools"
23)
24
25// Module to be packaged
26type componentTestModule struct {
27	ModuleBase
28	props struct {
29		Deps         []string
30		Skip_install *bool
31		Overrides    []string
32	}
33}
34
35// dep tag used in this test. All dependencies are considered as installable.
36type installDepTag struct {
37	blueprint.BaseDependencyTag
38	InstallAlwaysNeededDependencyTag
39}
40
41func componentTestModuleFactory() Module {
42	m := &componentTestModule{}
43	m.AddProperties(&m.props)
44	InitAndroidArchModule(m, HostAndDeviceSupported, MultilibBoth)
45	return m
46}
47
48func (m *componentTestModule) DepsMutator(ctx BottomUpMutatorContext) {
49	ctx.AddDependency(ctx.Module(), installDepTag{}, m.props.Deps...)
50}
51
52func (m *componentTestModule) GenerateAndroidBuildActions(ctx ModuleContext) {
53	builtFile := PathForModuleOut(ctx, m.Name())
54	dir := ctx.Target().Arch.ArchType.Multilib
55	installDir := PathForModuleInstall(ctx, dir)
56	if proptools.Bool(m.props.Skip_install) {
57		m.SkipInstall()
58	}
59	ctx.InstallFile(installDir, m.Name(), builtFile)
60}
61
62// Module that itself is a package
63type packageTestModule struct {
64	ModuleBase
65	PackagingBase
66	properties struct {
67		Install_deps []string
68	}
69	entries []string
70}
71
72func packageTestModuleFactory(multiTarget bool, depsCollectFirstTargetOnly bool) Module {
73	module := &packageTestModule{}
74	InitPackageModule(module)
75	module.DepsCollectFirstTargetOnly = depsCollectFirstTargetOnly
76	if multiTarget {
77		InitAndroidMultiTargetsArchModule(module, DeviceSupported, MultilibCommon)
78	} else {
79		InitAndroidArchModule(module, DeviceSupported, MultilibBoth)
80	}
81	module.AddProperties(&module.properties)
82	return module
83}
84
85type packagingDepTag struct {
86	blueprint.BaseDependencyTag
87	PackagingItemAlwaysDepTag
88}
89
90func (m *packageTestModule) DepsMutator(ctx BottomUpMutatorContext) {
91	m.AddDeps(ctx, packagingDepTag{})
92	ctx.AddDependency(ctx.Module(), installDepTag{}, m.properties.Install_deps...)
93}
94
95func (m *packageTestModule) GenerateAndroidBuildActions(ctx ModuleContext) {
96	zipFile := PathForModuleOut(ctx, "myzip.zip")
97	m.entries = m.CopyDepsToZip(ctx, m.GatherPackagingSpecs(ctx), zipFile)
98}
99
100type testConfig struct {
101	multiTarget                bool
102	depsCollectFirstTargetOnly bool
103	debuggable                 bool
104}
105
106func runPackagingTest(t *testing.T, config testConfig, bp string, expected []string) {
107	t.Helper()
108
109	var archVariant string
110	if config.multiTarget {
111		archVariant = "android_common"
112	} else {
113		archVariant = "android_arm64_armv8-a"
114	}
115
116	moduleFactory := func() Module {
117		return packageTestModuleFactory(config.multiTarget, config.depsCollectFirstTargetOnly)
118	}
119
120	result := GroupFixturePreparers(
121		PrepareForTestWithDefaults,
122		PrepareForTestWithArchMutator,
123		FixtureRegisterWithContext(func(ctx RegistrationContext) {
124			ctx.RegisterModuleType("component", componentTestModuleFactory)
125			ctx.RegisterModuleType("package_module", moduleFactory)
126		}),
127		FixtureModifyProductVariables(func(variables FixtureProductVariables) {
128			variables.Debuggable = proptools.BoolPtr(config.debuggable)
129		}),
130		FixtureWithRootAndroidBp(bp),
131	).RunTest(t)
132
133	p := result.Module("package", archVariant).(*packageTestModule)
134	actual := p.entries
135	actual = SortedUniqueStrings(actual)
136	expected = SortedUniqueStrings(expected)
137	AssertDeepEquals(t, "package entries", expected, actual)
138}
139
140func TestPackagingBaseMultiTarget(t *testing.T) {
141	config := testConfig{
142		multiTarget:                true,
143		depsCollectFirstTargetOnly: false,
144	}
145	runPackagingTest(t, config,
146		`
147		component {
148			name: "foo",
149		}
150
151		package_module {
152			name: "package",
153			deps: ["foo"],
154		}
155		`, []string{"lib64/foo"})
156
157	runPackagingTest(t, config,
158		`
159		component {
160			name: "foo",
161			deps: ["bar"],
162		}
163
164		component {
165			name: "bar",
166		}
167
168		package_module {
169			name: "package",
170			deps: ["foo"],
171		}
172		`, []string{"lib64/foo", "lib64/bar"})
173
174	runPackagingTest(t, config,
175		`
176		component {
177			name: "foo",
178			deps: ["bar"],
179		}
180
181		component {
182			name: "bar",
183		}
184
185		package_module {
186			name: "package",
187			deps: ["foo"],
188			compile_multilib: "both",
189		}
190		`, []string{"lib32/foo", "lib32/bar", "lib64/foo", "lib64/bar"})
191
192	runPackagingTest(t, config,
193		`
194		component {
195			name: "foo",
196		}
197
198		component {
199			name: "bar",
200			compile_multilib: "32",
201		}
202
203		package_module {
204			name: "package",
205			deps: ["foo"],
206			multilib: {
207				lib32: {
208					deps: ["bar"],
209				},
210			},
211			compile_multilib: "both",
212		}
213		`, []string{"lib32/foo", "lib32/bar", "lib64/foo"})
214
215	runPackagingTest(t, config,
216		`
217		component {
218			name: "foo",
219		}
220
221		component {
222			name: "bar",
223		}
224
225		package_module {
226			name: "package",
227			deps: ["foo"],
228			multilib: {
229				first: {
230					deps: ["bar"],
231				},
232			},
233			compile_multilib: "both",
234		}
235		`, []string{"lib32/foo", "lib64/foo", "lib64/bar"})
236
237	runPackagingTest(t, config,
238		`
239		component {
240			name: "foo",
241		}
242
243		component {
244			name: "bar",
245		}
246
247		component {
248			name: "baz",
249		}
250
251		package_module {
252			name: "package",
253			deps: ["foo"],
254			arch: {
255				arm64: {
256					deps: ["bar"],
257				},
258				x86_64: {
259					deps: ["baz"],
260				},
261			},
262			compile_multilib: "both",
263		}
264		`, []string{"lib32/foo", "lib64/foo", "lib64/bar"})
265}
266
267func TestPackagingBaseSingleTarget(t *testing.T) {
268	config := testConfig{
269		multiTarget:                false,
270		depsCollectFirstTargetOnly: false,
271	}
272	runPackagingTest(t, config,
273		`
274		component {
275			name: "foo",
276		}
277
278		package_module {
279			name: "package",
280			deps: ["foo"],
281		}
282		`, []string{"lib64/foo"})
283
284	runPackagingTest(t, config,
285		`
286		component {
287			name: "foo",
288			deps: ["bar"],
289		}
290
291		component {
292			name: "bar",
293		}
294
295		package_module {
296			name: "package",
297			deps: ["foo"],
298		}
299		`, []string{"lib64/foo", "lib64/bar"})
300
301	runPackagingTest(t, config,
302		`
303		component {
304			name: "foo",
305		}
306
307		component {
308			name: "bar",
309			compile_multilib: "32",
310		}
311
312		package_module {
313			name: "package",
314			deps: ["foo"],
315			multilib: {
316				lib32: {
317					deps: ["bar"],
318				},
319			},
320		}
321		`, []string{"lib64/foo"})
322
323	runPackagingTest(t, config,
324		`
325		component {
326			name: "foo",
327		}
328
329		component {
330			name: "bar",
331		}
332
333		package_module {
334			name: "package",
335			deps: ["foo"],
336			multilib: {
337				lib64: {
338					deps: ["bar"],
339				},
340			},
341		}
342		`, []string{"lib64/foo", "lib64/bar"})
343
344	runPackagingTest(t, config,
345		`
346		component {
347			name: "foo",
348		}
349
350		component {
351			name: "bar",
352		}
353
354		component {
355			name: "baz",
356		}
357
358		package_module {
359			name: "package",
360			deps: ["foo"],
361			arch: {
362				arm64: {
363					deps: ["bar"],
364				},
365				x86_64: {
366					deps: ["baz"],
367				},
368			},
369		}
370		`, []string{"lib64/foo", "lib64/bar"})
371
372	runPackagingTest(t, config,
373		`
374		component {
375			name: "foo",
376		}
377
378		component {
379			name: "bar",
380		}
381
382		package_module {
383			name: "package",
384			deps: ["foo"],
385			install_deps: ["bar"],
386		}
387		`, []string{"lib64/foo"})
388}
389
390func TestPackagingWithSkipInstallDeps(t *testing.T) {
391	// package -[dep]-> foo -[dep]-> bar      -[dep]-> baz
392	// Packaging should continue transitively through modules that are not installed.
393	config := testConfig{
394		multiTarget:                false,
395		depsCollectFirstTargetOnly: false,
396	}
397	runPackagingTest(t, config,
398		`
399		component {
400			name: "foo",
401			deps: ["bar"],
402		}
403
404		component {
405			name: "bar",
406			deps: ["baz"],
407			skip_install: true,
408		}
409
410		component {
411			name: "baz",
412		}
413
414		package_module {
415			name: "package",
416			deps: ["foo"],
417		}
418		`, []string{"lib64/foo", "lib64/bar", "lib64/baz"})
419}
420
421func TestPackagingWithDepsCollectFirstTargetOnly(t *testing.T) {
422	config := testConfig{
423		multiTarget:                true,
424		depsCollectFirstTargetOnly: true,
425	}
426	runPackagingTest(t, config,
427		`
428		component {
429			name: "foo",
430		}
431
432		package_module {
433			name: "package",
434			deps: ["foo"],
435		}
436		`, []string{"lib64/foo"})
437
438	runPackagingTest(t, config,
439		`
440		component {
441			name: "foo",
442			deps: ["bar"],
443		}
444
445		component {
446			name: "bar",
447		}
448
449		package_module {
450			name: "package",
451			deps: ["foo"],
452		}
453		`, []string{"lib64/foo", "lib64/bar"})
454
455	runPackagingTest(t, config,
456		`
457		component {
458			name: "foo",
459			deps: ["bar"],
460		}
461
462		component {
463			name: "bar",
464		}
465
466		package_module {
467			name: "package",
468			deps: ["foo"],
469			compile_multilib: "both",
470		}
471		`, []string{"lib64/foo", "lib64/bar"})
472
473	runPackagingTest(t, config,
474		`
475		component {
476			name: "foo",
477		}
478
479		component {
480			name: "bar",
481			compile_multilib: "32",
482		}
483
484		package_module {
485			name: "package",
486			deps: ["foo"],
487			multilib: {
488				lib32: {
489					deps: ["bar"],
490				},
491			},
492			compile_multilib: "both",
493		}
494		`, []string{"lib32/bar", "lib64/foo"})
495
496	runPackagingTest(t, config,
497		`
498		component {
499			name: "foo",
500		}
501
502		component {
503			name: "bar",
504		}
505
506		package_module {
507			name: "package",
508			deps: ["foo"],
509			multilib: {
510				both: {
511					deps: ["bar"],
512				},
513			},
514			compile_multilib: "both",
515		}
516		`, []string{"lib64/foo", "lib32/bar", "lib64/bar"})
517
518	runPackagingTest(t, config,
519		`
520		component {
521			name: "foo",
522		}
523
524		component {
525			name: "bar",
526		}
527
528		component {
529			name: "baz",
530		}
531
532		package_module {
533			name: "package",
534			deps: ["foo"],
535			arch: {
536				arm64: {
537					deps: ["bar"],
538				},
539				x86_64: {
540					deps: ["baz"],
541				},
542			},
543			compile_multilib: "both",
544		}
545		`, []string{"lib64/foo", "lib64/bar"})
546}
547
548func TestDebuggableDeps(t *testing.T) {
549	bp := `
550		component {
551			name: "foo",
552		}
553
554		component {
555			name: "bar",
556			deps: ["baz"],
557		}
558
559		component {
560			name: "baz",
561		}
562
563		package_module {
564			name: "package",
565			deps: ["foo"] + select(product_variable("debuggable"), {
566				true: ["bar"],
567				default: [],
568			}),
569		}`
570	testcases := []struct {
571		debuggable bool
572		expected   []string
573	}{
574		{
575			debuggable: true,
576			expected:   []string{"lib64/foo", "lib64/bar", "lib64/baz"},
577		},
578		{
579			debuggable: false,
580			expected:   []string{"lib64/foo"},
581		},
582	}
583	for _, tc := range testcases {
584		config := testConfig{
585			debuggable: tc.debuggable,
586		}
587		runPackagingTest(t, config, bp, tc.expected)
588	}
589}
590
591func TestPrefer32Deps(t *testing.T) {
592	bpTemplate := `
593		component {
594			name: "foo",
595			compile_multilib: "both", // not needed but for clarity
596		}
597
598		component {
599			name: "foo_32only",
600			compile_multilib: "prefer32",
601		}
602
603		component {
604			name: "foo_64only",
605			compile_multilib: "64",
606		}
607
608		package_module {
609			name: "package",
610			compile_multilib: "%COMPILE_MULTILIB%",
611			multilib: {
612				prefer32: {
613					deps: %DEPS%,
614				},
615			},
616		}
617	`
618
619	testcases := []struct {
620		compileMultilib string
621		deps            []string
622		expected        []string
623	}{
624		{
625			compileMultilib: "first",
626			deps:            []string{"foo", "foo_64only"},
627			expected:        []string{"lib64/foo", "lib64/foo_64only"},
628		},
629		{
630			compileMultilib: "64",
631			deps:            []string{"foo", "foo_64only"},
632			expected:        []string{"lib64/foo", "lib64/foo_64only"},
633		},
634		{
635			compileMultilib: "32",
636			deps:            []string{"foo", "foo_32only"},
637			expected:        []string{"lib32/foo", "lib32/foo_32only"},
638		},
639		{
640			compileMultilib: "both",
641			deps:            []string{"foo", "foo_32only", "foo_64only"},
642			expected:        []string{"lib32/foo", "lib32/foo_32only", "lib64/foo_64only"},
643		},
644	}
645	for _, tc := range testcases {
646		config := testConfig{
647			multiTarget:                true,
648			depsCollectFirstTargetOnly: true,
649		}
650		bp := strings.Replace(bpTemplate, "%COMPILE_MULTILIB%", tc.compileMultilib, -1)
651		bp = strings.Replace(bp, "%DEPS%", `["`+strings.Join(tc.deps, `", "`)+`"]`, -1)
652		runPackagingTest(t, config, bp, tc.expected)
653	}
654}
655
656func TestOverrides(t *testing.T) {
657	bpTemplate := `
658		component {
659			name: "foo",
660			deps: ["bar"],
661		}
662
663		component {
664			name: "bar",
665		}
666
667		component {
668			name: "bar_override",
669			overrides: ["bar"],
670		}
671
672		component {
673			name: "baz",
674			deps: ["bar_override"],
675		}
676
677		package_module {
678			name: "package",
679			deps: %DEPS%,
680		}
681	`
682	testcases := []struct {
683		deps     []string
684		expected []string
685	}{
686		{
687			deps:     []string{"foo"},
688			expected: []string{"lib64/foo", "lib64/bar"},
689		},
690		{
691			deps:     []string{"foo", "bar_override"},
692			expected: []string{"lib64/foo", "lib64/bar_override"},
693		},
694		{
695			deps:     []string{"foo", "bar", "bar_override"},
696			expected: []string{"lib64/foo", "lib64/bar_override"},
697		},
698		{
699			deps:     []string{"bar", "bar_override"},
700			expected: []string{"lib64/bar_override"},
701		},
702		{
703			deps:     []string{"foo", "baz"},
704			expected: []string{"lib64/foo", "lib64/baz", "lib64/bar_override"},
705		},
706	}
707	for _, tc := range testcases {
708		config := testConfig{
709			multiTarget:                true,
710			depsCollectFirstTargetOnly: false,
711		}
712		bp := strings.Replace(bpTemplate, "%DEPS%", `["`+strings.Join(tc.deps, `", "`)+`"]`, -1)
713		runPackagingTest(t, config, bp, tc.expected)
714	}
715}
716