blob: 0b7b54620a429ad58596c7ddcd878f66f2bd1bce [file] [log] [blame]
Ulya Trafimovich69612672020-10-20 17:41:54 +01001// Copyright 2020 Google Inc. All rights reserved.
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 dexpreopt
16
17// This file contains unit tests for class loader context structure.
18// For class loader context tests involving .bp files, see TestUsesLibraries in java package.
19
20import (
Ulya Trafimovich7bc1cf52021-01-05 15:41:55 +000021 "fmt"
Ulya Trafimovich69612672020-10-20 17:41:54 +010022 "reflect"
23 "strings"
24 "testing"
25
26 "android/soong/android"
27)
28
29func TestCLC(t *testing.T) {
30 // Construct class loader context with the following structure:
31 // .
32 // ├── 29
33 // │   ├── android.hidl.manager
34 // │   └── android.hidl.base
35 // │
36 // └── any
37 // ├── a
38 // ├── b
39 // ├── c
40 // ├── d
Ulya Trafimovich8cbc5d22020-11-03 15:15:46 +000041 // │   ├── a2
42 // │   ├── b2
43 // │   └── c2
44 // │   ├── a1
45 // │   └── b1
Ulya Trafimovich69612672020-10-20 17:41:54 +010046 // ├── f
47 // ├── a3
48 // └── b3
49 //
50 ctx := testContext()
51
Ulya Trafimovichfc0f6e32021-08-12 16:16:11 +010052 optional := false
53
Ulya Trafimovich8cbc5d22020-11-03 15:15:46 +000054 m := make(ClassLoaderContextMap)
Ulya Trafimovich69612672020-10-20 17:41:54 +010055
Ulya Trafimovichfc0f6e32021-08-12 16:16:11 +010056 m.AddContext(ctx, AnySdkVersion, "a", optional, buildPath(ctx, "a"), installPath(ctx, "a"), nil)
57 m.AddContext(ctx, AnySdkVersion, "b", optional, buildPath(ctx, "b"), installPath(ctx, "b"), nil)
58 m.AddContext(ctx, AnySdkVersion, "c", optional, buildPath(ctx, "c"), installPath(ctx, "c"), nil)
Ulya Trafimovich69612672020-10-20 17:41:54 +010059
60 // Add some libraries with nested subcontexts.
61
Ulya Trafimovich8cbc5d22020-11-03 15:15:46 +000062 m1 := make(ClassLoaderContextMap)
Ulya Trafimovichfc0f6e32021-08-12 16:16:11 +010063 m1.AddContext(ctx, AnySdkVersion, "a1", optional, buildPath(ctx, "a1"), installPath(ctx, "a1"), nil)
64 m1.AddContext(ctx, AnySdkVersion, "b1", optional, buildPath(ctx, "b1"), installPath(ctx, "b1"), nil)
Ulya Trafimovich69612672020-10-20 17:41:54 +010065
Ulya Trafimovich8cbc5d22020-11-03 15:15:46 +000066 m2 := make(ClassLoaderContextMap)
Ulya Trafimovichfc0f6e32021-08-12 16:16:11 +010067 m2.AddContext(ctx, AnySdkVersion, "a2", optional, buildPath(ctx, "a2"), installPath(ctx, "a2"), nil)
68 m2.AddContext(ctx, AnySdkVersion, "b2", optional, buildPath(ctx, "b2"), installPath(ctx, "b2"), nil)
69 m2.AddContext(ctx, AnySdkVersion, "c2", optional, buildPath(ctx, "c2"), installPath(ctx, "c2"), m1)
Ulya Trafimovich69612672020-10-20 17:41:54 +010070
Ulya Trafimovich8cbc5d22020-11-03 15:15:46 +000071 m3 := make(ClassLoaderContextMap)
Ulya Trafimovichfc0f6e32021-08-12 16:16:11 +010072 m3.AddContext(ctx, AnySdkVersion, "a3", optional, buildPath(ctx, "a3"), installPath(ctx, "a3"), nil)
73 m3.AddContext(ctx, AnySdkVersion, "b3", optional, buildPath(ctx, "b3"), installPath(ctx, "b3"), nil)
Ulya Trafimovich69612672020-10-20 17:41:54 +010074
Ulya Trafimovichfc0f6e32021-08-12 16:16:11 +010075 m.AddContext(ctx, AnySdkVersion, "d", optional, buildPath(ctx, "d"), installPath(ctx, "d"), m2)
Ulya Trafimovich8cbc5d22020-11-03 15:15:46 +000076 // When the same library is both in conditional and unconditional context, it should be removed
77 // from conditional context.
Ulya Trafimovichfc0f6e32021-08-12 16:16:11 +010078 m.AddContext(ctx, 42, "f", optional, buildPath(ctx, "f"), installPath(ctx, "f"), nil)
79 m.AddContext(ctx, AnySdkVersion, "f", optional, buildPath(ctx, "f"), installPath(ctx, "f"), nil)
Ulya Trafimovich18554242020-11-03 15:55:11 +000080
81 // Merge map with implicit root library that is among toplevel contexts => does nothing.
82 m.AddContextMap(m1, "c")
83 // Merge map with implicit root library that is not among toplevel contexts => all subcontexts
84 // of the other map are added as toplevel contexts.
85 m.AddContextMap(m3, "m_g")
Ulya Trafimovich69612672020-10-20 17:41:54 +010086
87 // Compatibility libraries with unknown install paths get default paths.
Ulya Trafimovichfc0f6e32021-08-12 16:16:11 +010088 m.AddContext(ctx, 29, AndroidHidlManager, optional, buildPath(ctx, AndroidHidlManager), nil, nil)
89 m.AddContext(ctx, 29, AndroidHidlBase, optional, buildPath(ctx, AndroidHidlBase), nil, nil)
Ulya Trafimovich69612672020-10-20 17:41:54 +010090
91 // Add "android.test.mock" to conditional CLC, observe that is gets removed because it is only
92 // needed as a compatibility library if "android.test.runner" is in CLC as well.
Ulya Trafimovichfc0f6e32021-08-12 16:16:11 +010093 m.AddContext(ctx, 30, AndroidTestMock, optional, buildPath(ctx, AndroidTestMock), nil, nil)
Ulya Trafimovich69612672020-10-20 17:41:54 +010094
Ulya Trafimovich8cbc5d22020-11-03 15:15:46 +000095 valid, validationError := validateClassLoaderContext(m)
Ulya Trafimovich69612672020-10-20 17:41:54 +010096
Ulya Trafimovich8cbc5d22020-11-03 15:15:46 +000097 fixClassLoaderContext(m)
Ulya Trafimovich69612672020-10-20 17:41:54 +010098
99 var haveStr string
100 var havePaths android.Paths
Ulya Trafimovichfc0f6e32021-08-12 16:16:11 +0100101 var haveUsesLibsReq, haveUsesLibsOpt []string
Ulya Trafimovich8cbc5d22020-11-03 15:15:46 +0000102 if valid && validationError == nil {
103 haveStr, havePaths = ComputeClassLoaderContext(m)
Ulya Trafimovichfc0f6e32021-08-12 16:16:11 +0100104 haveUsesLibsReq, haveUsesLibsOpt = m.UsesLibs()
Ulya Trafimovich69612672020-10-20 17:41:54 +0100105 }
106
107 // Test that validation is successful (all paths are known).
108 t.Run("validate", func(t *testing.T) {
Ulya Trafimovich8cbc5d22020-11-03 15:15:46 +0000109 if !(valid && validationError == nil) {
Ulya Trafimovich69612672020-10-20 17:41:54 +0100110 t.Errorf("invalid class loader context")
111 }
112 })
113
114 // Test that class loader context structure is correct.
115 t.Run("string", func(t *testing.T) {
116 wantStr := " --host-context-for-sdk 29 " +
117 "PCL[out/" + AndroidHidlManager + ".jar]#" +
118 "PCL[out/" + AndroidHidlBase + ".jar]" +
119 " --target-context-for-sdk 29 " +
120 "PCL[/system/framework/" + AndroidHidlManager + ".jar]#" +
121 "PCL[/system/framework/" + AndroidHidlBase + ".jar]" +
122 " --host-context-for-sdk any " +
Ulya Trafimovich8cbc5d22020-11-03 15:15:46 +0000123 "PCL[out/a.jar]#PCL[out/b.jar]#PCL[out/c.jar]#PCL[out/d.jar]" +
124 "{PCL[out/a2.jar]#PCL[out/b2.jar]#PCL[out/c2.jar]" +
125 "{PCL[out/a1.jar]#PCL[out/b1.jar]}}#" +
Ulya Trafimovich69612672020-10-20 17:41:54 +0100126 "PCL[out/f.jar]#PCL[out/a3.jar]#PCL[out/b3.jar]" +
127 " --target-context-for-sdk any " +
Ulya Trafimovich8cbc5d22020-11-03 15:15:46 +0000128 "PCL[/system/a.jar]#PCL[/system/b.jar]#PCL[/system/c.jar]#PCL[/system/d.jar]" +
129 "{PCL[/system/a2.jar]#PCL[/system/b2.jar]#PCL[/system/c2.jar]" +
130 "{PCL[/system/a1.jar]#PCL[/system/b1.jar]}}#" +
Ulya Trafimovich69612672020-10-20 17:41:54 +0100131 "PCL[/system/f.jar]#PCL[/system/a3.jar]#PCL[/system/b3.jar]"
132 if wantStr != haveStr {
133 t.Errorf("\nwant class loader context: %s\nhave class loader context: %s", wantStr, haveStr)
134 }
135 })
136
137 // Test that all expected build paths are gathered.
138 t.Run("paths", func(t *testing.T) {
139 wantPaths := []string{
140 "out/android.hidl.manager-V1.0-java.jar", "out/android.hidl.base-V1.0-java.jar",
141 "out/a.jar", "out/b.jar", "out/c.jar", "out/d.jar",
142 "out/a2.jar", "out/b2.jar", "out/c2.jar",
143 "out/a1.jar", "out/b1.jar",
144 "out/f.jar", "out/a3.jar", "out/b3.jar",
145 }
146 if !reflect.DeepEqual(wantPaths, havePaths.Strings()) {
147 t.Errorf("\nwant paths: %s\nhave paths: %s", wantPaths, havePaths)
148 }
149 })
150
151 // Test for libraries that are added by the manifest_fixer.
152 t.Run("uses libs", func(t *testing.T) {
Ulya Trafimovichfc0f6e32021-08-12 16:16:11 +0100153 wantUsesLibsReq := []string{"a", "b", "c", "d", "f", "a3", "b3"}
154 wantUsesLibsOpt := []string{}
155 if !reflect.DeepEqual(wantUsesLibsReq, haveUsesLibsReq) {
156 t.Errorf("\nwant required uses libs: %s\nhave required uses libs: %s", wantUsesLibsReq, haveUsesLibsReq)
157 }
158 if !reflect.DeepEqual(wantUsesLibsOpt, haveUsesLibsOpt) {
159 t.Errorf("\nwant optional uses libs: %s\nhave optional uses libs: %s", wantUsesLibsOpt, haveUsesLibsOpt)
Ulya Trafimovich69612672020-10-20 17:41:54 +0100160 }
161 })
162}
163
Jeongik Cha19ade892021-04-22 20:55:21 +0900164func TestCLCJson(t *testing.T) {
165 ctx := testContext()
Ulya Trafimovichfc0f6e32021-08-12 16:16:11 +0100166 optional := false
Jeongik Cha19ade892021-04-22 20:55:21 +0900167 m := make(ClassLoaderContextMap)
Ulya Trafimovichfc0f6e32021-08-12 16:16:11 +0100168 m.AddContext(ctx, 28, "a", optional, buildPath(ctx, "a"), installPath(ctx, "a"), nil)
169 m.AddContext(ctx, 29, "b", optional, buildPath(ctx, "b"), installPath(ctx, "b"), nil)
170 m.AddContext(ctx, 30, "c", optional, buildPath(ctx, "c"), installPath(ctx, "c"), nil)
171 m.AddContext(ctx, AnySdkVersion, "d", optional, buildPath(ctx, "d"), installPath(ctx, "d"), nil)
Jeongik Cha19ade892021-04-22 20:55:21 +0900172 jsonCLC := toJsonClassLoaderContext(m)
173 restored := fromJsonClassLoaderContext(ctx, jsonCLC)
174 android.AssertIntEquals(t, "The size of the maps should be the same.", len(m), len(restored))
175 for k := range m {
176 a, _ := m[k]
177 b, ok := restored[k]
178 android.AssertBoolEquals(t, "The both maps should have the same keys.", ok, true)
179 android.AssertIntEquals(t, "The size of the elements should be the same.", len(a), len(b))
180 for i, elemA := range a {
181 before := fmt.Sprintf("%v", *elemA)
182 after := fmt.Sprintf("%v", *b[i])
183 android.AssertStringEquals(t, "The content should be the same.", before, after)
184 }
185 }
186}
187
Ulya Trafimovich7bc1cf52021-01-05 15:41:55 +0000188// Test that unknown library paths cause a validation error.
189func testCLCUnknownPath(t *testing.T, whichPath string) {
Ulya Trafimovich69612672020-10-20 17:41:54 +0100190 ctx := testContext()
Ulya Trafimovichfc0f6e32021-08-12 16:16:11 +0100191 optional := false
Ulya Trafimovich69612672020-10-20 17:41:54 +0100192
Ulya Trafimovich8cbc5d22020-11-03 15:15:46 +0000193 m := make(ClassLoaderContextMap)
Ulya Trafimovich7bc1cf52021-01-05 15:41:55 +0000194 if whichPath == "build" {
Ulya Trafimovichfc0f6e32021-08-12 16:16:11 +0100195 m.AddContext(ctx, AnySdkVersion, "a", optional, nil, nil, nil)
Ulya Trafimovich7bc1cf52021-01-05 15:41:55 +0000196 } else {
Ulya Trafimovichfc0f6e32021-08-12 16:16:11 +0100197 m.AddContext(ctx, AnySdkVersion, "a", optional, buildPath(ctx, "a"), nil, nil)
Ulya Trafimovich7bc1cf52021-01-05 15:41:55 +0000198 }
Ulya Trafimovich69612672020-10-20 17:41:54 +0100199
Ulya Trafimovich8cbc5d22020-11-03 15:15:46 +0000200 // The library should be added to <uses-library> tags by the manifest_fixer.
Ulya Trafimovich7bc1cf52021-01-05 15:41:55 +0000201 t.Run("uses libs", func(t *testing.T) {
Ulya Trafimovichfc0f6e32021-08-12 16:16:11 +0100202 haveUsesLibsReq, haveUsesLibsOpt := m.UsesLibs()
203 wantUsesLibsReq := []string{"a"}
204 wantUsesLibsOpt := []string{}
205 if !reflect.DeepEqual(wantUsesLibsReq, haveUsesLibsReq) {
206 t.Errorf("\nwant required uses libs: %s\nhave required uses libs: %s", wantUsesLibsReq, haveUsesLibsReq)
207 }
208 if !reflect.DeepEqual(wantUsesLibsOpt, haveUsesLibsOpt) {
209 t.Errorf("\nwant optional uses libs: %s\nhave optional uses libs: %s", wantUsesLibsOpt, haveUsesLibsOpt)
Ulya Trafimovich8cbc5d22020-11-03 15:15:46 +0000210 }
211 })
Ulya Trafimovich69612672020-10-20 17:41:54 +0100212
Ulya Trafimovich7bc1cf52021-01-05 15:41:55 +0000213 // But CLC cannot be constructed: there is a validation error.
214 _, err := validateClassLoaderContext(m)
215 checkError(t, err, fmt.Sprintf("invalid %s path for <uses-library> \"a\"", whichPath))
216}
217
218// Test that unknown build path is an error.
219func TestCLCUnknownBuildPath(t *testing.T) {
220 testCLCUnknownPath(t, "build")
221}
222
223// Test that unknown install path is an error.
224func TestCLCUnknownInstallPath(t *testing.T) {
225 testCLCUnknownPath(t, "install")
Ulya Trafimovich69612672020-10-20 17:41:54 +0100226}
227
Ulya Trafimovich5e13a732020-11-03 15:33:03 +0000228// An attempt to add conditional nested subcontext should fail.
229func TestCLCNestedConditional(t *testing.T) {
230 ctx := testContext()
Ulya Trafimovichfc0f6e32021-08-12 16:16:11 +0100231 optional := false
Ulya Trafimovich5e13a732020-11-03 15:33:03 +0000232 m1 := make(ClassLoaderContextMap)
Ulya Trafimovichfc0f6e32021-08-12 16:16:11 +0100233 m1.AddContext(ctx, 42, "a", optional, buildPath(ctx, "a"), installPath(ctx, "a"), nil)
Ulya Trafimovich5e13a732020-11-03 15:33:03 +0000234 m := make(ClassLoaderContextMap)
Ulya Trafimovichfc0f6e32021-08-12 16:16:11 +0100235 err := m.addContext(ctx, AnySdkVersion, "b", optional, buildPath(ctx, "b"), installPath(ctx, "b"), m1)
Ulya Trafimovich5e13a732020-11-03 15:33:03 +0000236 checkError(t, err, "nested class loader context shouldn't have conditional part")
237}
238
Ulya Trafimovichc9f2b942020-12-23 15:41:29 +0000239// Test for SDK version order in conditional CLC: no matter in what order the libraries are added,
240// they end up in the order that agrees with PackageManager.
241func TestCLCSdkVersionOrder(t *testing.T) {
242 ctx := testContext()
Ulya Trafimovichfc0f6e32021-08-12 16:16:11 +0100243 optional := false
Ulya Trafimovichc9f2b942020-12-23 15:41:29 +0000244 m := make(ClassLoaderContextMap)
Ulya Trafimovichfc0f6e32021-08-12 16:16:11 +0100245 m.AddContext(ctx, 28, "a", optional, buildPath(ctx, "a"), installPath(ctx, "a"), nil)
246 m.AddContext(ctx, 29, "b", optional, buildPath(ctx, "b"), installPath(ctx, "b"), nil)
247 m.AddContext(ctx, 30, "c", optional, buildPath(ctx, "c"), installPath(ctx, "c"), nil)
248 m.AddContext(ctx, AnySdkVersion, "d", optional, buildPath(ctx, "d"), installPath(ctx, "d"), nil)
Ulya Trafimovichc9f2b942020-12-23 15:41:29 +0000249
250 valid, validationError := validateClassLoaderContext(m)
251
252 fixClassLoaderContext(m)
253
254 var haveStr string
255 if valid && validationError == nil {
256 haveStr, _ = ComputeClassLoaderContext(m)
257 }
258
259 // Test that validation is successful (all paths are known).
260 t.Run("validate", func(t *testing.T) {
261 if !(valid && validationError == nil) {
262 t.Errorf("invalid class loader context")
263 }
264 })
265
266 // Test that class loader context structure is correct.
267 t.Run("string", func(t *testing.T) {
268 wantStr := " --host-context-for-sdk 30 PCL[out/c.jar]" +
269 " --target-context-for-sdk 30 PCL[/system/c.jar]" +
270 " --host-context-for-sdk 29 PCL[out/b.jar]" +
271 " --target-context-for-sdk 29 PCL[/system/b.jar]" +
272 " --host-context-for-sdk 28 PCL[out/a.jar]" +
273 " --target-context-for-sdk 28 PCL[/system/a.jar]" +
274 " --host-context-for-sdk any PCL[out/d.jar]" +
275 " --target-context-for-sdk any PCL[/system/d.jar]"
276 if wantStr != haveStr {
277 t.Errorf("\nwant class loader context: %s\nhave class loader context: %s", wantStr, haveStr)
278 }
279 })
280}
281
Ulya Trafimovich69612672020-10-20 17:41:54 +0100282func checkError(t *testing.T, have error, want string) {
283 if have == nil {
284 t.Errorf("\nwant error: '%s'\nhave: none", want)
285 } else if msg := have.Error(); !strings.HasPrefix(msg, want) {
286 t.Errorf("\nwant error: '%s'\nhave error: '%s'\n", want, msg)
287 }
288}
289
290func testContext() android.ModuleInstallPathContext {
291 config := android.TestConfig("out", nil, "", nil)
292 return android.ModuleInstallPathContextForTesting(config)
293}
294
295func buildPath(ctx android.PathContext, lib string) android.Path {
296 return android.PathForOutput(ctx, lib+".jar")
297}
298
299func installPath(ctx android.ModuleInstallPathContext, lib string) android.InstallPath {
300 return android.PathForModuleInstall(ctx, lib+".jar")
301}