xref: /aosp_15_r20/build/soong/android/prebuilt_test.go (revision 333d2b3687b3a337dbcca9d65000bca186795e39)
1// Copyright 2016 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	"testing"
19
20	"github.com/google/blueprint"
21)
22
23func TestPrebuilts(t *testing.T) {
24	buildOS := TestArchConfig(t.TempDir(), nil, "", nil).BuildOS
25
26	var prebuiltsTests = []struct {
27		name      string
28		replaceBp bool // modules is added to default bp boilerplate if false.
29		modules   string
30		prebuilt  []OsType
31		preparer  FixturePreparer
32	}{
33		{
34			name: "no prebuilt",
35			modules: `
36				source {
37					name: "bar",
38				}`,
39			prebuilt: nil,
40		},
41		{
42			name: "no source prebuilt not preferred",
43			modules: `
44				prebuilt {
45					name: "bar",
46					prefer: false,
47					srcs: ["prebuilt_file"],
48				}`,
49			prebuilt: []OsType{Android, buildOS},
50		},
51		{
52			name: "no source prebuilt preferred",
53			modules: `
54				prebuilt {
55					name: "bar",
56					prefer: true,
57					srcs: ["prebuilt_file"],
58				}`,
59			prebuilt: []OsType{Android, buildOS},
60		},
61		{
62			name: "prebuilt not preferred",
63			modules: `
64				source {
65					name: "bar",
66				}
67
68				prebuilt {
69					name: "bar",
70					prefer: false,
71					srcs: ["prebuilt_file"],
72				}`,
73			prebuilt: nil,
74		},
75		{
76			name: "prebuilt preferred",
77			modules: `
78				source {
79					name: "bar",
80				}
81
82				prebuilt {
83					name: "bar",
84					prefer: true,
85					srcs: ["prebuilt_file"],
86				}`,
87			prebuilt: []OsType{Android, buildOS},
88		},
89		{
90			name: "prebuilt no file not preferred",
91			modules: `
92				source {
93					name: "bar",
94				}
95
96				prebuilt {
97					name: "bar",
98					prefer: false,
99				}`,
100			prebuilt: nil,
101		},
102		{
103			name: "prebuilt no file preferred",
104			modules: `
105				source {
106					name: "bar",
107				}
108
109				prebuilt {
110					name: "bar",
111					prefer: true,
112				}`,
113			prebuilt: nil,
114		},
115		{
116			name: "prebuilt file from filegroup preferred",
117			modules: `
118				filegroup {
119					name: "fg",
120					srcs: ["prebuilt_file"],
121				}
122				prebuilt {
123					name: "bar",
124					prefer: true,
125					srcs: [":fg"],
126				}`,
127			prebuilt: []OsType{Android, buildOS},
128		},
129		{
130			name: "prebuilt module for device only",
131			modules: `
132				source {
133					name: "bar",
134				}
135
136				prebuilt {
137					name: "bar",
138					host_supported: false,
139					prefer: true,
140					srcs: ["prebuilt_file"],
141				}`,
142			prebuilt: []OsType{Android},
143		},
144		{
145			name: "prebuilt file for host only",
146			modules: `
147				source {
148					name: "bar",
149				}
150
151				prebuilt {
152					name: "bar",
153					prefer: true,
154					target: {
155						host: {
156							srcs: ["prebuilt_file"],
157						},
158					},
159				}`,
160			prebuilt: []OsType{buildOS},
161		},
162		{
163			name: "prebuilt override not preferred",
164			modules: `
165				source {
166					name: "baz",
167				}
168
169				override_source {
170					name: "bar",
171					base: "baz",
172				}
173
174				prebuilt {
175					name: "bar",
176					prefer: false,
177					srcs: ["prebuilt_file"],
178				}`,
179			prebuilt: nil,
180		},
181		{
182			name: "prebuilt override preferred",
183			modules: `
184				source {
185					name: "baz",
186				}
187
188				override_source {
189					name: "bar",
190					base: "baz",
191				}
192
193				prebuilt {
194					name: "bar",
195					prefer: true,
196					srcs: ["prebuilt_file"],
197				}`,
198			prebuilt: []OsType{Android, buildOS},
199		},
200		{
201			name:      "prebuilt including default-disabled OS",
202			replaceBp: true,
203			modules: `
204				source {
205					name: "foo",
206					deps: [":bar"],
207					target: {
208						windows: {
209							enabled: true,
210						},
211					},
212				}
213
214				source {
215					name: "bar",
216					target: {
217						windows: {
218							enabled: true,
219						},
220					},
221				}
222
223				prebuilt {
224					name: "bar",
225					prefer: true,
226					srcs: ["prebuilt_file"],
227					target: {
228						windows: {
229							enabled: true,
230						},
231					},
232				}`,
233			prebuilt: []OsType{Android, buildOS, Windows},
234		},
235		{
236			name:      "fall back to source for default-disabled OS",
237			replaceBp: true,
238			modules: `
239				source {
240					name: "foo",
241					deps: [":bar"],
242					target: {
243						windows: {
244							enabled: true,
245						},
246					},
247				}
248
249				source {
250					name: "bar",
251					target: {
252						windows: {
253							enabled: true,
254						},
255					},
256				}
257
258				prebuilt {
259					name: "bar",
260					prefer: true,
261					srcs: ["prebuilt_file"],
262				}`,
263			prebuilt: []OsType{Android, buildOS},
264		},
265		{
266			name:      "prebuilt properties customizable",
267			replaceBp: true,
268			modules: `
269				source {
270					name: "foo",
271					deps: [":bar"],
272				}
273
274				soong_config_module_type {
275					name: "prebuilt_with_config",
276					module_type: "prebuilt",
277					config_namespace: "any_namespace",
278					bool_variables: ["bool_var"],
279					properties: ["prefer"],
280				}
281
282				prebuilt_with_config {
283					name: "bar",
284					prefer: true,
285					srcs: ["prebuilt_file"],
286					soong_config_variables: {
287						bool_var: {
288							prefer: false,
289							conditions_default: {
290								prefer: true,
291							},
292						},
293					},
294				}`,
295			prebuilt: []OsType{Android, buildOS},
296		},
297	}
298
299	fs := MockFS{
300		"prebuilt_file": nil,
301		"source_file":   nil,
302	}
303
304	for _, test := range prebuiltsTests {
305		t.Run(test.name, func(t *testing.T) {
306			bp := test.modules
307			if !test.replaceBp {
308				bp = bp + `
309					source {
310						name: "foo",
311						deps: [":bar"],
312					}`
313			}
314
315			// Add windows to the target list to test the logic when a variant is
316			// disabled by default.
317			if !Windows.DefaultDisabled {
318				t.Errorf("windows is assumed to be disabled by default")
319			}
320
321			result := GroupFixturePreparers(
322				PrepareForTestWithArchMutator,
323				PrepareForTestWithPrebuilts,
324				PrepareForTestWithOverrides,
325				PrepareForTestWithFilegroup,
326				// Add a Windows target to the configuration.
327				FixtureModifyConfig(func(config Config) {
328					config.Targets[Windows] = []Target{
329						{Windows, Arch{ArchType: X86_64}, NativeBridgeDisabled, "", "", true},
330					}
331				}),
332				fs.AddToFixture(),
333				FixtureRegisterWithContext(registerTestPrebuiltModules),
334				OptionalFixturePreparer(test.preparer),
335			).RunTestWithBp(t, bp)
336
337			for _, variant := range result.ModuleVariantsForTests("foo") {
338				foo := result.ModuleForTests("foo", variant)
339				t.Run(foo.Module().Target().Os.String(), func(t *testing.T) {
340					var dependsOnSourceModule, dependsOnPrebuiltModule bool
341					result.VisitDirectDeps(foo.Module(), func(m blueprint.Module) {
342						if _, ok := m.(*sourceModule); ok {
343							dependsOnSourceModule = true
344						}
345						if p, ok := m.(*prebuiltModule); ok {
346							dependsOnPrebuiltModule = true
347							if !p.Prebuilt().properties.UsePrebuilt {
348								t.Errorf("dependency on prebuilt module not marked used")
349							}
350						}
351					})
352
353					moduleIsDisabled := !foo.Module().Enabled(PanickingConfigAndErrorContext(result.TestContext))
354					deps := foo.Module().(*sourceModule).deps
355					if moduleIsDisabled {
356						if len(deps) > 0 {
357							t.Errorf("disabled module got deps: %v", deps)
358						}
359					} else {
360						if len(deps) != 1 {
361							t.Errorf("deps does not have single path, but is %v", deps)
362						}
363					}
364
365					var usingSourceFile, usingPrebuiltFile bool
366					if len(deps) > 0 && deps[0].String() == "source_file" {
367						usingSourceFile = true
368					}
369					if len(deps) > 0 && deps[0].String() == "prebuilt_file" {
370						usingPrebuiltFile = true
371					}
372
373					prebuilt := false
374					for _, os := range test.prebuilt {
375						if os == foo.Module().Target().Os {
376							prebuilt = true
377						}
378					}
379
380					if prebuilt {
381						if moduleIsDisabled {
382							t.Errorf("dependent module for prebuilt is disabled")
383						}
384
385						if !dependsOnPrebuiltModule {
386							t.Errorf("doesn't depend on prebuilt module")
387						}
388						if !usingPrebuiltFile {
389							t.Errorf("doesn't use prebuilt_file")
390						}
391
392						if dependsOnSourceModule {
393							t.Errorf("depends on source module")
394						}
395						if usingSourceFile {
396							t.Errorf("using source_file")
397						}
398					} else if !moduleIsDisabled {
399						if dependsOnPrebuiltModule {
400							t.Errorf("depends on prebuilt module")
401						}
402						if usingPrebuiltFile {
403							t.Errorf("using prebuilt_file")
404						}
405
406						if !dependsOnSourceModule {
407							t.Errorf("doesn't depend on source module")
408						}
409						if !usingSourceFile {
410							t.Errorf("doesn't use source_file")
411						}
412					}
413				})
414			}
415		})
416	}
417}
418
419func testPrebuiltErrorWithFixture(t *testing.T, expectedError, bp string, fixture FixturePreparer) {
420	t.Helper()
421	fs := MockFS{
422		"prebuilt_file": nil,
423	}
424	GroupFixturePreparers(
425		PrepareForTestWithArchMutator,
426		PrepareForTestWithPrebuilts,
427		PrepareForTestWithOverrides,
428		fs.AddToFixture(),
429		FixtureRegisterWithContext(registerTestPrebuiltModules),
430		OptionalFixturePreparer(fixture),
431	).
432		ExtendWithErrorHandler(FixtureExpectsAtLeastOneErrorMatchingPattern(expectedError)).
433		RunTestWithBp(t, bp)
434
435}
436
437func testPrebuiltError(t *testing.T, expectedError, bp string) {
438	testPrebuiltErrorWithFixture(t, expectedError, bp, nil)
439}
440
441func TestPrebuiltShouldNotChangePartition(t *testing.T) {
442	testPrebuiltError(t, `partition is different`, `
443		source {
444			name: "foo",
445			vendor: true,
446		}
447		prebuilt {
448			name: "foo",
449			prefer: true,
450			srcs: ["prebuilt_file"],
451		}`)
452}
453
454func TestPrebuiltShouldNotChangePartition_WithOverride(t *testing.T) {
455	testPrebuiltError(t, `partition is different`, `
456		source {
457			name: "foo",
458			vendor: true,
459		}
460		override_source {
461			name: "bar",
462			base: "foo",
463		}
464		prebuilt {
465			name: "bar",
466			prefer: true,
467			srcs: ["prebuilt_file"],
468		}`)
469}
470
471func registerTestPrebuiltBuildComponents(ctx RegistrationContext) {
472	registerTestPrebuiltModules(ctx)
473
474	RegisterPrebuiltMutators(ctx)
475	ctx.PostDepsMutators(RegisterOverridePostDepsMutators)
476}
477
478var prepareForTestWithFakePrebuiltModules = FixtureRegisterWithContext(registerTestPrebuiltModules)
479
480func registerTestPrebuiltModules(ctx RegistrationContext) {
481	ctx.RegisterModuleType("prebuilt", newPrebuiltModule)
482	ctx.RegisterModuleType("source", newSourceModule)
483	ctx.RegisterModuleType("override_source", newOverrideSourceModule)
484	ctx.RegisterModuleType("soong_config_module_type", SoongConfigModuleTypeFactory)
485	ctx.RegisterModuleType("soong_config_string_variable", SoongConfigStringVariableDummyFactory)
486	ctx.RegisterModuleType("soong_config_bool_variable", SoongConfigBoolVariableDummyFactory)
487	RegisterApexContributionsBuildComponents(ctx)
488}
489
490type prebuiltModule struct {
491	ModuleBase
492	prebuilt   Prebuilt
493	properties struct {
494		Srcs []string `android:"path,arch_variant"`
495	}
496}
497
498func newPrebuiltModule() Module {
499	m := &prebuiltModule{}
500	m.AddProperties(&m.properties)
501	InitPrebuiltModule(m, &m.properties.Srcs)
502	InitAndroidArchModule(m, HostAndDeviceDefault, MultilibCommon)
503	return m
504}
505
506func (p *prebuiltModule) Name() string {
507	return p.prebuilt.Name(p.ModuleBase.Name())
508}
509
510func (p *prebuiltModule) GenerateAndroidBuildActions(ctx ModuleContext) {
511	if len(p.properties.Srcs) >= 1 {
512		src := p.prebuilt.SingleSourcePath(ctx)
513		ctx.SetOutputFiles(Paths{src}, "")
514	}
515}
516
517func (p *prebuiltModule) Prebuilt() *Prebuilt {
518	return &p.prebuilt
519}
520
521type sourceModuleProperties struct {
522	Deps []string `android:"path,arch_variant"`
523}
524
525type sourceModule struct {
526	ModuleBase
527	OverridableModuleBase
528
529	properties                                     sourceModuleProperties
530	dependsOnSourceModule, dependsOnPrebuiltModule bool
531	deps                                           Paths
532	src                                            Path
533}
534
535func newSourceModule() Module {
536	m := &sourceModule{}
537	m.AddProperties(&m.properties)
538	InitAndroidArchModule(m, HostAndDeviceDefault, MultilibCommon)
539	InitOverridableModule(m, nil)
540	return m
541}
542
543func (s *sourceModule) OverridablePropertiesDepsMutator(ctx BottomUpMutatorContext) {
544	// s.properties.Deps are annotated with android:path, so they are
545	// automatically added to the dependency by pathDeps mutator
546}
547
548func (s *sourceModule) GenerateAndroidBuildActions(ctx ModuleContext) {
549	s.deps = PathsForModuleSrc(ctx, s.properties.Deps)
550	s.src = PathForModuleSrc(ctx, "source_file")
551}
552
553func (s *sourceModule) Srcs() Paths {
554	return Paths{s.src}
555}
556
557type overrideSourceModule struct {
558	ModuleBase
559	OverrideModuleBase
560}
561
562func (o *overrideSourceModule) GenerateAndroidBuildActions(_ ModuleContext) {
563}
564
565func newOverrideSourceModule() Module {
566	m := &overrideSourceModule{}
567	m.AddProperties(&sourceModuleProperties{})
568
569	InitAndroidArchModule(m, HostAndDeviceDefault, MultilibCommon)
570	InitOverrideModule(m)
571	return m
572}
573
574func TestPrebuiltErrorCannotListBothSourceAndPrebuiltInContributions(t *testing.T) {
575	selectMainlineModuleContritbutions := GroupFixturePreparers(
576		PrepareForTestWithBuildFlag("RELEASE_APEX_CONTRIBUTIONS_ADSERVICES", "my_apex_contributions"),
577	)
578	testPrebuiltErrorWithFixture(t, `Found duplicate variations of the same module in apex_contributions: foo and prebuilt_foo. Please remove one of these`, `
579		source {
580			name: "foo",
581		}
582		prebuilt {
583			name: "foo",
584			srcs: ["prebuilt_file"],
585		}
586		apex_contributions {
587			name: "my_apex_contributions",
588			api_domain: "my_mainline_module",
589			contents: [
590			  "foo",
591			  "prebuilt_foo",
592			],
593		}
594		all_apex_contributions {
595			name: "all_apex_contributions",
596		}
597		`, selectMainlineModuleContritbutions)
598}
599