blob: 610a4c9ecbec31fef9f2fdb6b464042511f3dae0 [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 Trafimovich8cbc5d22020-11-03 15:15:46 +000052 m := make(ClassLoaderContextMap)
Ulya Trafimovich69612672020-10-20 17:41:54 +010053
Ulya Trafimovich7bc1cf52021-01-05 15:41:55 +000054 m.AddContext(ctx, AnySdkVersion, "a", buildPath(ctx, "a"), installPath(ctx, "a"), nil)
55 m.AddContext(ctx, AnySdkVersion, "b", buildPath(ctx, "b"), installPath(ctx, "b"), nil)
56 m.AddContext(ctx, AnySdkVersion, "c", buildPath(ctx, "c"), installPath(ctx, "c"), nil)
Ulya Trafimovich69612672020-10-20 17:41:54 +010057
58 // Add some libraries with nested subcontexts.
59
Ulya Trafimovich8cbc5d22020-11-03 15:15:46 +000060 m1 := make(ClassLoaderContextMap)
Ulya Trafimovich7bc1cf52021-01-05 15:41:55 +000061 m1.AddContext(ctx, AnySdkVersion, "a1", buildPath(ctx, "a1"), installPath(ctx, "a1"), nil)
62 m1.AddContext(ctx, AnySdkVersion, "b1", buildPath(ctx, "b1"), installPath(ctx, "b1"), nil)
Ulya Trafimovich69612672020-10-20 17:41:54 +010063
Ulya Trafimovich8cbc5d22020-11-03 15:15:46 +000064 m2 := make(ClassLoaderContextMap)
Ulya Trafimovich7bc1cf52021-01-05 15:41:55 +000065 m2.AddContext(ctx, AnySdkVersion, "a2", buildPath(ctx, "a2"), installPath(ctx, "a2"), nil)
66 m2.AddContext(ctx, AnySdkVersion, "b2", buildPath(ctx, "b2"), installPath(ctx, "b2"), nil)
67 m2.AddContext(ctx, AnySdkVersion, "c2", buildPath(ctx, "c2"), installPath(ctx, "c2"), m1)
Ulya Trafimovich69612672020-10-20 17:41:54 +010068
Ulya Trafimovich8cbc5d22020-11-03 15:15:46 +000069 m3 := make(ClassLoaderContextMap)
Ulya Trafimovich7bc1cf52021-01-05 15:41:55 +000070 m3.AddContext(ctx, AnySdkVersion, "a3", buildPath(ctx, "a3"), installPath(ctx, "a3"), nil)
71 m3.AddContext(ctx, AnySdkVersion, "b3", buildPath(ctx, "b3"), installPath(ctx, "b3"), nil)
Ulya Trafimovich69612672020-10-20 17:41:54 +010072
Ulya Trafimovich7bc1cf52021-01-05 15:41:55 +000073 m.AddContext(ctx, AnySdkVersion, "d", buildPath(ctx, "d"), installPath(ctx, "d"), m2)
Ulya Trafimovich8cbc5d22020-11-03 15:15:46 +000074 // When the same library is both in conditional and unconditional context, it should be removed
75 // from conditional context.
Ulya Trafimovich7bc1cf52021-01-05 15:41:55 +000076 m.AddContext(ctx, 42, "f", buildPath(ctx, "f"), installPath(ctx, "f"), nil)
77 m.AddContext(ctx, AnySdkVersion, "f", buildPath(ctx, "f"), installPath(ctx, "f"), nil)
Ulya Trafimovich18554242020-11-03 15:55:11 +000078
79 // Merge map with implicit root library that is among toplevel contexts => does nothing.
80 m.AddContextMap(m1, "c")
81 // Merge map with implicit root library that is not among toplevel contexts => all subcontexts
82 // of the other map are added as toplevel contexts.
83 m.AddContextMap(m3, "m_g")
Ulya Trafimovich69612672020-10-20 17:41:54 +010084
85 // Compatibility libraries with unknown install paths get default paths.
Ulya Trafimovich7bc1cf52021-01-05 15:41:55 +000086 m.AddContext(ctx, 29, AndroidHidlManager, buildPath(ctx, AndroidHidlManager), nil, nil)
87 m.AddContext(ctx, 29, AndroidHidlBase, buildPath(ctx, AndroidHidlBase), nil, nil)
Ulya Trafimovich69612672020-10-20 17:41:54 +010088
89 // Add "android.test.mock" to conditional CLC, observe that is gets removed because it is only
90 // needed as a compatibility library if "android.test.runner" is in CLC as well.
Ulya Trafimovich7bc1cf52021-01-05 15:41:55 +000091 m.AddContext(ctx, 30, AndroidTestMock, buildPath(ctx, AndroidTestMock), nil, nil)
Ulya Trafimovich69612672020-10-20 17:41:54 +010092
Ulya Trafimovich8cbc5d22020-11-03 15:15:46 +000093 valid, validationError := validateClassLoaderContext(m)
Ulya Trafimovich69612672020-10-20 17:41:54 +010094
Ulya Trafimovich8cbc5d22020-11-03 15:15:46 +000095 fixClassLoaderContext(m)
Ulya Trafimovich69612672020-10-20 17:41:54 +010096
97 var haveStr string
98 var havePaths android.Paths
99 var haveUsesLibs []string
Ulya Trafimovich8cbc5d22020-11-03 15:15:46 +0000100 if valid && validationError == nil {
101 haveStr, havePaths = ComputeClassLoaderContext(m)
102 haveUsesLibs = m.UsesLibs()
Ulya Trafimovich69612672020-10-20 17:41:54 +0100103 }
104
105 // Test that validation is successful (all paths are known).
106 t.Run("validate", func(t *testing.T) {
Ulya Trafimovich8cbc5d22020-11-03 15:15:46 +0000107 if !(valid && validationError == nil) {
Ulya Trafimovich69612672020-10-20 17:41:54 +0100108 t.Errorf("invalid class loader context")
109 }
110 })
111
112 // Test that class loader context structure is correct.
113 t.Run("string", func(t *testing.T) {
114 wantStr := " --host-context-for-sdk 29 " +
115 "PCL[out/" + AndroidHidlManager + ".jar]#" +
116 "PCL[out/" + AndroidHidlBase + ".jar]" +
117 " --target-context-for-sdk 29 " +
118 "PCL[/system/framework/" + AndroidHidlManager + ".jar]#" +
119 "PCL[/system/framework/" + AndroidHidlBase + ".jar]" +
120 " --host-context-for-sdk any " +
Ulya Trafimovich8cbc5d22020-11-03 15:15:46 +0000121 "PCL[out/a.jar]#PCL[out/b.jar]#PCL[out/c.jar]#PCL[out/d.jar]" +
122 "{PCL[out/a2.jar]#PCL[out/b2.jar]#PCL[out/c2.jar]" +
123 "{PCL[out/a1.jar]#PCL[out/b1.jar]}}#" +
Ulya Trafimovich69612672020-10-20 17:41:54 +0100124 "PCL[out/f.jar]#PCL[out/a3.jar]#PCL[out/b3.jar]" +
125 " --target-context-for-sdk any " +
Ulya Trafimovich8cbc5d22020-11-03 15:15:46 +0000126 "PCL[/system/a.jar]#PCL[/system/b.jar]#PCL[/system/c.jar]#PCL[/system/d.jar]" +
127 "{PCL[/system/a2.jar]#PCL[/system/b2.jar]#PCL[/system/c2.jar]" +
128 "{PCL[/system/a1.jar]#PCL[/system/b1.jar]}}#" +
Ulya Trafimovich69612672020-10-20 17:41:54 +0100129 "PCL[/system/f.jar]#PCL[/system/a3.jar]#PCL[/system/b3.jar]"
130 if wantStr != haveStr {
131 t.Errorf("\nwant class loader context: %s\nhave class loader context: %s", wantStr, haveStr)
132 }
133 })
134
135 // Test that all expected build paths are gathered.
136 t.Run("paths", func(t *testing.T) {
137 wantPaths := []string{
138 "out/android.hidl.manager-V1.0-java.jar", "out/android.hidl.base-V1.0-java.jar",
139 "out/a.jar", "out/b.jar", "out/c.jar", "out/d.jar",
140 "out/a2.jar", "out/b2.jar", "out/c2.jar",
141 "out/a1.jar", "out/b1.jar",
142 "out/f.jar", "out/a3.jar", "out/b3.jar",
143 }
144 if !reflect.DeepEqual(wantPaths, havePaths.Strings()) {
145 t.Errorf("\nwant paths: %s\nhave paths: %s", wantPaths, havePaths)
146 }
147 })
148
149 // Test for libraries that are added by the manifest_fixer.
150 t.Run("uses libs", func(t *testing.T) {
Ulya Trafimovich78a71552020-11-25 14:20:52 +0000151 wantUsesLibs := []string{"a", "b", "c", "d", "f", "a3", "b3"}
Ulya Trafimovich69612672020-10-20 17:41:54 +0100152 if !reflect.DeepEqual(wantUsesLibs, haveUsesLibs) {
153 t.Errorf("\nwant uses libs: %s\nhave uses libs: %s", wantUsesLibs, haveUsesLibs)
154 }
155 })
156}
157
Jeongik Cha19ade892021-04-22 20:55:21 +0900158func TestCLCJson(t *testing.T) {
159 ctx := testContext()
160 m := make(ClassLoaderContextMap)
161 m.AddContext(ctx, 28, "a", buildPath(ctx, "a"), installPath(ctx, "a"), nil)
162 m.AddContext(ctx, 29, "b", buildPath(ctx, "b"), installPath(ctx, "b"), nil)
163 m.AddContext(ctx, 30, "c", buildPath(ctx, "c"), installPath(ctx, "c"), nil)
164 m.AddContext(ctx, AnySdkVersion, "d", buildPath(ctx, "d"), installPath(ctx, "d"), nil)
165 jsonCLC := toJsonClassLoaderContext(m)
166 restored := fromJsonClassLoaderContext(ctx, jsonCLC)
167 android.AssertIntEquals(t, "The size of the maps should be the same.", len(m), len(restored))
168 for k := range m {
169 a, _ := m[k]
170 b, ok := restored[k]
171 android.AssertBoolEquals(t, "The both maps should have the same keys.", ok, true)
172 android.AssertIntEquals(t, "The size of the elements should be the same.", len(a), len(b))
173 for i, elemA := range a {
174 before := fmt.Sprintf("%v", *elemA)
175 after := fmt.Sprintf("%v", *b[i])
176 android.AssertStringEquals(t, "The content should be the same.", before, after)
177 }
178 }
179}
180
Ulya Trafimovich7bc1cf52021-01-05 15:41:55 +0000181// Test that unknown library paths cause a validation error.
182func testCLCUnknownPath(t *testing.T, whichPath string) {
Ulya Trafimovich69612672020-10-20 17:41:54 +0100183 ctx := testContext()
184
Ulya Trafimovich8cbc5d22020-11-03 15:15:46 +0000185 m := make(ClassLoaderContextMap)
Ulya Trafimovich7bc1cf52021-01-05 15:41:55 +0000186 if whichPath == "build" {
187 m.AddContext(ctx, AnySdkVersion, "a", nil, nil, nil)
188 } else {
189 m.AddContext(ctx, AnySdkVersion, "a", buildPath(ctx, "a"), nil, nil)
190 }
Ulya Trafimovich69612672020-10-20 17:41:54 +0100191
Ulya Trafimovich8cbc5d22020-11-03 15:15:46 +0000192 // The library should be added to <uses-library> tags by the manifest_fixer.
Ulya Trafimovich7bc1cf52021-01-05 15:41:55 +0000193 t.Run("uses libs", func(t *testing.T) {
Ulya Trafimovich8cbc5d22020-11-03 15:15:46 +0000194 haveUsesLibs := m.UsesLibs()
195 wantUsesLibs := []string{"a"}
196 if !reflect.DeepEqual(wantUsesLibs, haveUsesLibs) {
197 t.Errorf("\nwant uses libs: %s\nhave uses libs: %s", wantUsesLibs, haveUsesLibs)
198 }
199 })
Ulya Trafimovich69612672020-10-20 17:41:54 +0100200
Ulya Trafimovich7bc1cf52021-01-05 15:41:55 +0000201 // But CLC cannot be constructed: there is a validation error.
202 _, err := validateClassLoaderContext(m)
203 checkError(t, err, fmt.Sprintf("invalid %s path for <uses-library> \"a\"", whichPath))
204}
205
206// Test that unknown build path is an error.
207func TestCLCUnknownBuildPath(t *testing.T) {
208 testCLCUnknownPath(t, "build")
209}
210
211// Test that unknown install path is an error.
212func TestCLCUnknownInstallPath(t *testing.T) {
213 testCLCUnknownPath(t, "install")
Ulya Trafimovich69612672020-10-20 17:41:54 +0100214}
215
Ulya Trafimovich5e13a732020-11-03 15:33:03 +0000216// An attempt to add conditional nested subcontext should fail.
217func TestCLCNestedConditional(t *testing.T) {
218 ctx := testContext()
219 m1 := make(ClassLoaderContextMap)
Ulya Trafimovich7bc1cf52021-01-05 15:41:55 +0000220 m1.AddContext(ctx, 42, "a", buildPath(ctx, "a"), installPath(ctx, "a"), nil)
Ulya Trafimovich5e13a732020-11-03 15:33:03 +0000221 m := make(ClassLoaderContextMap)
Ulya Trafimovich7bc1cf52021-01-05 15:41:55 +0000222 err := m.addContext(ctx, AnySdkVersion, "b", buildPath(ctx, "b"), installPath(ctx, "b"), m1)
Ulya Trafimovich5e13a732020-11-03 15:33:03 +0000223 checkError(t, err, "nested class loader context shouldn't have conditional part")
224}
225
Ulya Trafimovichc9f2b942020-12-23 15:41:29 +0000226// Test for SDK version order in conditional CLC: no matter in what order the libraries are added,
227// they end up in the order that agrees with PackageManager.
228func TestCLCSdkVersionOrder(t *testing.T) {
229 ctx := testContext()
230 m := make(ClassLoaderContextMap)
Ulya Trafimovich7bc1cf52021-01-05 15:41:55 +0000231 m.AddContext(ctx, 28, "a", buildPath(ctx, "a"), installPath(ctx, "a"), nil)
232 m.AddContext(ctx, 29, "b", buildPath(ctx, "b"), installPath(ctx, "b"), nil)
233 m.AddContext(ctx, 30, "c", buildPath(ctx, "c"), installPath(ctx, "c"), nil)
234 m.AddContext(ctx, AnySdkVersion, "d", buildPath(ctx, "d"), installPath(ctx, "d"), nil)
Ulya Trafimovichc9f2b942020-12-23 15:41:29 +0000235
236 valid, validationError := validateClassLoaderContext(m)
237
238 fixClassLoaderContext(m)
239
240 var haveStr string
241 if valid && validationError == nil {
242 haveStr, _ = ComputeClassLoaderContext(m)
243 }
244
245 // Test that validation is successful (all paths are known).
246 t.Run("validate", func(t *testing.T) {
247 if !(valid && validationError == nil) {
248 t.Errorf("invalid class loader context")
249 }
250 })
251
252 // Test that class loader context structure is correct.
253 t.Run("string", func(t *testing.T) {
254 wantStr := " --host-context-for-sdk 30 PCL[out/c.jar]" +
255 " --target-context-for-sdk 30 PCL[/system/c.jar]" +
256 " --host-context-for-sdk 29 PCL[out/b.jar]" +
257 " --target-context-for-sdk 29 PCL[/system/b.jar]" +
258 " --host-context-for-sdk 28 PCL[out/a.jar]" +
259 " --target-context-for-sdk 28 PCL[/system/a.jar]" +
260 " --host-context-for-sdk any PCL[out/d.jar]" +
261 " --target-context-for-sdk any PCL[/system/d.jar]"
262 if wantStr != haveStr {
263 t.Errorf("\nwant class loader context: %s\nhave class loader context: %s", wantStr, haveStr)
264 }
265 })
266}
267
Ulya Trafimovich69612672020-10-20 17:41:54 +0100268func checkError(t *testing.T, have error, want string) {
269 if have == nil {
270 t.Errorf("\nwant error: '%s'\nhave: none", want)
271 } else if msg := have.Error(); !strings.HasPrefix(msg, want) {
272 t.Errorf("\nwant error: '%s'\nhave error: '%s'\n", want, msg)
273 }
274}
275
276func testContext() android.ModuleInstallPathContext {
277 config := android.TestConfig("out", nil, "", nil)
278 return android.ModuleInstallPathContextForTesting(config)
279}
280
281func buildPath(ctx android.PathContext, lib string) android.Path {
282 return android.PathForOutput(ctx, lib+".jar")
283}
284
285func installPath(ctx android.ModuleInstallPathContext, lib string) android.InstallPath {
286 return android.PathForModuleInstall(ctx, lib+".jar")
287}