blob: 9e1ac943e0f36de387dd574c1e571975c0befa91 [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,
Jihoon Kang85bc1932024-07-01 17:04:46 +000095 sdk_version: "core_current",
Paul Duffine245b612021-06-10 08:59:41 +010096 }
97
98 java_library {
99 name: "quuz",
100 apex_available: [
101 "com.android.art",
102 ],
103 srcs: ["b.java"],
104 installable: true,
105 }
106
107 apex {
108 name: "myapex",
109 key: "myapex.key",
110 bootclasspath_fragments: [
111 "mybootclasspath-fragment",
112 ],
113 java_libs: [
114 "othersdklibrary",
115 ],
116 updatable: false,
117 }
118
119 apex_key {
120 name: "myapex.key",
121 public_key: "testkey.avbpubkey",
122 private_key: "testkey.pem",
123 }
124
125 bootclasspath_fragment {
126 name: "mybootclasspath-fragment",
127 apex_available: [
128 "myapex",
129 ],
130 contents: [
131 "bar",
132 ],
Paul Duffin9fd56472022-03-31 15:42:30 +0100133 hidden_api: {
134 split_packages: ["*"],
135 },
Paul Duffine245b612021-06-10 08:59:41 +0100136 }
137
138 java_library {
139 name: "bar",
140 srcs: ["b.java"],
141 installable: true,
142 apex_available: ["myapex"],
143 permitted_packages: ["bar"],
144 }
145
146 java_sdk_library {
147 name: "foo",
148 srcs: ["b.java"],
149 }
150
151 java_sdk_library {
152 name: "othersdklibrary",
153 srcs: ["b.java"],
154 shared_library: false,
155 apex_available: [
156 "com.android.art",
157 "myapex",
158 ],
159 }
160
Paul Duffine245b612021-06-10 08:59:41 +0100161 apex {
162 name: "otherapex",
163 key: "otherapex.key",
164 java_libs: [
165 "otherapexlibrary",
166 ],
167 updatable: false,
168 }
169
170 apex_key {
171 name: "otherapex.key",
172 public_key: "testkey.avbpubkey",
173 private_key: "testkey.pem",
174 }
175
176 java_library {
177 name: "otherapexlibrary",
178 srcs: ["b.java"],
179 installable: true,
180 apex_available: ["otherapex"],
181 permitted_packages: ["otherapexlibrary"],
182 }
183
184 platform_bootclasspath {
185 name: "myplatform-bootclasspath",
186
187 fragments: [
188 {
189 apex: "com.android.art",
190 module: "art-bootclasspath-fragment",
191 },
satayevabcd5972021-08-06 17:49:46 +0100192 {
193 apex: "myapex",
194 module: "mybootclasspath-fragment",
195 },
Paul Duffine245b612021-06-10 08:59:41 +0100196 ],
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
Paul Duffine245b612021-06-10 08:59:41 +0100210 other := result.Module("othersdklibrary", "android_common_apex10000")
211
212 otherApexLibrary := result.Module("otherapexlibrary", "android_common_apex10000")
213
214 platformFoo := result.Module("quuz", "android_common")
215
216 bootclasspath := result.Module("myplatform-bootclasspath", "android_common")
217
218 // Use a custom assertion method instead of AssertDeepEquals as the latter formats the output
219 // using %#v which results in meaningless output as ClasspathElements are pointers.
220 assertElementsEquals := func(t *testing.T, message string, expected, actual java.ClasspathElements) {
221 if !reflect.DeepEqual(expected, actual) {
222 t.Errorf("%s: expected:\n %s\n got:\n %s", message, expected, actual)
223 }
224 }
225
226 expectFragmentElement := func(module android.Module, contents ...android.Module) java.ClasspathElement {
227 return &java.ClasspathFragmentElement{module, contents}
228 }
229 expectLibraryElement := func(module android.Module) java.ClasspathElement {
230 return &java.ClasspathLibraryElement{module}
231 }
232
233 newCtx := func() *testClasspathElementContext {
Colin Cross313aa542023-12-13 13:47:44 -0800234 return &testClasspathElementContext{
235 OtherModuleProviderContext: result.TestContext.OtherModuleProviderAdaptor(),
236 testContext: result.TestContext,
237 module: bootclasspath,
238 }
Paul Duffine245b612021-06-10 08:59:41 +0100239 }
240
241 // Verify that CreateClasspathElements works when given valid input.
242 t.Run("art:baz, art:quuz, my:bar, foo", func(t *testing.T) {
243 ctx := newCtx()
244 elements := java.CreateClasspathElements(ctx, []android.Module{artBaz, artQuuz, myBar, platformFoo}, []android.Module{artFragment, myFragment})
245 expectedElements := java.ClasspathElements{
246 expectFragmentElement(artFragment, artBaz, artQuuz),
247 expectFragmentElement(myFragment, myBar),
248 expectLibraryElement(platformFoo),
249 }
250 assertElementsEquals(t, "elements", expectedElements, elements)
251 })
252
Paul Duffine245b612021-06-10 08:59:41 +0100253 // Verify that CreateClasspathElements detects when an apex has multiple fragments.
254 t.Run("multiple fragments for same apex", func(t *testing.T) {
255 ctx := newCtx()
256 elements := java.CreateClasspathElements(ctx, []android.Module{}, []android.Module{artFragment, artFragment})
257 android.FailIfNoMatchingErrors(t, "apex com.android.art has multiple fragments, art-bootclasspath-fragment{.*} and art-bootclasspath-fragment{.*}", ctx.errs)
258 expectedElements := java.ClasspathElements{}
259 assertElementsEquals(t, "elements", expectedElements, elements)
260 })
261
262 // Verify that CreateClasspathElements detects when a library is in multiple fragments.
263 t.Run("library from multiple fragments", func(t *testing.T) {
264 ctx := newCtx()
265 elements := java.CreateClasspathElements(ctx, []android.Module{other}, []android.Module{artFragment, myFragment})
266 android.FailIfNoMatchingErrors(t, "library othersdklibrary{.*} is in two separate fragments, art-bootclasspath-fragment{.*} and mybootclasspath-fragment{.*}", ctx.errs)
267 expectedElements := java.ClasspathElements{}
268 assertElementsEquals(t, "elements", expectedElements, elements)
269 })
270
271 // Verify that CreateClasspathElements detects when a fragment's contents are not contiguous and
272 // are separated by a library from another fragment.
273 t.Run("discontiguous separated by fragment", func(t *testing.T) {
274 ctx := newCtx()
275 elements := java.CreateClasspathElements(ctx, []android.Module{artBaz, myBar, artQuuz, platformFoo}, []android.Module{artFragment, myFragment})
276 expectedElements := java.ClasspathElements{
277 expectFragmentElement(artFragment, artBaz, artQuuz),
278 expectFragmentElement(myFragment, myBar),
279 expectLibraryElement(platformFoo),
280 }
281 assertElementsEquals(t, "elements", expectedElements, elements)
282 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)
283 })
284
285 // Verify that CreateClasspathElements detects when a fragment's contents are not contiguous and
286 // are separated by a standalone library.
287 t.Run("discontiguous separated by library", func(t *testing.T) {
288 ctx := newCtx()
289 elements := java.CreateClasspathElements(ctx, []android.Module{artBaz, platformFoo, artQuuz, myBar}, []android.Module{artFragment, myFragment})
290 expectedElements := java.ClasspathElements{
291 expectFragmentElement(artFragment, artBaz, artQuuz),
292 expectLibraryElement(platformFoo),
293 expectFragmentElement(myFragment, myBar),
294 }
295 assertElementsEquals(t, "elements", expectedElements, elements)
296 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)
297 })
298
299 // Verify that CreateClasspathElements detects when there a library on the classpath that
300 // indicates it is from an apex the supplied fragments list does not contain a fragment for that
301 // apex.
302 t.Run("no fragment for apex", func(t *testing.T) {
303 ctx := newCtx()
304 elements := java.CreateClasspathElements(ctx, []android.Module{artBaz, otherApexLibrary}, []android.Module{artFragment})
305 expectedElements := java.ClasspathElements{
306 expectFragmentElement(artFragment, artBaz),
307 }
308 assertElementsEquals(t, "elements", expectedElements, elements)
309 android.FailIfNoMatchingErrors(t, `library otherapexlibrary{.*} is from apexes \[otherapex\] which have no corresponding fragment in \[art-bootclasspath-fragment{.*}\]`, ctx.errs)
310 })
311}