• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 apex
16
17import (
18	"reflect"
19	"testing"
20
21	"android/soong/android"
22	"android/soong/java"
23)
24
25// Contains tests for java.CreateClasspathElements logic from java/classpath_element.go that
26// requires apexes.
27
28// testClasspathElementContext is a ClasspathElementContext suitable for use in tests.
29type testClasspathElementContext struct {
30	android.OtherModuleProviderContext
31	testContext *android.TestContext
32	module      android.Module
33	errs        []error
34}
35
36func (t *testClasspathElementContext) ModuleErrorf(fmt string, args ...interface{}) {
37	t.errs = append(t.errs, t.testContext.ModuleErrorf(t.module, fmt, args...))
38}
39
40var _ java.ClasspathElementContext = (*testClasspathElementContext)(nil)
41
42func TestCreateClasspathElements(t *testing.T) {
43	preparer := android.GroupFixturePreparers(
44		prepareForTestWithPlatformBootclasspath,
45		prepareForTestWithArtApex,
46		prepareForTestWithMyapex,
47		// For otherapex.
48		android.FixtureMergeMockFs(android.MockFS{
49			"system/sepolicy/apex/otherapex-file_contexts": nil,
50		}),
51		java.PrepareForTestWithJavaSdkLibraryFiles,
52		java.FixtureWithLastReleaseApis("foo", "othersdklibrary"),
53		java.FixtureConfigureApexBootJars("myapex:bar"),
54		android.FixtureWithRootAndroidBp(`
55		apex {
56			name: "com.android.art",
57			key: "com.android.art.key",
58 			bootclasspath_fragments: [
59				"art-bootclasspath-fragment",
60			],
61			java_libs: [
62				"othersdklibrary",
63			],
64			updatable: false,
65		}
66
67		apex_key {
68			name: "com.android.art.key",
69			public_key: "com.android.art.avbpubkey",
70			private_key: "com.android.art.pem",
71		}
72
73		bootclasspath_fragment {
74			name: "art-bootclasspath-fragment",
75			image_name: "art",
76			apex_available: [
77				"com.android.art",
78			],
79			contents: [
80				"baz",
81				"quuz",
82			],
83			hidden_api: {
84				split_packages: ["*"],
85			},
86		}
87
88		java_library {
89			name: "baz",
90			apex_available: [
91				"com.android.art",
92			],
93			srcs: ["b.java"],
94			installable: true,
95		}
96
97		java_library {
98			name: "quuz",
99			apex_available: [
100				"com.android.art",
101			],
102			srcs: ["b.java"],
103			installable: true,
104		}
105
106		apex {
107			name: "myapex",
108			key: "myapex.key",
109 			bootclasspath_fragments: [
110				"mybootclasspath-fragment",
111			],
112			java_libs: [
113				"othersdklibrary",
114			],
115			updatable: false,
116		}
117
118		apex_key {
119			name: "myapex.key",
120			public_key: "testkey.avbpubkey",
121			private_key: "testkey.pem",
122		}
123
124		bootclasspath_fragment {
125			name: "mybootclasspath-fragment",
126			apex_available: [
127				"myapex",
128			],
129			contents: [
130				"bar",
131			],
132			hidden_api: {
133				split_packages: ["*"],
134			},
135		}
136
137		java_library {
138			name: "bar",
139			srcs: ["b.java"],
140			installable: true,
141			apex_available: ["myapex"],
142			permitted_packages: ["bar"],
143		}
144
145		java_sdk_library {
146			name: "foo",
147			srcs: ["b.java"],
148		}
149
150		java_sdk_library {
151			name: "othersdklibrary",
152			srcs: ["b.java"],
153			shared_library: false,
154			apex_available: [
155				"com.android.art",
156				"myapex",
157			],
158		}
159
160		apex {
161			name: "otherapex",
162			key: "otherapex.key",
163			java_libs: [
164				"otherapexlibrary",
165			],
166			updatable: false,
167		}
168
169		apex_key {
170			name: "otherapex.key",
171			public_key: "testkey.avbpubkey",
172			private_key: "testkey.pem",
173		}
174
175		java_library {
176			name: "otherapexlibrary",
177			srcs: ["b.java"],
178			installable: true,
179			apex_available: ["otherapex"],
180			permitted_packages: ["otherapexlibrary"],
181		}
182
183		platform_bootclasspath {
184			name: "myplatform-bootclasspath",
185
186			fragments: [
187				{
188					apex: "com.android.art",
189					module: "art-bootclasspath-fragment",
190				},
191				{
192					apex: "myapex",
193					module: "mybootclasspath-fragment",
194				},
195			],
196		}
197	`),
198	)
199
200	result := preparer.RunTest(t)
201
202	artFragment := result.Module("art-bootclasspath-fragment", "android_common_apex10000")
203	artBaz := result.Module("baz", "android_common_apex10000")
204	artQuuz := result.Module("quuz", "android_common_apex10000")
205
206	myFragment := result.Module("mybootclasspath-fragment", "android_common_apex10000")
207	myBar := result.Module("bar", "android_common_apex10000")
208
209	other := result.Module("othersdklibrary", "android_common_apex10000")
210
211	otherApexLibrary := result.Module("otherapexlibrary", "android_common_apex10000")
212
213	platformFoo := result.Module("quuz", "android_common")
214
215	bootclasspath := result.Module("myplatform-bootclasspath", "android_common")
216
217	// Use a custom assertion method instead of AssertDeepEquals as the latter formats the output
218	// using %#v which results in meaningless output as ClasspathElements are pointers.
219	assertElementsEquals := func(t *testing.T, message string, expected, actual java.ClasspathElements) {
220		if !reflect.DeepEqual(expected, actual) {
221			t.Errorf("%s: expected:\n  %s\n got:\n  %s", message, expected, actual)
222		}
223	}
224
225	expectFragmentElement := func(module android.Module, contents ...android.Module) java.ClasspathElement {
226		return &java.ClasspathFragmentElement{module, contents}
227	}
228	expectLibraryElement := func(module android.Module) java.ClasspathElement {
229		return &java.ClasspathLibraryElement{module}
230	}
231
232	newCtx := func() *testClasspathElementContext {
233		return &testClasspathElementContext{
234			OtherModuleProviderContext: result.TestContext.OtherModuleProviderAdaptor(),
235			testContext:                result.TestContext,
236			module:                     bootclasspath,
237		}
238	}
239
240	// Verify that CreateClasspathElements works when given valid input.
241	t.Run("art:baz, art:quuz, my:bar, foo", func(t *testing.T) {
242		ctx := newCtx()
243		elements := java.CreateClasspathElements(ctx, []android.Module{artBaz, artQuuz, myBar, platformFoo}, []android.Module{artFragment, myFragment})
244		expectedElements := java.ClasspathElements{
245			expectFragmentElement(artFragment, artBaz, artQuuz),
246			expectFragmentElement(myFragment, myBar),
247			expectLibraryElement(platformFoo),
248		}
249		assertElementsEquals(t, "elements", expectedElements, elements)
250	})
251
252	// Verify that CreateClasspathElements detects when an apex has multiple fragments.
253	t.Run("multiple fragments for same apex", func(t *testing.T) {
254		ctx := newCtx()
255		elements := java.CreateClasspathElements(ctx, []android.Module{}, []android.Module{artFragment, artFragment})
256		android.FailIfNoMatchingErrors(t, "apex com.android.art has multiple fragments, art-bootclasspath-fragment{.*} and art-bootclasspath-fragment{.*}", ctx.errs)
257		expectedElements := java.ClasspathElements{}
258		assertElementsEquals(t, "elements", expectedElements, elements)
259	})
260
261	// Verify that CreateClasspathElements detects when a library is in multiple fragments.
262	t.Run("library from multiple fragments", func(t *testing.T) {
263		ctx := newCtx()
264		elements := java.CreateClasspathElements(ctx, []android.Module{other}, []android.Module{artFragment, myFragment})
265		android.FailIfNoMatchingErrors(t, "library othersdklibrary{.*} is in two separate fragments, art-bootclasspath-fragment{.*} and mybootclasspath-fragment{.*}", ctx.errs)
266		expectedElements := java.ClasspathElements{}
267		assertElementsEquals(t, "elements", expectedElements, elements)
268	})
269
270	// Verify that CreateClasspathElements detects when a fragment's contents are not contiguous and
271	// are separated by a library from another fragment.
272	t.Run("discontiguous separated by fragment", func(t *testing.T) {
273		ctx := newCtx()
274		elements := java.CreateClasspathElements(ctx, []android.Module{artBaz, myBar, artQuuz, platformFoo}, []android.Module{artFragment, myFragment})
275		expectedElements := java.ClasspathElements{
276			expectFragmentElement(artFragment, artBaz, artQuuz),
277			expectFragmentElement(myFragment, myBar),
278			expectLibraryElement(platformFoo),
279		}
280		assertElementsEquals(t, "elements", expectedElements, elements)
281		android.FailIfNoMatchingErrors(t, "libraries from the same fragment must be contiguous, however baz{.*} and quuz{os:android,arch:common,apex:apex10000} from fragment art-bootclasspath-fragment{.*} are separated by libraries from fragment mybootclasspath-fragment{.*} like bar{.*}", ctx.errs)
282	})
283
284	// Verify that CreateClasspathElements detects when a fragment's contents are not contiguous and
285	// are separated by a standalone library.
286	t.Run("discontiguous separated by library", func(t *testing.T) {
287		ctx := newCtx()
288		elements := java.CreateClasspathElements(ctx, []android.Module{artBaz, platformFoo, artQuuz, myBar}, []android.Module{artFragment, myFragment})
289		expectedElements := java.ClasspathElements{
290			expectFragmentElement(artFragment, artBaz, artQuuz),
291			expectLibraryElement(platformFoo),
292			expectFragmentElement(myFragment, myBar),
293		}
294		assertElementsEquals(t, "elements", expectedElements, elements)
295		android.FailIfNoMatchingErrors(t, "libraries from the same fragment must be contiguous, however baz{.*} and quuz{os:android,arch:common,apex:apex10000} from fragment art-bootclasspath-fragment{.*} are separated by library quuz{.*}", ctx.errs)
296	})
297
298	// Verify that CreateClasspathElements detects when there a library on the classpath that
299	// indicates it is from an apex the supplied fragments list does not contain a fragment for that
300	// apex.
301	t.Run("no fragment for apex", func(t *testing.T) {
302		ctx := newCtx()
303		elements := java.CreateClasspathElements(ctx, []android.Module{artBaz, otherApexLibrary}, []android.Module{artFragment})
304		expectedElements := java.ClasspathElements{
305			expectFragmentElement(artFragment, artBaz),
306		}
307		assertElementsEquals(t, "elements", expectedElements, elements)
308		android.FailIfNoMatchingErrors(t, `library otherapexlibrary{.*} is from apexes \[otherapex\] which have no corresponding fragment in \[art-bootclasspath-fragment{.*}\]`, ctx.errs)
309	})
310}
311