xref: /aosp_15_r20/build/soong/java/bootclasspath_fragment_test.go (revision 333d2b3687b3a337dbcca9d65000bca186795e39)
1// Copyright (C) 2021 The Android Open Source Project
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 java
16
17import (
18	"strings"
19	"testing"
20
21	"android/soong/android"
22	"android/soong/dexpreopt"
23)
24
25// Contains some simple tests for bootclasspath_fragment logic, additional tests can be found in
26// apex/bootclasspath_fragment_test.go as the ART boot image requires modules from the ART apex.
27
28var prepareForTestWithBootclasspathFragment = android.GroupFixturePreparers(
29	PrepareForTestWithJavaDefaultModules,
30	dexpreopt.PrepareForTestByEnablingDexpreopt,
31)
32
33func TestBootclasspathFragment_UnknownImageName(t *testing.T) {
34	prepareForTestWithBootclasspathFragment.
35		ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(
36			`\Qimage_name: unknown image name "unknown", expected "art"\E`)).
37		RunTestWithBp(t, `
38			bootclasspath_fragment {
39				name: "unknown-bootclasspath-fragment",
40				image_name: "unknown",
41				contents: ["foo"],
42			}
43
44			java_library {
45				name: "foo",
46				srcs: ["foo.java"],
47				installable: true,
48			}
49		`)
50}
51
52func TestPrebuiltBootclasspathFragment_UnknownImageName(t *testing.T) {
53	prepareForTestWithBootclasspathFragment.
54		ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(
55			`\Qimage_name: unknown image name "unknown", expected "art"\E`)).
56		RunTestWithBp(t, `
57			prebuilt_bootclasspath_fragment {
58				name: "unknown-bootclasspath-fragment",
59				image_name: "unknown",
60				contents: ["foo"],
61			}
62
63			java_import {
64				name: "foo",
65				jars: ["foo.jar"],
66			}
67		`)
68}
69
70func TestBootclasspathFragmentInconsistentArtConfiguration_Platform(t *testing.T) {
71	android.GroupFixturePreparers(
72		prepareForTestWithBootclasspathFragment,
73		dexpreopt.FixtureSetArtBootJars("platform:foo", "apex:bar"),
74	).
75		ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(
76			`\QArtApexJars is invalid as it requests a platform variant of "foo"\E`)).
77		RunTestWithBp(t, `
78			bootclasspath_fragment {
79				name: "bootclasspath-fragment",
80				image_name: "art",
81				contents: ["foo", "bar"],
82				apex_available: [
83					"apex",
84				],
85			}
86
87			java_library {
88				name: "foo",
89				srcs: ["foo.java"],
90				installable: true,
91			}
92
93			java_library {
94				name: "bar",
95				srcs: ["bar.java"],
96				installable: true,
97			}
98		`)
99}
100
101func TestBootclasspathFragmentInconsistentArtConfiguration_ApexMixture(t *testing.T) {
102	android.GroupFixturePreparers(
103		prepareForTestWithBootclasspathFragment,
104		dexpreopt.FixtureSetArtBootJars("apex1:foo", "apex2:bar"),
105	).
106		ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(
107			`\QArtApexJars configuration is inconsistent, expected all jars to be in the same apex but it specifies apex "apex1" and "apex2"\E`)).
108		RunTestWithBp(t, `
109			bootclasspath_fragment {
110				name: "bootclasspath-fragment",
111				image_name: "art",
112				contents: ["foo", "bar"],
113				apex_available: [
114					"apex1",
115					"apex2",
116				],
117			}
118
119			java_library {
120				name: "foo",
121				srcs: ["foo.java"],
122				installable: true,
123			}
124
125			java_library {
126				name: "bar",
127				srcs: ["bar.java"],
128				installable: true,
129			}
130		`)
131}
132
133func TestBootclasspathFragment_Coverage(t *testing.T) {
134	prepareWithBp := android.FixtureWithRootAndroidBp(`
135		bootclasspath_fragment {
136			name: "myfragment",
137			contents: [
138				"mybootlib",
139			],
140			api: {
141				stub_libs: [
142					"mysdklibrary",
143				],
144			},
145			coverage: {
146				contents: [
147					"coveragelib",
148				],
149				api: {
150					stub_libs: [
151						"mycoveragestubs",
152					],
153				},
154			},
155			hidden_api: {
156				split_packages: ["*"],
157			},
158		}
159
160		java_library {
161			name: "mybootlib",
162			srcs: ["Test.java"],
163			system_modules: "none",
164			sdk_version: "none",
165			compile_dex: true,
166		}
167
168		java_library {
169			name: "coveragelib",
170			srcs: ["Test.java"],
171			system_modules: "none",
172			sdk_version: "none",
173			compile_dex: true,
174		}
175
176		java_sdk_library {
177			name: "mysdklibrary",
178			srcs: ["Test.java"],
179			compile_dex: true,
180			public: {enabled: true},
181			system: {enabled: true},
182		}
183
184		java_sdk_library {
185			name: "mycoveragestubs",
186			srcs: ["Test.java"],
187			compile_dex: true,
188			public: {enabled: true},
189		}
190	`)
191
192	checkContents := func(t *testing.T, result *android.TestResult, expected ...string) {
193		module := result.Module("myfragment", "android_common").(*BootclasspathFragmentModule)
194		eval := module.ConfigurableEvaluator(android.PanickingConfigAndErrorContext(result.TestContext))
195		android.AssertArrayString(t, "contents property", expected, module.properties.Contents.GetOrDefault(eval, nil))
196	}
197
198	preparer := android.GroupFixturePreparers(
199		prepareForTestWithBootclasspathFragment,
200		PrepareForTestWithJavaSdkLibraryFiles,
201		FixtureWithLastReleaseApis("mysdklibrary", "mycoveragestubs"),
202		FixtureConfigureApexBootJars("someapex:mybootlib"),
203		prepareWithBp,
204	)
205
206	t.Run("without coverage", func(t *testing.T) {
207		result := preparer.RunTest(t)
208		checkContents(t, result, "mybootlib")
209	})
210
211	t.Run("with coverage", func(t *testing.T) {
212		result := android.GroupFixturePreparers(
213			prepareForTestWithFrameworkJacocoInstrumentation,
214			preparer,
215		).RunTest(t)
216		checkContents(t, result, "mybootlib", "coveragelib")
217	})
218}
219
220func TestBootclasspathFragment_StubLibs(t *testing.T) {
221	result := android.GroupFixturePreparers(
222		prepareForTestWithBootclasspathFragment,
223		PrepareForTestWithJavaSdkLibraryFiles,
224		FixtureWithLastReleaseApis("mysdklibrary", "myothersdklibrary", "mycoreplatform"),
225		FixtureConfigureApexBootJars("someapex:mysdklibrary"),
226		android.PrepareForTestWithBuildFlag("RELEASE_HIDDEN_API_EXPORTABLE_STUBS", "true"),
227	).RunTestWithBp(t, `
228		bootclasspath_fragment {
229			name: "myfragment",
230			contents: ["mysdklibrary"],
231			api: {
232				stub_libs: [
233					"mystublib",
234					"myothersdklibrary",
235				],
236			},
237			core_platform_api: {
238				stub_libs: ["mycoreplatform.stubs"],
239			},
240			hidden_api: {
241				split_packages: ["*"],
242			},
243		}
244
245		java_library {
246			name: "mystublib",
247			srcs: ["Test.java"],
248			system_modules: "none",
249			sdk_version: "none",
250			compile_dex: true,
251		}
252
253		java_sdk_library {
254			name: "mysdklibrary",
255			srcs: ["a.java"],
256			shared_library: false,
257			public: {enabled: true},
258			system: {enabled: true},
259		}
260
261		java_sdk_library {
262			name: "myothersdklibrary",
263			srcs: ["a.java"],
264			shared_library: false,
265			public: {enabled: true},
266		}
267
268		java_sdk_library {
269			name: "mycoreplatform",
270			srcs: ["a.java"],
271			shared_library: false,
272			public: {enabled: true},
273		}
274	`)
275
276	fragment := result.Module("myfragment", "android_common")
277	info, _ := android.OtherModuleProvider(result, fragment, HiddenAPIInfoProvider)
278
279	stubsJar := "out/soong/.intermediates/mystublib/android_common/dex/mystublib.jar"
280
281	// Stubs jars for mysdklibrary
282	publicStubsJar := "out/soong/.intermediates/mysdklibrary.stubs.exportable/android_common/dex/mysdklibrary.stubs.exportable.jar"
283	systemStubsJar := "out/soong/.intermediates/mysdklibrary.stubs.exportable.system/android_common/dex/mysdklibrary.stubs.exportable.system.jar"
284
285	// Stubs jars for myothersdklibrary
286	otherPublicStubsJar := "out/soong/.intermediates/myothersdklibrary.stubs.exportable/android_common/dex/myothersdklibrary.stubs.exportable.jar"
287
288	// Check that SdkPublic uses public stubs for all sdk libraries.
289	android.AssertPathsRelativeToTopEquals(t, "public dex stubs jar", []string{otherPublicStubsJar, publicStubsJar, stubsJar}, info.TransitiveStubDexJarsByScope.StubDexJarsForScope(PublicHiddenAPIScope))
290
291	// Check that SdkSystem uses system stubs for mysdklibrary and public stubs for myothersdklibrary
292	// as it does not provide system stubs.
293	android.AssertPathsRelativeToTopEquals(t, "system dex stubs jar", []string{otherPublicStubsJar, systemStubsJar, stubsJar}, info.TransitiveStubDexJarsByScope.StubDexJarsForScope(SystemHiddenAPIScope))
294
295	// Check that SdkTest also uses system stubs for mysdklibrary as it does not provide test stubs
296	// and public stubs for myothersdklibrary as it does not provide test stubs either.
297	android.AssertPathsRelativeToTopEquals(t, "test dex stubs jar", []string{otherPublicStubsJar, systemStubsJar, stubsJar}, info.TransitiveStubDexJarsByScope.StubDexJarsForScope(TestHiddenAPIScope))
298
299	// Check that SdkCorePlatform uses public stubs from the mycoreplatform library.
300	corePlatformStubsJar := "out/soong/.intermediates/mycoreplatform.stubs/android_common/dex/mycoreplatform.stubs.jar"
301	android.AssertPathsRelativeToTopEquals(t, "core platform dex stubs jar", []string{corePlatformStubsJar}, info.TransitiveStubDexJarsByScope.StubDexJarsForScope(CorePlatformHiddenAPIScope))
302
303	// Check the widest stubs.. The list contains the widest stub dex jar provided by each module.
304	expectedWidestPaths := []string{
305		// mycoreplatform's widest API is core platform.
306		corePlatformStubsJar,
307
308		// myothersdklibrary's widest API is public.
309		otherPublicStubsJar,
310
311		// sdklibrary's widest API is system.
312		systemStubsJar,
313
314		// mystublib's only provides one API and so it must be the widest.
315		stubsJar,
316	}
317
318	android.AssertPathsRelativeToTopEquals(t, "widest dex stubs jar", expectedWidestPaths, info.TransitiveStubDexJarsByScope.StubDexJarsForWidestAPIScope())
319}
320
321func TestFromTextWidestApiScope(t *testing.T) {
322	result := android.GroupFixturePreparers(
323		prepareForTestWithBootclasspathFragment,
324		PrepareForTestWithJavaSdkLibraryFiles,
325		android.FixtureModifyConfig(func(config android.Config) {
326			config.SetBuildFromTextStub(true)
327		}),
328		FixtureWithLastReleaseApis("mysdklibrary", "android-non-updatable"),
329		FixtureConfigureApexBootJars("someapex:mysdklibrary"),
330	).RunTestWithBp(t, `
331		bootclasspath_fragment {
332			name: "myfragment",
333			contents: ["mysdklibrary"],
334			additional_stubs: [
335				"android-non-updatable",
336			],
337			hidden_api: {
338				split_packages: ["*"],
339			},
340		}
341		java_sdk_library {
342			name: "mysdklibrary",
343			srcs: ["a.java"],
344			shared_library: false,
345			public: {enabled: true},
346			system: {enabled: true},
347		}
348		java_sdk_library {
349			name: "android-non-updatable",
350			srcs: ["b.java"],
351			compile_dex: true,
352			public: {
353				enabled: true,
354			},
355			system: {
356				enabled: true,
357			},
358			test: {
359				enabled: true,
360			},
361			module_lib: {
362				enabled: true,
363			},
364		}
365	`)
366
367	fragment := result.ModuleForTests("myfragment", "android_common")
368	dependencyStubDexFlag := "--dependency-stub-dex=out/soong/.intermediates/default/java/android-non-updatable.stubs.test_module_lib/android_common/dex/android-non-updatable.stubs.test_module_lib.jar"
369	stubFlagsCommand := fragment.Output("modular-hiddenapi/stub-flags.csv").RuleParams.Command
370	android.AssertStringDoesContain(t,
371		"Stub flags generating command does not include the expected dependency stub dex file",
372		stubFlagsCommand, dependencyStubDexFlag)
373}
374
375func TestSnapshotWithBootclasspathFragment_HiddenAPI(t *testing.T) {
376	result := android.GroupFixturePreparers(
377		prepareForTestWithBootclasspathFragment,
378		PrepareForTestWithJavaSdkLibraryFiles,
379		FixtureWithLastReleaseApis("mysdklibrary", "mynewlibrary"),
380		FixtureConfigureApexBootJars("myapex:mybootlib", "myapex:mynewlibrary"),
381		android.MockFS{
382			"my-blocked.txt":                   nil,
383			"my-max-target-o-low-priority.txt": nil,
384			"my-max-target-p.txt":              nil,
385			"my-max-target-q.txt":              nil,
386			"my-max-target-r-low-priority.txt": nil,
387			"my-removed.txt":                   nil,
388			"my-unsupported-packages.txt":      nil,
389			"my-unsupported.txt":               nil,
390			"my-new-max-target-q.txt":          nil,
391		}.AddToFixture(),
392		android.FixtureWithRootAndroidBp(`
393			bootclasspath_fragment {
394				name: "mybootclasspathfragment",
395				apex_available: ["myapex"],
396				contents: ["mybootlib", "mynewlibrary"],
397				hidden_api: {
398					unsupported: [
399							"my-unsupported.txt",
400					],
401					removed: [
402							"my-removed.txt",
403					],
404					max_target_r_low_priority: [
405							"my-max-target-r-low-priority.txt",
406					],
407					max_target_q: [
408							"my-max-target-q.txt",
409					],
410					max_target_p: [
411							"my-max-target-p.txt",
412					],
413					max_target_o_low_priority: [
414							"my-max-target-o-low-priority.txt",
415					],
416					blocked: [
417							"my-blocked.txt",
418					],
419					unsupported_packages: [
420							"my-unsupported-packages.txt",
421					],
422					split_packages: ["sdklibrary"],
423					package_prefixes: ["sdklibrary.all.mine"],
424					single_packages: ["sdklibrary.mine"],
425				},
426			}
427
428			java_library {
429				name: "mybootlib",
430				apex_available: ["myapex"],
431				srcs: ["Test.java"],
432				system_modules: "none",
433				sdk_version: "none",
434				min_sdk_version: "1",
435				compile_dex: true,
436				permitted_packages: ["mybootlib"],
437			}
438
439			java_sdk_library {
440				name: "mynewlibrary",
441				apex_available: ["myapex"],
442				srcs: ["Test.java"],
443				min_sdk_version: "10",
444				compile_dex: true,
445				public: {enabled: true},
446				permitted_packages: ["mysdklibrary"],
447				hidden_api: {
448					max_target_q: [
449							"my-new-max-target-q.txt",
450					],
451					split_packages: ["sdklibrary", "newlibrary"],
452					package_prefixes: ["newlibrary.all.mine"],
453					single_packages: ["newlibrary.mine"],
454				},
455			}
456		`),
457	).RunTest(t)
458
459	// Make sure that the library exports hidden API properties for use by the bootclasspath_fragment.
460	library := result.Module("mynewlibrary", "android_common")
461	info, _ := android.OtherModuleProvider(result, library, hiddenAPIPropertyInfoProvider)
462	android.AssertArrayString(t, "split packages", []string{"sdklibrary", "newlibrary"}, info.SplitPackages)
463	android.AssertArrayString(t, "package prefixes", []string{"newlibrary.all.mine"}, info.PackagePrefixes)
464	android.AssertArrayString(t, "single packages", []string{"newlibrary.mine"}, info.SinglePackages)
465	for _, c := range HiddenAPIFlagFileCategories {
466		expectedMaxTargetQPaths := []string(nil)
467		if c.PropertyName() == "max_target_q" {
468			expectedMaxTargetQPaths = []string{"my-new-max-target-q.txt"}
469		}
470		android.AssertPathsRelativeToTopEquals(t, c.PropertyName(), expectedMaxTargetQPaths, info.FlagFilesByCategory[c])
471	}
472
473	// Make sure that the signature-patterns.csv is passed all the appropriate package properties
474	// from the bootclasspath_fragment and its contents.
475	fragment := result.ModuleForTests("mybootclasspathfragment", "android_common")
476	rule := fragment.Output("modular-hiddenapi/signature-patterns.csv")
477	expectedCommand := strings.Join([]string{
478		"--split-package newlibrary",
479		"--split-package sdklibrary",
480		"--package-prefix newlibrary.all.mine",
481		"--package-prefix sdklibrary.all.mine",
482		"--single-package newlibrary.mine",
483		"--single-package sdklibrary",
484	}, " ")
485	android.AssertStringDoesContain(t, "signature patterns command", rule.RuleParams.Command, expectedCommand)
486}
487
488func TestBootclasspathFragment_Test(t *testing.T) {
489	result := android.GroupFixturePreparers(
490		prepareForTestWithBootclasspathFragment,
491		PrepareForTestWithJavaSdkLibraryFiles,
492		FixtureWithLastReleaseApis("mysdklibrary"),
493	).RunTestWithBp(t, `
494		bootclasspath_fragment {
495			name: "myfragment",
496			contents: ["mysdklibrary"],
497			hidden_api: {
498				split_packages: [],
499			},
500		}
501
502		bootclasspath_fragment_test {
503			name: "a_test_fragment",
504			contents: ["mysdklibrary"],
505			hidden_api: {
506				split_packages: [],
507			},
508		}
509
510
511		java_sdk_library {
512			name: "mysdklibrary",
513			srcs: ["a.java"],
514			shared_library: false,
515			public: {enabled: true},
516			system: {enabled: true},
517		}
518	`)
519
520	fragment := result.Module("myfragment", "android_common").(*BootclasspathFragmentModule)
521	android.AssertBoolEquals(t, "not a test fragment", false, fragment.isTestFragment())
522
523	fragment = result.Module("a_test_fragment", "android_common").(*BootclasspathFragmentModule)
524	android.AssertBoolEquals(t, "is a test fragment by type", true, fragment.isTestFragment())
525}
526