blob: aed354367803cddd2637183bb8bf02b341673c49 [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 Trafimovich8cbc5d22020-11-03 15:15:46 +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 Trafimovich8cbc5d22020-11-03 15:15:46 +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 Trafimovich8cbc5d22020-11-03 15:15:46 +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)
66 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)
70 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)
75 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 Trafimovich8cbc5d22020-11-03 15:15:46 +000078 m.AddContextForSdk(ctx, AnySdkVersion, "d", buildPath(ctx, "d"), installPath(ctx, "d"), m2)
79 // When the same library is both in conditional and unconditional context, it should be removed
80 // from conditional context.
81 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)
83 m.AddContextMap(m3)
Ulya Trafimovich69612672020-10-20 17:41:54 +010084
85 // Compatibility libraries with unknown install paths get default paths.
Ulya Trafimovich8cbc5d22020-11-03 15:15:46 +000086 m.AddContextForSdk(ctx, 29, AndroidHidlManager, buildPath(ctx, AndroidHidlManager), nil, nil)
87 m.AddContextForSdk(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 Trafimovich8cbc5d22020-11-03 15:15:46 +000091 m.AddContextForSdk(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) {
151 wantUsesLibs := []string{"a", "b", "c", "d", "a2", "b2", "c2", "a1", "b1", "f", "a3", "b3"}
152 if !reflect.DeepEqual(wantUsesLibs, haveUsesLibs) {
153 t.Errorf("\nwant uses libs: %s\nhave uses libs: %s", wantUsesLibs, haveUsesLibs)
154 }
155 })
156}
157
158// Test that an unexpected unknown build path causes immediate error.
159func TestCLCUnknownBuildPath(t *testing.T) {
160 ctx := testContext()
Ulya Trafimovich8cbc5d22020-11-03 15:15:46 +0000161 m := make(ClassLoaderContextMap)
162 err := m.addContext(ctx, AnySdkVersion, "a", nil, nil, true, nil)
163 checkError(t, err, "unknown build path to <uses-library> \"a\"")
Ulya Trafimovich69612672020-10-20 17:41:54 +0100164}
165
166// Test that an unexpected unknown install path causes immediate error.
167func TestCLCUnknownInstallPath(t *testing.T) {
168 ctx := testContext()
Ulya Trafimovich8cbc5d22020-11-03 15:15:46 +0000169 m := make(ClassLoaderContextMap)
170 err := m.addContext(ctx, AnySdkVersion, "a", buildPath(ctx, "a"), nil, true, nil)
171 checkError(t, err, "unknown install path to <uses-library> \"a\"")
Ulya Trafimovich69612672020-10-20 17:41:54 +0100172}
173
174func TestCLCMaybeAdd(t *testing.T) {
175 ctx := testContext()
176
Ulya Trafimovich8cbc5d22020-11-03 15:15:46 +0000177 m := make(ClassLoaderContextMap)
Ulya Trafimovich69612672020-10-20 17:41:54 +0100178 a := "a"
Ulya Trafimovich8cbc5d22020-11-03 15:15:46 +0000179 m.MaybeAddContext(ctx, &a, nil, nil)
Ulya Trafimovich69612672020-10-20 17:41:54 +0100180
Ulya Trafimovich8cbc5d22020-11-03 15:15:46 +0000181 // The library should be added to <uses-library> tags by the manifest_fixer.
182 t.Run("maybe add", func(t *testing.T) {
183 haveUsesLibs := m.UsesLibs()
184 wantUsesLibs := []string{"a"}
185 if !reflect.DeepEqual(wantUsesLibs, haveUsesLibs) {
186 t.Errorf("\nwant uses libs: %s\nhave uses libs: %s", wantUsesLibs, haveUsesLibs)
187 }
188 })
Ulya Trafimovich69612672020-10-20 17:41:54 +0100189
Ulya Trafimovich8cbc5d22020-11-03 15:15:46 +0000190 // But class loader context in such cases should raise an error on validation.
191 t.Run("validate", func(t *testing.T) {
192 _, err := validateClassLoaderContext(m)
193 checkError(t, err, "invalid path for <uses-library> \"a\"")
194 })
Ulya Trafimovich69612672020-10-20 17:41:54 +0100195}
196
Ulya Trafimovich5e13a732020-11-03 15:33:03 +0000197// An attempt to add conditional nested subcontext should fail.
198func TestCLCNestedConditional(t *testing.T) {
199 ctx := testContext()
200 m1 := make(ClassLoaderContextMap)
201 m1.AddContextForSdk(ctx, 42, "a", buildPath(ctx, "a"), installPath(ctx, "a"), nil)
202 m := make(ClassLoaderContextMap)
203 err := m.addContext(ctx, AnySdkVersion, "b", buildPath(ctx, "b"), installPath(ctx, "b"), true, m1)
204 checkError(t, err, "nested class loader context shouldn't have conditional part")
205}
206
Ulya Trafimovich69612672020-10-20 17:41:54 +0100207func checkError(t *testing.T, have error, want string) {
208 if have == nil {
209 t.Errorf("\nwant error: '%s'\nhave: none", want)
210 } else if msg := have.Error(); !strings.HasPrefix(msg, want) {
211 t.Errorf("\nwant error: '%s'\nhave error: '%s'\n", want, msg)
212 }
213}
214
215func testContext() android.ModuleInstallPathContext {
216 config := android.TestConfig("out", nil, "", nil)
217 return android.ModuleInstallPathContextForTesting(config)
218}
219
220func buildPath(ctx android.PathContext, lib string) android.Path {
221 return android.PathForOutput(ctx, lib+".jar")
222}
223
224func installPath(ctx android.ModuleInstallPathContext, lib string) android.InstallPath {
225 return android.PathForModuleInstall(ctx, lib+".jar")
226}