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