blob: c2f2fc5b9eaecca07ba4f2ac268633978ab0e220 [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) {
Colin Crossa2fdb612024-10-11 12:52:56 -070043 t.Parallel()
Paul Duffine245b612021-06-10 08:59:41 +010044 preparer := android.GroupFixturePreparers(
45 prepareForTestWithPlatformBootclasspath,
46 prepareForTestWithArtApex,
47 prepareForTestWithMyapex,
Colin Crossb614cd42024-10-11 12:52:21 -070048 prepareForTestWithOtherapex,
Paul Duffine245b612021-06-10 08:59:41 +010049 java.PrepareForTestWithJavaSdkLibraryFiles,
50 java.FixtureWithLastReleaseApis("foo", "othersdklibrary"),
satayevabcd5972021-08-06 17:49:46 +010051 java.FixtureConfigureApexBootJars("myapex:bar"),
Paul Duffine245b612021-06-10 08:59:41 +010052 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",
satayevabcd5972021-08-06 17:49:46 +010073 image_name: "art",
Paul Duffine245b612021-06-10 08:59:41 +010074 apex_available: [
75 "com.android.art",
76 ],
77 contents: [
78 "baz",
79 "quuz",
80 ],
Paul Duffin9fd56472022-03-31 15:42:30 +010081 hidden_api: {
82 split_packages: ["*"],
83 },
Paul Duffine245b612021-06-10 08:59:41 +010084 }
85
86 java_library {
87 name: "baz",
88 apex_available: [
89 "com.android.art",
90 ],
91 srcs: ["b.java"],
92 installable: true,
Jihoon Kang85bc1932024-07-01 17:04:46 +000093 sdk_version: "core_current",
Paul Duffine245b612021-06-10 08:59:41 +010094 }
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 ],
Paul Duffin9fd56472022-03-31 15:42:30 +0100131 hidden_api: {
132 split_packages: ["*"],
133 },
Paul Duffine245b612021-06-10 08:59:41 +0100134 }
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
Paul Duffine245b612021-06-10 08:59:41 +0100159 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 },
satayevabcd5972021-08-06 17:49:46 +0100190 {
191 apex: "myapex",
192 module: "mybootclasspath-fragment",
193 },
Paul Duffine245b612021-06-10 08:59:41 +0100194 ],
195 }
196 `),
197 )
198
199 result := preparer.RunTest(t)
200
Colin Crosse5c7d7c2024-12-18 17:08:07 -0800201 artFragment := result.Module("art-bootclasspath-fragment", "android_common_com.android.art")
Paul Duffine245b612021-06-10 08:59:41 +0100202 artBaz := result.Module("baz", "android_common_apex10000")
203 artQuuz := result.Module("quuz", "android_common_apex10000")
204
Colin Crosse5c7d7c2024-12-18 17:08:07 -0800205 myFragment := result.Module("mybootclasspath-fragment", "android_common_myapex")
Paul Duffine245b612021-06-10 08:59:41 +0100206 myBar := result.Module("bar", "android_common_apex10000")
207
Paul Duffine245b612021-06-10 08:59:41 +0100208 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 {
Colin Cross313aa542023-12-13 13:47:44 -0800230 return &testClasspathElementContext{
231 OtherModuleProviderContext: result.TestContext.OtherModuleProviderAdaptor(),
232 testContext: result.TestContext,
233 module: bootclasspath,
234 }
Paul Duffine245b612021-06-10 08:59:41 +0100235 }
236
237 // Verify that CreateClasspathElements works when given valid input.
238 t.Run("art:baz, art:quuz, my:bar, foo", func(t *testing.T) {
Colin Crossa2fdb612024-10-11 12:52:56 -0700239 t.Parallel()
Paul Duffine245b612021-06-10 08:59:41 +0100240 ctx := newCtx()
Colin Cross92b0eb12025-02-06 11:49:52 -0800241 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})
Paul Duffine245b612021-06-10 08:59:41 +0100246 expectedElements := java.ClasspathElements{
247 expectFragmentElement(artFragment, artBaz, artQuuz),
248 expectFragmentElement(myFragment, myBar),
249 expectLibraryElement(platformFoo),
250 }
251 assertElementsEquals(t, "elements", expectedElements, elements)
252 })
253
Paul Duffine245b612021-06-10 08:59:41 +0100254 // 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) {
Colin Crossa2fdb612024-10-11 12:52:56 -0700257 t.Parallel()
Paul Duffine245b612021-06-10 08:59:41 +0100258 ctx := newCtx()
Colin Cross92b0eb12025-02-06 11:49:52 -0800259 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})
Paul Duffine245b612021-06-10 08:59:41 +0100264 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) {
Colin Crossa2fdb612024-10-11 12:52:56 -0700276 t.Parallel()
Paul Duffine245b612021-06-10 08:59:41 +0100277 ctx := newCtx()
Colin Cross92b0eb12025-02-06 11:49:52 -0800278 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})
Paul Duffine245b612021-06-10 08:59:41 +0100283 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) {
Colin Crossa2fdb612024-10-11 12:52:56 -0700296 t.Parallel()
Paul Duffine245b612021-06-10 08:59:41 +0100297 ctx := newCtx()
Colin Cross92b0eb12025-02-06 11:49:52 -0800298 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})
Paul Duffine245b612021-06-10 08:59:41 +0100303 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}