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