blob: 86f7871a02b1a10b36d176e19fb7a47fc10456c6 [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
Ulya Trafimovich7bc1cf52021-01-05 15:41:55 +0000158// Test that unknown library paths cause a validation error.
159func testCLCUnknownPath(t *testing.T, whichPath string) {
Ulya Trafimovich69612672020-10-20 17:41:54 +0100160 ctx := testContext()
161
Ulya Trafimovich8cbc5d22020-11-03 15:15:46 +0000162 m := make(ClassLoaderContextMap)
Ulya Trafimovich7bc1cf52021-01-05 15:41:55 +0000163 if whichPath == "build" {
164 m.AddContext(ctx, AnySdkVersion, "a", nil, nil, nil)
165 } else {
166 m.AddContext(ctx, AnySdkVersion, "a", buildPath(ctx, "a"), nil, nil)
167 }
Ulya Trafimovich69612672020-10-20 17:41:54 +0100168
Ulya Trafimovich8cbc5d22020-11-03 15:15:46 +0000169 // The library should be added to <uses-library> tags by the manifest_fixer.
Ulya Trafimovich7bc1cf52021-01-05 15:41:55 +0000170 t.Run("uses libs", func(t *testing.T) {
Ulya Trafimovich8cbc5d22020-11-03 15:15:46 +0000171 haveUsesLibs := m.UsesLibs()
172 wantUsesLibs := []string{"a"}
173 if !reflect.DeepEqual(wantUsesLibs, haveUsesLibs) {
174 t.Errorf("\nwant uses libs: %s\nhave uses libs: %s", wantUsesLibs, haveUsesLibs)
175 }
176 })
Ulya Trafimovich69612672020-10-20 17:41:54 +0100177
Ulya Trafimovich7bc1cf52021-01-05 15:41:55 +0000178 // But CLC cannot be constructed: there is a validation error.
179 _, err := validateClassLoaderContext(m)
180 checkError(t, err, fmt.Sprintf("invalid %s path for <uses-library> \"a\"", whichPath))
181}
182
183// Test that unknown build path is an error.
184func TestCLCUnknownBuildPath(t *testing.T) {
185 testCLCUnknownPath(t, "build")
186}
187
188// Test that unknown install path is an error.
189func TestCLCUnknownInstallPath(t *testing.T) {
190 testCLCUnknownPath(t, "install")
Ulya Trafimovich69612672020-10-20 17:41:54 +0100191}
192
Ulya Trafimovich5e13a732020-11-03 15:33:03 +0000193// An attempt to add conditional nested subcontext should fail.
194func TestCLCNestedConditional(t *testing.T) {
195 ctx := testContext()
196 m1 := make(ClassLoaderContextMap)
Ulya Trafimovich7bc1cf52021-01-05 15:41:55 +0000197 m1.AddContext(ctx, 42, "a", buildPath(ctx, "a"), installPath(ctx, "a"), nil)
Ulya Trafimovich5e13a732020-11-03 15:33:03 +0000198 m := make(ClassLoaderContextMap)
Ulya Trafimovich7bc1cf52021-01-05 15:41:55 +0000199 err := m.addContext(ctx, AnySdkVersion, "b", buildPath(ctx, "b"), installPath(ctx, "b"), m1)
Ulya Trafimovich5e13a732020-11-03 15:33:03 +0000200 checkError(t, err, "nested class loader context shouldn't have conditional part")
201}
202
Ulya Trafimovichc9f2b942020-12-23 15:41:29 +0000203// Test for SDK version order in conditional CLC: no matter in what order the libraries are added,
204// they end up in the order that agrees with PackageManager.
205func TestCLCSdkVersionOrder(t *testing.T) {
206 ctx := testContext()
207 m := make(ClassLoaderContextMap)
Ulya Trafimovich7bc1cf52021-01-05 15:41:55 +0000208 m.AddContext(ctx, 28, "a", buildPath(ctx, "a"), installPath(ctx, "a"), nil)
209 m.AddContext(ctx, 29, "b", buildPath(ctx, "b"), installPath(ctx, "b"), nil)
210 m.AddContext(ctx, 30, "c", buildPath(ctx, "c"), installPath(ctx, "c"), nil)
211 m.AddContext(ctx, AnySdkVersion, "d", buildPath(ctx, "d"), installPath(ctx, "d"), nil)
Ulya Trafimovichc9f2b942020-12-23 15:41:29 +0000212
213 valid, validationError := validateClassLoaderContext(m)
214
215 fixClassLoaderContext(m)
216
217 var haveStr string
218 if valid && validationError == nil {
219 haveStr, _ = ComputeClassLoaderContext(m)
220 }
221
222 // Test that validation is successful (all paths are known).
223 t.Run("validate", func(t *testing.T) {
224 if !(valid && validationError == nil) {
225 t.Errorf("invalid class loader context")
226 }
227 })
228
229 // Test that class loader context structure is correct.
230 t.Run("string", func(t *testing.T) {
231 wantStr := " --host-context-for-sdk 30 PCL[out/c.jar]" +
232 " --target-context-for-sdk 30 PCL[/system/c.jar]" +
233 " --host-context-for-sdk 29 PCL[out/b.jar]" +
234 " --target-context-for-sdk 29 PCL[/system/b.jar]" +
235 " --host-context-for-sdk 28 PCL[out/a.jar]" +
236 " --target-context-for-sdk 28 PCL[/system/a.jar]" +
237 " --host-context-for-sdk any PCL[out/d.jar]" +
238 " --target-context-for-sdk any PCL[/system/d.jar]"
239 if wantStr != haveStr {
240 t.Errorf("\nwant class loader context: %s\nhave class loader context: %s", wantStr, haveStr)
241 }
242 })
243}
244
Ulya Trafimovich69612672020-10-20 17:41:54 +0100245func checkError(t *testing.T, have error, want string) {
246 if have == nil {
247 t.Errorf("\nwant error: '%s'\nhave: none", want)
248 } else if msg := have.Error(); !strings.HasPrefix(msg, want) {
249 t.Errorf("\nwant error: '%s'\nhave error: '%s'\n", want, msg)
250 }
251}
252
253func testContext() android.ModuleInstallPathContext {
254 config := android.TestConfig("out", nil, "", nil)
255 return android.ModuleInstallPathContextForTesting(config)
256}
257
258func buildPath(ctx android.PathContext, lib string) android.Path {
259 return android.PathForOutput(ctx, lib+".jar")
260}
261
262func installPath(ctx android.ModuleInstallPathContext, lib string) android.InstallPath {
263 return android.PathForModuleInstall(ctx, lib+".jar")
264}