blob: b9a91982a984e91a67d065fb800bdad8a701edfa [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"
Paul Duffine245b612021-06-10 08:59:41 +010023)
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 {
Colin Cross313aa542023-12-13 13:47:44 -080030 android.OtherModuleProviderContext
Paul Duffine245b612021-06-10 08:59:41 +010031 testContext *android.TestContext
32 module android.Module
33 errs []error
34}
35
Paul Duffine245b612021-06-10 08:59:41 +010036func (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"),
satayevabcd5972021-08-06 17:49:46 +010053 java.FixtureConfigureApexBootJars("myapex:bar"),
Paul Duffine245b612021-06-10 08:59:41 +010054 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",
satayevabcd5972021-08-06 17:49:46 +010075 image_name: "art",
Paul Duffine245b612021-06-10 08:59:41 +010076 apex_available: [
77 "com.android.art",
78 ],
79 contents: [
80 "baz",
81 "quuz",
82 ],
Paul Duffin9fd56472022-03-31 15:42:30 +010083 hidden_api: {
84 split_packages: ["*"],
85 },
Paul Duffine245b612021-06-10 08:59:41 +010086 }
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 ],
Paul Duffin9fd56472022-03-31 15:42:30 +0100132 hidden_api: {
133 split_packages: ["*"],
134 },
Paul Duffine245b612021-06-10 08:59:41 +0100135 }
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
Paul Duffine245b612021-06-10 08:59:41 +0100160 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 },
satayevabcd5972021-08-06 17:49:46 +0100191 {
192 apex: "myapex",
193 module: "mybootclasspath-fragment",
194 },
Paul Duffine245b612021-06-10 08:59:41 +0100195 ],
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
Paul Duffine245b612021-06-10 08:59:41 +0100209 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 {
Colin Cross313aa542023-12-13 13:47:44 -0800233 return &testClasspathElementContext{
234 OtherModuleProviderContext: result.TestContext.OtherModuleProviderAdaptor(),
235 testContext: result.TestContext,
236 module: bootclasspath,
237 }
Paul Duffine245b612021-06-10 08:59:41 +0100238 }
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
Paul Duffine245b612021-06-10 08:59:41 +0100252 // 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}