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