• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1package android
2
3import (
4	"testing"
5
6	"github.com/google/blueprint"
7)
8
9var licensesTests = []struct {
10	name                string
11	fs                  MockFS
12	expectedErrors      []string
13	effectivePackage    map[string]string
14	effectiveNotices    map[string][]string
15	effectiveKinds      map[string][]string
16	effectiveConditions map[string][]string
17}{
18	{
19		name: "invalid module type without licenses property",
20		fs: map[string][]byte{
21			"top/Android.bp": []byte(`
22				mock_bad_module {
23					name: "libexample",
24				}`),
25		},
26		expectedErrors: []string{`module type "mock_bad_module" must have an applicable licenses property`},
27	},
28	{
29		name: "license must exist",
30		fs: map[string][]byte{
31			"top/Android.bp": []byte(`
32				mock_library {
33					name: "libexample",
34					licenses: ["notice"],
35				}`),
36		},
37		expectedErrors: []string{`"libexample" depends on undefined module "notice"`},
38	},
39	{
40		name: "all good",
41		fs: map[string][]byte{
42			"top/Android.bp": []byte(`
43				license_kind {
44					name: "notice",
45					conditions: ["shownotice"],
46				}
47
48				license {
49					name: "top_Apache2",
50					license_kinds: ["notice"],
51					package_name: "topDog",
52					license_text: ["LICENSE", "NOTICE"],
53				}
54
55				mock_library {
56					name: "libexample1",
57					licenses: ["top_Apache2"],
58				}`),
59			"top/nested/Android.bp": []byte(`
60				mock_library {
61					name: "libnested",
62					licenses: ["top_Apache2"],
63				}`),
64			"other/Android.bp": []byte(`
65				mock_library {
66					name: "libother",
67					licenses: ["top_Apache2"],
68				}`),
69		},
70		effectiveKinds: map[string][]string{
71			"libexample1": []string{"notice"},
72			"libnested":   []string{"notice"},
73			"libother":    []string{"notice"},
74		},
75		effectivePackage: map[string]string{
76			"libexample1": "topDog",
77			"libnested":   "topDog",
78			"libother":    "topDog",
79		},
80		effectiveConditions: map[string][]string{
81			"libexample1": []string{"shownotice"},
82			"libnested":   []string{"shownotice"},
83			"libother":    []string{"shownotice"},
84		},
85		effectiveNotices: map[string][]string{
86			"libexample1": []string{"top/LICENSE:topDog", "top/NOTICE:topDog"},
87			"libnested":   []string{"top/LICENSE:topDog", "top/NOTICE:topDog"},
88			"libother":    []string{"top/LICENSE:topDog", "top/NOTICE:topDog"},
89		},
90	},
91
92	// Defaults propagation tests
93	{
94		// Check that licenses is the union of the defaults modules.
95		name: "defaults union, basic",
96		fs: map[string][]byte{
97			"top/Android.bp": []byte(`
98				license_kind {
99					name: "top_notice",
100					conditions: ["notice"],
101				}
102
103				license {
104					name: "top_other",
105					license_kinds: ["top_notice"],
106				}
107
108				mock_defaults {
109					name: "libexample_defaults",
110					licenses: ["top_other"],
111				}
112				mock_library {
113					name: "libexample",
114					licenses: ["nested_other"],
115					defaults: ["libexample_defaults"],
116				}
117				mock_library {
118					name: "libsamepackage",
119					deps: ["libexample"],
120				}`),
121			"top/nested/Android.bp": []byte(`
122				license_kind {
123					name: "nested_notice",
124					conditions: ["notice"],
125				}
126
127				license {
128					name: "nested_other",
129					license_kinds: ["nested_notice"],
130				}
131
132				mock_library {
133					name: "libnested",
134					deps: ["libexample"],
135				}`),
136			"other/Android.bp": []byte(`
137				mock_library {
138					name: "libother",
139					deps: ["libexample"],
140				}`),
141		},
142		effectiveKinds: map[string][]string{
143			"libexample":     []string{"nested_notice", "top_notice"},
144			"libsamepackage": []string{},
145			"libnested":      []string{},
146			"libother":       []string{},
147		},
148		effectiveConditions: map[string][]string{
149			"libexample":     []string{"notice"},
150			"libsamepackage": []string{},
151			"libnested":      []string{},
152			"libother":       []string{},
153		},
154	},
155	{
156		name: "defaults union, multiple defaults",
157		fs: map[string][]byte{
158			"top/Android.bp": []byte(`
159				license {
160					name: "top",
161				}
162				mock_defaults {
163					name: "libexample_defaults_1",
164					licenses: ["other"],
165				}
166				mock_defaults {
167					name: "libexample_defaults_2",
168					licenses: ["top_nested"],
169				}
170				mock_library {
171					name: "libexample",
172					defaults: ["libexample_defaults_1", "libexample_defaults_2"],
173				}
174				mock_library {
175					name: "libsamepackage",
176					deps: ["libexample"],
177				}`),
178			"top/nested/Android.bp": []byte(`
179				license {
180					name: "top_nested",
181					license_text: ["LICENSE.txt"],
182				}
183				mock_library {
184					name: "libnested",
185					deps: ["libexample"],
186				}`),
187			"other/Android.bp": []byte(`
188				license {
189					name: "other",
190				}
191				mock_library {
192					name: "libother",
193					deps: ["libexample"],
194				}`),
195			"outsider/Android.bp": []byte(`
196				mock_library {
197					name: "liboutsider",
198					deps: ["libexample"],
199				}`),
200		},
201		effectiveKinds: map[string][]string{
202			"libexample":     []string{},
203			"libsamepackage": []string{},
204			"libnested":      []string{},
205			"libother":       []string{},
206			"liboutsider":    []string{},
207		},
208		effectiveNotices: map[string][]string{
209			"libexample":     []string{"top/nested/LICENSE.txt"},
210			"libsamepackage": []string{},
211			"libnested":      []string{},
212			"libother":       []string{},
213			"liboutsider":    []string{},
214		},
215	},
216
217	// Defaults module's defaults_licenses tests
218	{
219		name: "defaults_licenses invalid",
220		fs: map[string][]byte{
221			"top/Android.bp": []byte(`
222				mock_defaults {
223					name: "top_defaults",
224					licenses: ["notice"],
225				}`),
226		},
227		expectedErrors: []string{`"top_defaults" depends on undefined module "notice"`},
228	},
229	{
230		name: "defaults_licenses overrides package default",
231		fs: map[string][]byte{
232			"top/Android.bp": []byte(`
233				package {
234					default_applicable_licenses: ["by_exception_only"],
235				}
236				license {
237					name: "by_exception_only",
238				}
239				license {
240					name: "notice",
241				}
242				mock_defaults {
243					name: "top_defaults",
244					licenses: ["notice"],
245				}
246				mock_library {
247					name: "libexample",
248				}
249				mock_library {
250					name: "libdefaults",
251					defaults: ["top_defaults"],
252				}`),
253		},
254	},
255
256	// Package default_applicable_licenses tests
257	{
258		name: "package default_applicable_licenses must exist",
259		fs: map[string][]byte{
260			"top/Android.bp": []byte(`
261				package {
262					default_applicable_licenses: ["notice"],
263				}`),
264		},
265		expectedErrors: []string{`"//top" depends on undefined module "notice"`},
266	},
267	{
268		// This test relies on the default licenses being legacy_public.
269		name: "package default_applicable_licenses property used when no licenses specified",
270		fs: map[string][]byte{
271			"top/Android.bp": []byte(`
272				package {
273					default_applicable_licenses: ["top_notice"],
274				}
275
276				license {
277					name: "top_notice",
278				}
279				mock_library {
280					name: "libexample",
281				}`),
282			"outsider/Android.bp": []byte(`
283				mock_library {
284					name: "liboutsider",
285					deps: ["libexample"],
286				}`),
287		},
288	},
289	{
290		name: "package default_applicable_licenses not inherited to subpackages",
291		fs: map[string][]byte{
292			"top/Android.bp": []byte(`
293				package {
294					default_applicable_licenses: ["top_notice"],
295				}
296				license {
297					name: "top_notice",
298				}
299				mock_library {
300					name: "libexample",
301				}`),
302			"top/nested/Android.bp": []byte(`
303				package {
304					default_applicable_licenses: ["outsider"],
305				}
306
307				mock_library {
308					name: "libnested",
309				}`),
310			"top/other/Android.bp": []byte(`
311				mock_library {
312					name: "libother",
313				}`),
314			"outsider/Android.bp": []byte(`
315				license {
316					name: "outsider",
317				}
318				mock_library {
319					name: "liboutsider",
320					deps: ["libexample", "libother", "libnested"],
321				}`),
322		},
323	},
324	{
325		name: "verify that prebuilt dependencies are included",
326		fs: map[string][]byte{
327			"prebuilts/Android.bp": []byte(`
328				license {
329					name: "prebuilt"
330				}
331				prebuilt {
332					name: "module",
333					licenses: ["prebuilt"],
334				}`),
335			"top/sources/source_file": nil,
336			"top/sources/Android.bp": []byte(`
337				license {
338					name: "top_sources"
339				}
340				source {
341					name: "module",
342					licenses: ["top_sources"],
343				}`),
344			"top/other/source_file": nil,
345			"top/other/Android.bp": []byte(`
346				source {
347					name: "other",
348					deps: [":module"],
349				}`),
350		},
351	},
352	{
353		name: "verify that prebuilt dependencies are ignored for licenses reasons (preferred)",
354		fs: map[string][]byte{
355			"prebuilts/Android.bp": []byte(`
356				license {
357					name: "prebuilt"
358				}
359				prebuilt {
360					name: "module",
361					licenses: ["prebuilt"],
362					prefer: true,
363				}`),
364			"top/sources/source_file": nil,
365			"top/sources/Android.bp": []byte(`
366				license {
367					name: "top_sources"
368				}
369				source {
370					name: "module",
371					licenses: ["top_sources"],
372				}`),
373			"top/other/source_file": nil,
374			"top/other/Android.bp": []byte(`
375				source {
376					name: "other",
377					deps: [":module"],
378				}`),
379		},
380	},
381}
382
383func TestLicenses(t *testing.T) {
384	for _, test := range licensesTests {
385		t.Run(test.name, func(t *testing.T) {
386			// Customize the common license text fixture factory.
387			result := GroupFixturePreparers(
388				prepareForLicenseTest,
389				FixtureRegisterWithContext(func(ctx RegistrationContext) {
390					ctx.RegisterModuleType("mock_bad_module", newMockLicensesBadModule)
391					ctx.RegisterModuleType("mock_library", newMockLicensesLibraryModule)
392					ctx.RegisterModuleType("mock_defaults", defaultsLicensesFactory)
393				}),
394				test.fs.AddToFixture(),
395			).
396				ExtendWithErrorHandler(FixtureExpectsAllErrorsToMatchAPattern(test.expectedErrors)).
397				RunTest(t)
398
399			if test.effectivePackage != nil {
400				checkEffectivePackage(t, result, test.effectivePackage)
401			}
402
403			if test.effectiveNotices != nil {
404				checkEffectiveNotices(t, result, test.effectiveNotices)
405			}
406
407			if test.effectiveKinds != nil {
408				checkEffectiveKinds(t, result, test.effectiveKinds)
409			}
410
411			if test.effectiveConditions != nil {
412				checkEffectiveConditions(t, result, test.effectiveConditions)
413			}
414		})
415	}
416}
417
418func checkEffectivePackage(t *testing.T, result *TestResult, effectivePackage map[string]string) {
419	actualPackage := make(map[string]string)
420	result.Context.Context.VisitAllModules(func(m blueprint.Module) {
421		if _, ok := m.(*licenseModule); ok {
422			return
423		}
424		if _, ok := m.(*licenseKindModule); ok {
425			return
426		}
427		if _, ok := m.(*packageModule); ok {
428			return
429		}
430		module, ok := m.(Module)
431		if !ok {
432			t.Errorf("%q not a module", m.Name())
433			return
434		}
435		base := module.base()
436		if base == nil {
437			return
438		}
439
440		if base.commonProperties.Effective_package_name == nil {
441			actualPackage[m.Name()] = ""
442		} else {
443			actualPackage[m.Name()] = *base.commonProperties.Effective_package_name
444		}
445	})
446
447	for moduleName, expectedPackage := range effectivePackage {
448		packageName, ok := actualPackage[moduleName]
449		if !ok {
450			packageName = ""
451		}
452		if expectedPackage != packageName {
453			t.Errorf("effective package mismatch for module %q: expected %q, found %q", moduleName, expectedPackage, packageName)
454		}
455	}
456}
457
458func checkEffectiveNotices(t *testing.T, result *TestResult, effectiveNotices map[string][]string) {
459	actualNotices := make(map[string][]string)
460	result.Context.Context.VisitAllModules(func(m blueprint.Module) {
461		if _, ok := m.(*licenseModule); ok {
462			return
463		}
464		if _, ok := m.(*licenseKindModule); ok {
465			return
466		}
467		if _, ok := m.(*packageModule); ok {
468			return
469		}
470		module, ok := m.(Module)
471		if !ok {
472			t.Errorf("%q not a module", m.Name())
473			return
474		}
475		base := module.base()
476		if base == nil {
477			return
478		}
479		actualNotices[m.Name()] = base.commonProperties.Effective_license_text.Strings()
480	})
481
482	for moduleName, expectedNotices := range effectiveNotices {
483		notices, ok := actualNotices[moduleName]
484		if !ok {
485			notices = []string{}
486		}
487		if !compareUnorderedStringArrays(expectedNotices, notices) {
488			t.Errorf("effective notice files mismatch for module %q: expected %q, found %q", moduleName, expectedNotices, notices)
489		}
490	}
491}
492
493func checkEffectiveKinds(t *testing.T, result *TestResult, effectiveKinds map[string][]string) {
494	actualKinds := make(map[string][]string)
495	result.Context.Context.VisitAllModules(func(m blueprint.Module) {
496		if _, ok := m.(*licenseModule); ok {
497			return
498		}
499		if _, ok := m.(*licenseKindModule); ok {
500			return
501		}
502		if _, ok := m.(*packageModule); ok {
503			return
504		}
505		module, ok := m.(Module)
506		if !ok {
507			t.Errorf("%q not a module", m.Name())
508			return
509		}
510		base := module.base()
511		if base == nil {
512			return
513		}
514		actualKinds[m.Name()] = base.commonProperties.Effective_license_kinds
515	})
516
517	for moduleName, expectedKinds := range effectiveKinds {
518		kinds, ok := actualKinds[moduleName]
519		if !ok {
520			kinds = []string{}
521		}
522		if !compareUnorderedStringArrays(expectedKinds, kinds) {
523			t.Errorf("effective license kinds mismatch for module %q: expected %q, found %q", moduleName, expectedKinds, kinds)
524		}
525	}
526}
527
528func checkEffectiveConditions(t *testing.T, result *TestResult, effectiveConditions map[string][]string) {
529	actualConditions := make(map[string][]string)
530	result.Context.Context.VisitAllModules(func(m blueprint.Module) {
531		if _, ok := m.(*licenseModule); ok {
532			return
533		}
534		if _, ok := m.(*licenseKindModule); ok {
535			return
536		}
537		if _, ok := m.(*packageModule); ok {
538			return
539		}
540		module, ok := m.(Module)
541		if !ok {
542			t.Errorf("%q not a module", m.Name())
543			return
544		}
545		base := module.base()
546		if base == nil {
547			return
548		}
549		actualConditions[m.Name()] = base.commonProperties.Effective_license_conditions
550	})
551
552	for moduleName, expectedConditions := range effectiveConditions {
553		conditions, ok := actualConditions[moduleName]
554		if !ok {
555			conditions = []string{}
556		}
557		if !compareUnorderedStringArrays(expectedConditions, conditions) {
558			t.Errorf("effective license conditions mismatch for module %q: expected %q, found %q", moduleName, expectedConditions, conditions)
559		}
560	}
561}
562
563func compareUnorderedStringArrays(expected, actual []string) bool {
564	if len(expected) != len(actual) {
565		return false
566	}
567	s := make(map[string]int)
568	for _, v := range expected {
569		s[v] += 1
570	}
571	for _, v := range actual {
572		c, ok := s[v]
573		if !ok {
574			return false
575		}
576		if c < 1 {
577			return false
578		}
579		s[v] -= 1
580	}
581	return true
582}
583
584type mockLicensesBadProperties struct {
585	Visibility []string
586}
587
588type mockLicensesBadModule struct {
589	ModuleBase
590	DefaultableModuleBase
591	properties mockLicensesBadProperties
592}
593
594func newMockLicensesBadModule() Module {
595	m := &mockLicensesBadModule{}
596
597	base := m.base()
598	m.AddProperties(&base.nameProperties, &m.properties)
599
600	// The default_visibility property needs to be checked and parsed by the visibility module during
601	// its checking and parsing phases so make it the primary visibility property.
602	setPrimaryVisibilityProperty(m, "visibility", &m.properties.Visibility)
603
604	initAndroidModuleBase(m)
605	InitDefaultableModule(m)
606
607	return m
608}
609
610func (m *mockLicensesBadModule) GenerateAndroidBuildActions(ModuleContext) {
611}
612
613type mockLicensesLibraryProperties struct {
614	Deps []string
615}
616
617type mockLicensesLibraryModule struct {
618	ModuleBase
619	DefaultableModuleBase
620	properties mockLicensesLibraryProperties
621}
622
623func newMockLicensesLibraryModule() Module {
624	m := &mockLicensesLibraryModule{}
625	m.AddProperties(&m.properties)
626	InitAndroidArchModule(m, HostAndDeviceSupported, MultilibCommon)
627	InitDefaultableModule(m)
628	return m
629}
630
631type dependencyLicensesTag struct {
632	blueprint.BaseDependencyTag
633	name string
634}
635
636func (j *mockLicensesLibraryModule) DepsMutator(ctx BottomUpMutatorContext) {
637	ctx.AddVariationDependencies(nil, dependencyLicensesTag{name: "mockdeps"}, j.properties.Deps...)
638}
639
640func (p *mockLicensesLibraryModule) GenerateAndroidBuildActions(ModuleContext) {
641}
642
643type mockLicensesDefaults struct {
644	ModuleBase
645	DefaultsModuleBase
646}
647
648func defaultsLicensesFactory() Module {
649	m := &mockLicensesDefaults{}
650	InitDefaultsModule(m)
651	return m
652}
653