blob: abfca275956baa134a6f7caf34fd5d837d52697b [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
Ulya Trafimovicha8c28e22020-10-06 17:24:19 +010028const (
29 shared = true // dependencies are not added to uses libs
30 nonshared = false // dependencies are added to uses libs
31)
32
Ulya Trafimovich69612672020-10-20 17:41:54 +010033func TestCLC(t *testing.T) {
34 // Construct class loader context with the following structure:
35 // .
36 // ├── 29
37 // │   ├── android.hidl.manager
38 // │   └── android.hidl.base
39 // │
40 // └── any
41 // ├── a
42 // ├── b
43 // ├── c
44 // ├── d
Ulya Trafimovich8cbc5d22020-11-03 15:15:46 +000045 // │   ├── a2
46 // │   ├── b2
47 // │   └── c2
48 // │   ├── a1
49 // │   └── b1
Ulya Trafimovich69612672020-10-20 17:41:54 +010050 // ├── f
51 // ├── a3
52 // └── b3
53 //
54 ctx := testContext()
55
Ulya Trafimovich8cbc5d22020-11-03 15:15:46 +000056 m := make(ClassLoaderContextMap)
Ulya Trafimovich69612672020-10-20 17:41:54 +010057
Ulya Trafimovicha8c28e22020-10-06 17:24:19 +010058 m.AddContext(ctx, "a", nonshared, buildPath(ctx, "a"), installPath(ctx, "a"))
59 m.AddContext(ctx, "b", shared, buildPath(ctx, "b"), installPath(ctx, "b"))
Ulya Trafimovich69612672020-10-20 17:41:54 +010060
61 // "Maybe" variant in the good case: add as usual.
62 c := "c"
Ulya Trafimovicha8c28e22020-10-06 17:24:19 +010063 m.MaybeAddContext(ctx, &c, nonshared, buildPath(ctx, "c"), installPath(ctx, "c"))
Ulya Trafimovich69612672020-10-20 17:41:54 +010064
65 // "Maybe" variant in the bad case: don't add library with unknown name, keep going.
Ulya Trafimovicha8c28e22020-10-06 17:24:19 +010066 m.MaybeAddContext(ctx, nil, nonshared, nil, nil)
Ulya Trafimovich69612672020-10-20 17:41:54 +010067
68 // Add some libraries with nested subcontexts.
69
Ulya Trafimovich8cbc5d22020-11-03 15:15:46 +000070 m1 := make(ClassLoaderContextMap)
Ulya Trafimovicha8c28e22020-10-06 17:24:19 +010071 m1.AddContext(ctx, "a1", nonshared, buildPath(ctx, "a1"), installPath(ctx, "a1"))
72 m1.AddContext(ctx, "b1", shared, buildPath(ctx, "b1"), installPath(ctx, "b1"))
Ulya Trafimovich69612672020-10-20 17:41:54 +010073
Ulya Trafimovich8cbc5d22020-11-03 15:15:46 +000074 m2 := make(ClassLoaderContextMap)
Ulya Trafimovicha8c28e22020-10-06 17:24:19 +010075 m2.AddContext(ctx, "a2", nonshared, buildPath(ctx, "a2"), installPath(ctx, "a2"))
76 m2.AddContext(ctx, "b2", shared, buildPath(ctx, "b2"), installPath(ctx, "b2"))
77 m2.AddContextForSdk(ctx, AnySdkVersion, "c2", shared, buildPath(ctx, "c2"), installPath(ctx, "c2"), m1)
Ulya Trafimovich69612672020-10-20 17:41:54 +010078
Ulya Trafimovich8cbc5d22020-11-03 15:15:46 +000079 m3 := make(ClassLoaderContextMap)
Ulya Trafimovicha8c28e22020-10-06 17:24:19 +010080 m3.AddContext(ctx, "a3", nonshared, buildPath(ctx, "a3"), installPath(ctx, "a3"))
81 m3.AddContext(ctx, "b3", shared, buildPath(ctx, "b3"), installPath(ctx, "b3"))
Ulya Trafimovich69612672020-10-20 17:41:54 +010082
Ulya Trafimovicha8c28e22020-10-06 17:24:19 +010083 m.AddContextForSdk(ctx, AnySdkVersion, "d", nonshared, buildPath(ctx, "d"), installPath(ctx, "d"), m2)
Ulya Trafimovich8cbc5d22020-11-03 15:15:46 +000084 // When the same library is both in conditional and unconditional context, it should be removed
85 // from conditional context.
Ulya Trafimovicha8c28e22020-10-06 17:24:19 +010086 m.AddContextForSdk(ctx, 42, "f", nonshared, buildPath(ctx, "f"), installPath(ctx, "f"), nil)
87 m.AddContextForSdk(ctx, AnySdkVersion, "f", nonshared, buildPath(ctx, "f"), installPath(ctx, "f"), nil)
Ulya Trafimovich18554242020-11-03 15:55:11 +000088
89 // Merge map with implicit root library that is among toplevel contexts => does nothing.
90 m.AddContextMap(m1, "c")
91 // Merge map with implicit root library that is not among toplevel contexts => all subcontexts
92 // of the other map are added as toplevel contexts.
93 m.AddContextMap(m3, "m_g")
Ulya Trafimovich69612672020-10-20 17:41:54 +010094
95 // Compatibility libraries with unknown install paths get default paths.
Ulya Trafimovicha8c28e22020-10-06 17:24:19 +010096 m.AddContextForSdk(ctx, 29, AndroidHidlManager, nonshared, buildPath(ctx, AndroidHidlManager), nil, nil)
97 m.AddContextForSdk(ctx, 29, AndroidHidlBase, nonshared, buildPath(ctx, AndroidHidlBase), nil, nil)
Ulya Trafimovich69612672020-10-20 17:41:54 +010098
99 // Add "android.test.mock" to conditional CLC, observe that is gets removed because it is only
100 // needed as a compatibility library if "android.test.runner" is in CLC as well.
Ulya Trafimovicha8c28e22020-10-06 17:24:19 +0100101 m.AddContextForSdk(ctx, 30, AndroidTestMock, nonshared, buildPath(ctx, AndroidTestMock), nil, nil)
Ulya Trafimovich69612672020-10-20 17:41:54 +0100102
Ulya Trafimovich8cbc5d22020-11-03 15:15:46 +0000103 valid, validationError := validateClassLoaderContext(m)
Ulya Trafimovich69612672020-10-20 17:41:54 +0100104
Ulya Trafimovich8cbc5d22020-11-03 15:15:46 +0000105 fixClassLoaderContext(m)
Ulya Trafimovich69612672020-10-20 17:41:54 +0100106
107 var haveStr string
108 var havePaths android.Paths
109 var haveUsesLibs []string
Ulya Trafimovich8cbc5d22020-11-03 15:15:46 +0000110 if valid && validationError == nil {
111 haveStr, havePaths = ComputeClassLoaderContext(m)
112 haveUsesLibs = m.UsesLibs()
Ulya Trafimovich69612672020-10-20 17:41:54 +0100113 }
114
115 // Test that validation is successful (all paths are known).
116 t.Run("validate", func(t *testing.T) {
Ulya Trafimovich8cbc5d22020-11-03 15:15:46 +0000117 if !(valid && validationError == nil) {
Ulya Trafimovich69612672020-10-20 17:41:54 +0100118 t.Errorf("invalid class loader context")
119 }
120 })
121
122 // Test that class loader context structure is correct.
123 t.Run("string", func(t *testing.T) {
124 wantStr := " --host-context-for-sdk 29 " +
125 "PCL[out/" + AndroidHidlManager + ".jar]#" +
126 "PCL[out/" + AndroidHidlBase + ".jar]" +
127 " --target-context-for-sdk 29 " +
128 "PCL[/system/framework/" + AndroidHidlManager + ".jar]#" +
129 "PCL[/system/framework/" + AndroidHidlBase + ".jar]" +
130 " --host-context-for-sdk any " +
Ulya Trafimovich8cbc5d22020-11-03 15:15:46 +0000131 "PCL[out/a.jar]#PCL[out/b.jar]#PCL[out/c.jar]#PCL[out/d.jar]" +
132 "{PCL[out/a2.jar]#PCL[out/b2.jar]#PCL[out/c2.jar]" +
133 "{PCL[out/a1.jar]#PCL[out/b1.jar]}}#" +
Ulya Trafimovich69612672020-10-20 17:41:54 +0100134 "PCL[out/f.jar]#PCL[out/a3.jar]#PCL[out/b3.jar]" +
135 " --target-context-for-sdk any " +
Ulya Trafimovich8cbc5d22020-11-03 15:15:46 +0000136 "PCL[/system/a.jar]#PCL[/system/b.jar]#PCL[/system/c.jar]#PCL[/system/d.jar]" +
137 "{PCL[/system/a2.jar]#PCL[/system/b2.jar]#PCL[/system/c2.jar]" +
138 "{PCL[/system/a1.jar]#PCL[/system/b1.jar]}}#" +
Ulya Trafimovich69612672020-10-20 17:41:54 +0100139 "PCL[/system/f.jar]#PCL[/system/a3.jar]#PCL[/system/b3.jar]"
140 if wantStr != haveStr {
141 t.Errorf("\nwant class loader context: %s\nhave class loader context: %s", wantStr, haveStr)
142 }
143 })
144
145 // Test that all expected build paths are gathered.
146 t.Run("paths", func(t *testing.T) {
147 wantPaths := []string{
148 "out/android.hidl.manager-V1.0-java.jar", "out/android.hidl.base-V1.0-java.jar",
149 "out/a.jar", "out/b.jar", "out/c.jar", "out/d.jar",
150 "out/a2.jar", "out/b2.jar", "out/c2.jar",
151 "out/a1.jar", "out/b1.jar",
152 "out/f.jar", "out/a3.jar", "out/b3.jar",
153 }
154 if !reflect.DeepEqual(wantPaths, havePaths.Strings()) {
155 t.Errorf("\nwant paths: %s\nhave paths: %s", wantPaths, havePaths)
156 }
157 })
158
159 // Test for libraries that are added by the manifest_fixer.
160 t.Run("uses libs", func(t *testing.T) {
Ulya Trafimovicha8c28e22020-10-06 17:24:19 +0100161 wantUsesLibs := []string{"a", "b", "c", "d", "a2", "b2", "c2", "f", "a3", "b3"}
Ulya Trafimovich69612672020-10-20 17:41:54 +0100162 if !reflect.DeepEqual(wantUsesLibs, haveUsesLibs) {
163 t.Errorf("\nwant uses libs: %s\nhave uses libs: %s", wantUsesLibs, haveUsesLibs)
164 }
165 })
166}
167
168// Test that an unexpected unknown build path causes immediate error.
169func TestCLCUnknownBuildPath(t *testing.T) {
170 ctx := testContext()
Ulya Trafimovich8cbc5d22020-11-03 15:15:46 +0000171 m := make(ClassLoaderContextMap)
Ulya Trafimovicha8c28e22020-10-06 17:24:19 +0100172 err := m.addContext(ctx, AnySdkVersion, "a", nonshared, nil, nil, true, nil)
Ulya Trafimovich8cbc5d22020-11-03 15:15:46 +0000173 checkError(t, err, "unknown build path to <uses-library> \"a\"")
Ulya Trafimovich69612672020-10-20 17:41:54 +0100174}
175
176// Test that an unexpected unknown install path causes immediate error.
177func TestCLCUnknownInstallPath(t *testing.T) {
178 ctx := testContext()
Ulya Trafimovich8cbc5d22020-11-03 15:15:46 +0000179 m := make(ClassLoaderContextMap)
Ulya Trafimovicha8c28e22020-10-06 17:24:19 +0100180 err := m.addContext(ctx, AnySdkVersion, "a", nonshared, buildPath(ctx, "a"), nil, true, nil)
Ulya Trafimovich8cbc5d22020-11-03 15:15:46 +0000181 checkError(t, err, "unknown install path to <uses-library> \"a\"")
Ulya Trafimovich69612672020-10-20 17:41:54 +0100182}
183
184func TestCLCMaybeAdd(t *testing.T) {
185 ctx := testContext()
186
Ulya Trafimovich8cbc5d22020-11-03 15:15:46 +0000187 m := make(ClassLoaderContextMap)
Ulya Trafimovich69612672020-10-20 17:41:54 +0100188 a := "a"
Ulya Trafimovicha8c28e22020-10-06 17:24:19 +0100189 m.MaybeAddContext(ctx, &a, nonshared, nil, nil)
Ulya Trafimovich69612672020-10-20 17:41:54 +0100190
Ulya Trafimovich8cbc5d22020-11-03 15:15:46 +0000191 // The library should be added to <uses-library> tags by the manifest_fixer.
192 t.Run("maybe add", func(t *testing.T) {
193 haveUsesLibs := m.UsesLibs()
194 wantUsesLibs := []string{"a"}
195 if !reflect.DeepEqual(wantUsesLibs, haveUsesLibs) {
196 t.Errorf("\nwant uses libs: %s\nhave uses libs: %s", wantUsesLibs, haveUsesLibs)
197 }
198 })
Ulya Trafimovich69612672020-10-20 17:41:54 +0100199
Ulya Trafimovich8cbc5d22020-11-03 15:15:46 +0000200 // But class loader context in such cases should raise an error on validation.
201 t.Run("validate", func(t *testing.T) {
202 _, err := validateClassLoaderContext(m)
203 checkError(t, err, "invalid path for <uses-library> \"a\"")
204 })
Ulya Trafimovich69612672020-10-20 17:41:54 +0100205}
206
Ulya Trafimovich5e13a732020-11-03 15:33:03 +0000207// An attempt to add conditional nested subcontext should fail.
208func TestCLCNestedConditional(t *testing.T) {
209 ctx := testContext()
210 m1 := make(ClassLoaderContextMap)
Ulya Trafimovicha8c28e22020-10-06 17:24:19 +0100211 m1.AddContextForSdk(ctx, 42, "a", nonshared, buildPath(ctx, "a"), installPath(ctx, "a"), nil)
Ulya Trafimovich5e13a732020-11-03 15:33:03 +0000212 m := make(ClassLoaderContextMap)
Ulya Trafimovicha8c28e22020-10-06 17:24:19 +0100213 err := m.addContext(ctx, AnySdkVersion, "b", nonshared, buildPath(ctx, "b"), installPath(ctx, "b"), true, m1)
Ulya Trafimovich5e13a732020-11-03 15:33:03 +0000214 checkError(t, err, "nested class loader context shouldn't have conditional part")
215}
216
Ulya Trafimovich69612672020-10-20 17:41:54 +0100217func checkError(t *testing.T, have error, want string) {
218 if have == nil {
219 t.Errorf("\nwant error: '%s'\nhave: none", want)
220 } else if msg := have.Error(); !strings.HasPrefix(msg, want) {
221 t.Errorf("\nwant error: '%s'\nhave error: '%s'\n", want, msg)
222 }
223}
224
225func testContext() android.ModuleInstallPathContext {
226 config := android.TestConfig("out", nil, "", nil)
227 return android.ModuleInstallPathContextForTesting(config)
228}
229
230func buildPath(ctx android.PathContext, lib string) android.Path {
231 return android.PathForOutput(ctx, lib+".jar")
232}
233
234func installPath(ctx android.ModuleInstallPathContext, lib string) android.InstallPath {
235 return android.PathForModuleInstall(ctx, lib+".jar")
236}