blob: 51c1a0a1f4f3246b38ec2077dad61fb230982f75 [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 (
21 "reflect"
22 "strings"
23 "testing"
24
25 "android/soong/android"
26)
27
28func TestCLC(t *testing.T) {
29 // Construct class loader context with the following structure:
30 // .
31 // ├── 29
32 // │   ├── android.hidl.manager
33 // │   └── android.hidl.base
34 // │
35 // └── any
36 // ├── a
37 // ├── b
38 // ├── c
39 // ├── d
40 // ├── a2
41 // ├── b2
42 // ├── c2
43 // ├── a1
44 // ├── b1
45 // ├── f
46 // ├── a3
47 // └── b3
48 //
49 ctx := testContext()
50
51 lp := make(LibraryPaths)
52
53 lp.AddLibraryPath(ctx, "a", buildPath(ctx, "a"), installPath(ctx, "a"))
54 lp.AddLibraryPath(ctx, "b", buildPath(ctx, "b"), installPath(ctx, "b"))
55
56 // "Maybe" variant in the good case: add as usual.
57 c := "c"
58 lp.MaybeAddLibraryPath(ctx, &c, buildPath(ctx, "c"), installPath(ctx, "c"))
59
60 // "Maybe" variant in the bad case: don't add library with unknown name, keep going.
61 lp.MaybeAddLibraryPath(ctx, nil, nil, nil)
62
63 // Add some libraries with nested subcontexts.
64
65 lp1 := make(LibraryPaths)
66 lp1.AddLibraryPath(ctx, "a1", buildPath(ctx, "a1"), installPath(ctx, "a1"))
67 lp1.AddLibraryPath(ctx, "b1", buildPath(ctx, "b1"), installPath(ctx, "b1"))
68
69 lp2 := make(LibraryPaths)
70 lp2.AddLibraryPath(ctx, "a2", buildPath(ctx, "a2"), installPath(ctx, "a2"))
71 lp2.AddLibraryPath(ctx, "b2", buildPath(ctx, "b2"), installPath(ctx, "b2"))
72 lp2.AddLibraryPath(ctx, "c2", buildPath(ctx, "c2"), installPath(ctx, "c2"))
73 lp2.AddLibraryPaths(lp1)
74
75 lp.AddLibraryPath(ctx, "d", buildPath(ctx, "d"), installPath(ctx, "d"))
76 lp.AddLibraryPaths(lp2)
77
78 lp3 := make(LibraryPaths)
79 lp3.AddLibraryPath(ctx, "f", buildPath(ctx, "f"), installPath(ctx, "f"))
80 lp3.AddLibraryPath(ctx, "a3", buildPath(ctx, "a3"), installPath(ctx, "a3"))
81 lp3.AddLibraryPath(ctx, "b3", buildPath(ctx, "b3"), installPath(ctx, "b3"))
82 lp.AddLibraryPaths(lp3)
83
84 // Compatibility libraries with unknown install paths get default paths.
85 lp.AddLibraryPath(ctx, AndroidHidlBase, buildPath(ctx, AndroidHidlBase), nil)
86 lp.AddLibraryPath(ctx, AndroidHidlManager, buildPath(ctx, AndroidHidlManager), nil)
87 lp.AddLibraryPath(ctx, AndroidTestMock, buildPath(ctx, AndroidTestMock), nil)
88
89 module := testSystemModuleConfig(ctx, "test")
90 module.LibraryPaths = lp
91
92 m := make(classLoaderContextMap)
93 valid := true
94
95 ok, err := m.addLibs(ctx, AnySdkVersion, module, "a", "b", "c", "d", "a2", "b2", "c2", "a1", "b1", "f", "a3", "b3")
96 valid = valid && ok && err == nil
97
98 // Add compatibility libraries to conditional CLC for SDK level 29.
99 ok, err = m.addLibs(ctx, 29, module, AndroidHidlManager, AndroidHidlBase)
100 valid = valid && ok && err == nil
101
102 // Add "android.test.mock" to conditional CLC, observe that is gets removed because it is only
103 // needed as a compatibility library if "android.test.runner" is in CLC as well.
104 ok, err = m.addLibs(ctx, 30, module, AndroidTestMock)
105 valid = valid && ok && err == nil
106
107 // When the same library is both in conditional and unconditional context, it should be removed
108 // from conditional context.
109 ok, err = m.addLibs(ctx, 42, module, "f")
110 valid = valid && ok && err == nil
111
112 fixConditionalClassLoaderContext(m)
113
114 var haveStr string
115 var havePaths android.Paths
116 var haveUsesLibs []string
117 if valid {
118 haveStr, havePaths = computeClassLoaderContext(ctx, m)
119 haveUsesLibs = m.usesLibs()
120 }
121
122 // Test that validation is successful (all paths are known).
123 t.Run("validate", func(t *testing.T) {
124 if !valid {
125 t.Errorf("invalid class loader context")
126 }
127 })
128
129 // Test that class loader context structure is correct.
130 t.Run("string", func(t *testing.T) {
131 wantStr := " --host-context-for-sdk 29 " +
132 "PCL[out/" + AndroidHidlManager + ".jar]#" +
133 "PCL[out/" + AndroidHidlBase + ".jar]" +
134 " --target-context-for-sdk 29 " +
135 "PCL[/system/framework/" + AndroidHidlManager + ".jar]#" +
136 "PCL[/system/framework/" + AndroidHidlBase + ".jar]" +
137 " --host-context-for-sdk any " +
138 "PCL[out/a.jar]#PCL[out/b.jar]#PCL[out/c.jar]#PCL[out/d.jar]#" +
139 "PCL[out/a2.jar]#PCL[out/b2.jar]#PCL[out/c2.jar]#" +
140 "PCL[out/a1.jar]#PCL[out/b1.jar]#" +
141 "PCL[out/f.jar]#PCL[out/a3.jar]#PCL[out/b3.jar]" +
142 " --target-context-for-sdk any " +
143 "PCL[/system/a.jar]#PCL[/system/b.jar]#PCL[/system/c.jar]#PCL[/system/d.jar]#" +
144 "PCL[/system/a2.jar]#PCL[/system/b2.jar]#PCL[/system/c2.jar]#" +
145 "PCL[/system/a1.jar]#PCL[/system/b1.jar]#" +
146 "PCL[/system/f.jar]#PCL[/system/a3.jar]#PCL[/system/b3.jar]"
147 if wantStr != haveStr {
148 t.Errorf("\nwant class loader context: %s\nhave class loader context: %s", wantStr, haveStr)
149 }
150 })
151
152 // Test that all expected build paths are gathered.
153 t.Run("paths", func(t *testing.T) {
154 wantPaths := []string{
155 "out/android.hidl.manager-V1.0-java.jar", "out/android.hidl.base-V1.0-java.jar",
156 "out/a.jar", "out/b.jar", "out/c.jar", "out/d.jar",
157 "out/a2.jar", "out/b2.jar", "out/c2.jar",
158 "out/a1.jar", "out/b1.jar",
159 "out/f.jar", "out/a3.jar", "out/b3.jar",
160 }
161 if !reflect.DeepEqual(wantPaths, havePaths.Strings()) {
162 t.Errorf("\nwant paths: %s\nhave paths: %s", wantPaths, havePaths)
163 }
164 })
165
166 // Test for libraries that are added by the manifest_fixer.
167 t.Run("uses libs", func(t *testing.T) {
168 wantUsesLibs := []string{"a", "b", "c", "d", "a2", "b2", "c2", "a1", "b1", "f", "a3", "b3"}
169 if !reflect.DeepEqual(wantUsesLibs, haveUsesLibs) {
170 t.Errorf("\nwant uses libs: %s\nhave uses libs: %s", wantUsesLibs, haveUsesLibs)
171 }
172 })
173}
174
175// Test that an unexpected unknown build path causes immediate error.
176func TestCLCUnknownBuildPath(t *testing.T) {
177 ctx := testContext()
178 lp := make(LibraryPaths)
179 err := lp.addLibraryPath(ctx, "a", nil, nil, true)
180 checkError(t, err, "unknown build path to <uses-library> 'a'")
181}
182
183// Test that an unexpected unknown install path causes immediate error.
184func TestCLCUnknownInstallPath(t *testing.T) {
185 ctx := testContext()
186 lp := make(LibraryPaths)
187 err := lp.addLibraryPath(ctx, "a", buildPath(ctx, "a"), nil, true)
188 checkError(t, err, "unknown install path to <uses-library> 'a'")
189}
190
191func TestCLCMaybeAdd(t *testing.T) {
192 ctx := testContext()
193
194 lp := make(LibraryPaths)
195 a := "a"
196 lp.MaybeAddLibraryPath(ctx, &a, nil, nil)
197
198 module := testSystemModuleConfig(ctx, "test")
199 module.LibraryPaths = lp
200
201 m := make(classLoaderContextMap)
202 _, err := m.addLibs(ctx, AnySdkVersion, module, "a")
203 checkError(t, err, "dexpreopt cannot find path for <uses-library> 'a'")
204}
205
206func checkError(t *testing.T, have error, want string) {
207 if have == nil {
208 t.Errorf("\nwant error: '%s'\nhave: none", want)
209 } else if msg := have.Error(); !strings.HasPrefix(msg, want) {
210 t.Errorf("\nwant error: '%s'\nhave error: '%s'\n", want, msg)
211 }
212}
213
214func testContext() android.ModuleInstallPathContext {
215 config := android.TestConfig("out", nil, "", nil)
216 return android.ModuleInstallPathContextForTesting(config)
217}
218
219func buildPath(ctx android.PathContext, lib string) android.Path {
220 return android.PathForOutput(ctx, lib+".jar")
221}
222
223func installPath(ctx android.ModuleInstallPathContext, lib string) android.InstallPath {
224 return android.PathForModuleInstall(ctx, lib+".jar")
225}