blob: df6856390665cbeddb83120c31bf2f59a0bcb60a [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
Ulya Trafimovich8cbc5d22020-11-03 15:15:46 +000040 // │   ├── a2
41 // │   ├── b2
42 // │   └── c2
43 // │   ├── a1
44 // │   └── b1
Ulya Trafimovich69612672020-10-20 17:41:54 +010045 // ├── f
46 // ├── a3
47 // └── b3
48 //
49 ctx := testContext()
50
Ulya Trafimovich8cbc5d22020-11-03 15:15:46 +000051 m := make(ClassLoaderContextMap)
Ulya Trafimovich69612672020-10-20 17:41:54 +010052
Ulya Trafimovich78a71552020-11-25 14:20:52 +000053 m.AddContext(ctx, "a", buildPath(ctx, "a"), installPath(ctx, "a"))
54 m.AddContext(ctx, "b", buildPath(ctx, "b"), installPath(ctx, "b"))
Ulya Trafimovich69612672020-10-20 17:41:54 +010055
56 // "Maybe" variant in the good case: add as usual.
57 c := "c"
Ulya Trafimovich78a71552020-11-25 14:20:52 +000058 m.MaybeAddContext(ctx, &c, buildPath(ctx, "c"), installPath(ctx, "c"))
Ulya Trafimovich69612672020-10-20 17:41:54 +010059
60 // "Maybe" variant in the bad case: don't add library with unknown name, keep going.
Ulya Trafimovich78a71552020-11-25 14:20:52 +000061 m.MaybeAddContext(ctx, nil, nil, nil)
Ulya Trafimovich69612672020-10-20 17:41:54 +010062
63 // Add some libraries with nested subcontexts.
64
Ulya Trafimovich8cbc5d22020-11-03 15:15:46 +000065 m1 := make(ClassLoaderContextMap)
Ulya Trafimovich78a71552020-11-25 14:20:52 +000066 m1.AddContext(ctx, "a1", buildPath(ctx, "a1"), installPath(ctx, "a1"))
67 m1.AddContext(ctx, "b1", buildPath(ctx, "b1"), installPath(ctx, "b1"))
Ulya Trafimovich69612672020-10-20 17:41:54 +010068
Ulya Trafimovich8cbc5d22020-11-03 15:15:46 +000069 m2 := make(ClassLoaderContextMap)
Ulya Trafimovich78a71552020-11-25 14:20:52 +000070 m2.AddContext(ctx, "a2", buildPath(ctx, "a2"), installPath(ctx, "a2"))
71 m2.AddContext(ctx, "b2", buildPath(ctx, "b2"), installPath(ctx, "b2"))
72 m2.AddContextForSdk(ctx, AnySdkVersion, "c2", buildPath(ctx, "c2"), installPath(ctx, "c2"), m1)
Ulya Trafimovich69612672020-10-20 17:41:54 +010073
Ulya Trafimovich8cbc5d22020-11-03 15:15:46 +000074 m3 := make(ClassLoaderContextMap)
Ulya Trafimovich78a71552020-11-25 14:20:52 +000075 m3.AddContext(ctx, "a3", buildPath(ctx, "a3"), installPath(ctx, "a3"))
76 m3.AddContext(ctx, "b3", buildPath(ctx, "b3"), installPath(ctx, "b3"))
Ulya Trafimovich69612672020-10-20 17:41:54 +010077
Ulya Trafimovich78a71552020-11-25 14:20:52 +000078 m.AddContextForSdk(ctx, AnySdkVersion, "d", buildPath(ctx, "d"), installPath(ctx, "d"), m2)
Ulya Trafimovich8cbc5d22020-11-03 15:15:46 +000079 // When the same library is both in conditional and unconditional context, it should be removed
80 // from conditional context.
Ulya Trafimovich78a71552020-11-25 14:20:52 +000081 m.AddContextForSdk(ctx, 42, "f", buildPath(ctx, "f"), installPath(ctx, "f"), nil)
82 m.AddContextForSdk(ctx, AnySdkVersion, "f", buildPath(ctx, "f"), installPath(ctx, "f"), nil)
Ulya Trafimovich18554242020-11-03 15:55:11 +000083
84 // Merge map with implicit root library that is among toplevel contexts => does nothing.
85 m.AddContextMap(m1, "c")
86 // Merge map with implicit root library that is not among toplevel contexts => all subcontexts
87 // of the other map are added as toplevel contexts.
88 m.AddContextMap(m3, "m_g")
Ulya Trafimovich69612672020-10-20 17:41:54 +010089
90 // Compatibility libraries with unknown install paths get default paths.
Ulya Trafimovich78a71552020-11-25 14:20:52 +000091 m.AddContextForSdk(ctx, 29, AndroidHidlManager, buildPath(ctx, AndroidHidlManager), nil, nil)
92 m.AddContextForSdk(ctx, 29, AndroidHidlBase, buildPath(ctx, AndroidHidlBase), nil, nil)
Ulya Trafimovich69612672020-10-20 17:41:54 +010093
94 // Add "android.test.mock" to conditional CLC, observe that is gets removed because it is only
95 // needed as a compatibility library if "android.test.runner" is in CLC as well.
Ulya Trafimovich78a71552020-11-25 14:20:52 +000096 m.AddContextForSdk(ctx, 30, AndroidTestMock, buildPath(ctx, AndroidTestMock), nil, nil)
Ulya Trafimovich69612672020-10-20 17:41:54 +010097
Ulya Trafimovich8cbc5d22020-11-03 15:15:46 +000098 valid, validationError := validateClassLoaderContext(m)
Ulya Trafimovich69612672020-10-20 17:41:54 +010099
Ulya Trafimovich8cbc5d22020-11-03 15:15:46 +0000100 fixClassLoaderContext(m)
Ulya Trafimovich69612672020-10-20 17:41:54 +0100101
102 var haveStr string
103 var havePaths android.Paths
104 var haveUsesLibs []string
Ulya Trafimovich8cbc5d22020-11-03 15:15:46 +0000105 if valid && validationError == nil {
106 haveStr, havePaths = ComputeClassLoaderContext(m)
107 haveUsesLibs = m.UsesLibs()
Ulya Trafimovich69612672020-10-20 17:41:54 +0100108 }
109
110 // Test that validation is successful (all paths are known).
111 t.Run("validate", func(t *testing.T) {
Ulya Trafimovich8cbc5d22020-11-03 15:15:46 +0000112 if !(valid && validationError == nil) {
Ulya Trafimovich69612672020-10-20 17:41:54 +0100113 t.Errorf("invalid class loader context")
114 }
115 })
116
117 // Test that class loader context structure is correct.
118 t.Run("string", func(t *testing.T) {
119 wantStr := " --host-context-for-sdk 29 " +
120 "PCL[out/" + AndroidHidlManager + ".jar]#" +
121 "PCL[out/" + AndroidHidlBase + ".jar]" +
122 " --target-context-for-sdk 29 " +
123 "PCL[/system/framework/" + AndroidHidlManager + ".jar]#" +
124 "PCL[/system/framework/" + AndroidHidlBase + ".jar]" +
125 " --host-context-for-sdk any " +
Ulya Trafimovich8cbc5d22020-11-03 15:15:46 +0000126 "PCL[out/a.jar]#PCL[out/b.jar]#PCL[out/c.jar]#PCL[out/d.jar]" +
127 "{PCL[out/a2.jar]#PCL[out/b2.jar]#PCL[out/c2.jar]" +
128 "{PCL[out/a1.jar]#PCL[out/b1.jar]}}#" +
Ulya Trafimovich69612672020-10-20 17:41:54 +0100129 "PCL[out/f.jar]#PCL[out/a3.jar]#PCL[out/b3.jar]" +
130 " --target-context-for-sdk any " +
Ulya Trafimovich8cbc5d22020-11-03 15:15:46 +0000131 "PCL[/system/a.jar]#PCL[/system/b.jar]#PCL[/system/c.jar]#PCL[/system/d.jar]" +
132 "{PCL[/system/a2.jar]#PCL[/system/b2.jar]#PCL[/system/c2.jar]" +
133 "{PCL[/system/a1.jar]#PCL[/system/b1.jar]}}#" +
Ulya Trafimovich69612672020-10-20 17:41:54 +0100134 "PCL[/system/f.jar]#PCL[/system/a3.jar]#PCL[/system/b3.jar]"
135 if wantStr != haveStr {
136 t.Errorf("\nwant class loader context: %s\nhave class loader context: %s", wantStr, haveStr)
137 }
138 })
139
140 // Test that all expected build paths are gathered.
141 t.Run("paths", func(t *testing.T) {
142 wantPaths := []string{
143 "out/android.hidl.manager-V1.0-java.jar", "out/android.hidl.base-V1.0-java.jar",
144 "out/a.jar", "out/b.jar", "out/c.jar", "out/d.jar",
145 "out/a2.jar", "out/b2.jar", "out/c2.jar",
146 "out/a1.jar", "out/b1.jar",
147 "out/f.jar", "out/a3.jar", "out/b3.jar",
148 }
149 if !reflect.DeepEqual(wantPaths, havePaths.Strings()) {
150 t.Errorf("\nwant paths: %s\nhave paths: %s", wantPaths, havePaths)
151 }
152 })
153
154 // Test for libraries that are added by the manifest_fixer.
155 t.Run("uses libs", func(t *testing.T) {
Ulya Trafimovich78a71552020-11-25 14:20:52 +0000156 wantUsesLibs := []string{"a", "b", "c", "d", "f", "a3", "b3"}
Ulya Trafimovich69612672020-10-20 17:41:54 +0100157 if !reflect.DeepEqual(wantUsesLibs, haveUsesLibs) {
158 t.Errorf("\nwant uses libs: %s\nhave uses libs: %s", wantUsesLibs, haveUsesLibs)
159 }
160 })
161}
162
163// Test that an unexpected unknown build path causes immediate error.
164func TestCLCUnknownBuildPath(t *testing.T) {
165 ctx := testContext()
Ulya Trafimovich8cbc5d22020-11-03 15:15:46 +0000166 m := make(ClassLoaderContextMap)
Ulya Trafimovich78a71552020-11-25 14:20:52 +0000167 err := m.addContext(ctx, AnySdkVersion, "a", nil, nil, true, nil)
Ulya Trafimovich8cbc5d22020-11-03 15:15:46 +0000168 checkError(t, err, "unknown build path to <uses-library> \"a\"")
Ulya Trafimovich69612672020-10-20 17:41:54 +0100169}
170
171// Test that an unexpected unknown install path causes immediate error.
172func TestCLCUnknownInstallPath(t *testing.T) {
173 ctx := testContext()
Ulya Trafimovich8cbc5d22020-11-03 15:15:46 +0000174 m := make(ClassLoaderContextMap)
Ulya Trafimovich78a71552020-11-25 14:20:52 +0000175 err := m.addContext(ctx, AnySdkVersion, "a", buildPath(ctx, "a"), nil, true, nil)
Ulya Trafimovich8cbc5d22020-11-03 15:15:46 +0000176 checkError(t, err, "unknown install path to <uses-library> \"a\"")
Ulya Trafimovich69612672020-10-20 17:41:54 +0100177}
178
179func TestCLCMaybeAdd(t *testing.T) {
180 ctx := testContext()
181
Ulya Trafimovich8cbc5d22020-11-03 15:15:46 +0000182 m := make(ClassLoaderContextMap)
Ulya Trafimovich69612672020-10-20 17:41:54 +0100183 a := "a"
Ulya Trafimovich78a71552020-11-25 14:20:52 +0000184 m.MaybeAddContext(ctx, &a, nil, nil)
Ulya Trafimovich69612672020-10-20 17:41:54 +0100185
Ulya Trafimovich8cbc5d22020-11-03 15:15:46 +0000186 // The library should be added to <uses-library> tags by the manifest_fixer.
187 t.Run("maybe add", func(t *testing.T) {
188 haveUsesLibs := m.UsesLibs()
189 wantUsesLibs := []string{"a"}
190 if !reflect.DeepEqual(wantUsesLibs, haveUsesLibs) {
191 t.Errorf("\nwant uses libs: %s\nhave uses libs: %s", wantUsesLibs, haveUsesLibs)
192 }
193 })
Ulya Trafimovich69612672020-10-20 17:41:54 +0100194
Ulya Trafimovich8cbc5d22020-11-03 15:15:46 +0000195 // But class loader context in such cases should raise an error on validation.
196 t.Run("validate", func(t *testing.T) {
197 _, err := validateClassLoaderContext(m)
198 checkError(t, err, "invalid path for <uses-library> \"a\"")
199 })
Ulya Trafimovich69612672020-10-20 17:41:54 +0100200}
201
Ulya Trafimovich5e13a732020-11-03 15:33:03 +0000202// An attempt to add conditional nested subcontext should fail.
203func TestCLCNestedConditional(t *testing.T) {
204 ctx := testContext()
205 m1 := make(ClassLoaderContextMap)
Ulya Trafimovich78a71552020-11-25 14:20:52 +0000206 m1.AddContextForSdk(ctx, 42, "a", buildPath(ctx, "a"), installPath(ctx, "a"), nil)
Ulya Trafimovich5e13a732020-11-03 15:33:03 +0000207 m := make(ClassLoaderContextMap)
Ulya Trafimovich78a71552020-11-25 14:20:52 +0000208 err := m.addContext(ctx, AnySdkVersion, "b", buildPath(ctx, "b"), installPath(ctx, "b"), true, m1)
Ulya Trafimovich5e13a732020-11-03 15:33:03 +0000209 checkError(t, err, "nested class loader context shouldn't have conditional part")
210}
211
Ulya Trafimovich69612672020-10-20 17:41:54 +0100212func checkError(t *testing.T, have error, want string) {
213 if have == nil {
214 t.Errorf("\nwant error: '%s'\nhave: none", want)
215 } else if msg := have.Error(); !strings.HasPrefix(msg, want) {
216 t.Errorf("\nwant error: '%s'\nhave error: '%s'\n", want, msg)
217 }
218}
219
220func testContext() android.ModuleInstallPathContext {
221 config := android.TestConfig("out", nil, "", nil)
222 return android.ModuleInstallPathContextForTesting(config)
223}
224
225func buildPath(ctx android.PathContext, lib string) android.Path {
226 return android.PathForOutput(ctx, lib+".jar")
227}
228
229func installPath(ctx android.ModuleInstallPathContext, lib string) android.InstallPath {
230 return android.PathForModuleInstall(ctx, lib+".jar")
231}