blob: 378ce1f7b9a1b112c67a131284c018e6e52532d5 [file] [log] [blame]
Paul Duffin82d90432019-11-30 09:24:33 +00001// Copyright 2019 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 sdk
16
17import (
Paul Duffinc3c5d5e2019-11-29 20:45:22 +000018 "fmt"
Paul Duffin82d90432019-11-30 09:24:33 +000019 "io/ioutil"
20 "os"
Paul Duffinc3c5d5e2019-11-29 20:45:22 +000021 "path/filepath"
Paul Duffinb07fa512020-03-10 22:17:04 +000022 "reflect"
Paul Duffin82d90432019-11-30 09:24:33 +000023 "strings"
24 "testing"
25
26 "android/soong/android"
27 "android/soong/apex"
28 "android/soong/cc"
29 "android/soong/java"
30)
31
Paul Duffinc3c5d5e2019-11-29 20:45:22 +000032func testSdkContext(bp string, fs map[string][]byte) (*android.TestContext, android.Config) {
Colin Cross98be1bb2019-12-13 20:41:13 -080033 bp = bp + `
34 apex_key {
35 name: "myapex.key",
36 public_key: "myapex.avbpubkey",
37 private_key: "myapex.pem",
38 }
39
40 android_app_certificate {
41 name: "myapex.cert",
42 certificate: "myapex",
43 }
Paul Duffina04c1072020-03-02 10:16:35 +000044 ` + cc.GatherRequiredDepsForTest(android.Android, android.Windows)
Colin Cross98be1bb2019-12-13 20:41:13 -080045
46 mockFS := map[string][]byte{
Martin Stjernholmcc776012020-07-07 03:22:21 +010047 "build/make/target/product/security": nil,
48 "apex_manifest.json": nil,
49 "system/sepolicy/apex/myapex-file_contexts": nil,
50 "system/sepolicy/apex/myapex2-file_contexts": nil,
51 "system/sepolicy/apex/mysdkapex-file_contexts": nil,
52 "myapex.avbpubkey": nil,
53 "myapex.pem": nil,
54 "myapex.x509.pem": nil,
55 "myapex.pk8": nil,
Colin Cross98be1bb2019-12-13 20:41:13 -080056 }
57
Colin Crossf28329d2020-02-15 11:00:10 -080058 cc.GatherRequiredFilesForTest(mockFS)
59
Colin Cross98be1bb2019-12-13 20:41:13 -080060 for k, v := range fs {
61 mockFS[k] = v
62 }
63
64 config := android.TestArchConfig(buildDir, nil, bp, mockFS)
65
Paul Duffin08798aa2020-02-27 13:12:46 +000066 // Add windows as a default disable OS to test behavior when some OS variants
67 // are disabled.
68 config.Targets[android.Windows] = []android.Target{
69 {android.Windows, android.Arch{ArchType: android.X86_64}, android.NativeBridgeDisabled, "", ""},
70 }
71
Paul Duffin82d90432019-11-30 09:24:33 +000072 ctx := android.NewTestArchContext()
73
Paul Duffin8c3fec42020-03-04 20:15:08 +000074 // Enable androidmk support.
75 // * Register the singleton
76 // * Configure that we are inside make
77 // * Add CommonOS to ensure that androidmk processing works.
78 android.RegisterAndroidMkBuildComponents(ctx)
79 android.SetInMakeForTests(config)
80 config.Targets[android.CommonOS] = []android.Target{
81 {android.CommonOS, android.Arch{ArchType: android.Common}, android.NativeBridgeDisabled, "", ""},
82 }
83
Paul Duffin82d90432019-11-30 09:24:33 +000084 // from android package
Paul Duffinc1327422020-01-14 12:15:29 +000085 android.RegisterPackageBuildComponents(ctx)
Paul Duffin593b3c92019-12-05 14:31:48 +000086 ctx.PreArchMutators(android.RegisterVisibilityRuleChecker)
Paul Duffin82d90432019-11-30 09:24:33 +000087 ctx.PreArchMutators(android.RegisterDefaultsPreArchMutators)
Paul Duffin44f1d842020-06-26 20:17:02 +010088 ctx.PreArchMutators(android.RegisterComponentsMutator)
Paul Duffin593b3c92019-12-05 14:31:48 +000089 ctx.PreArchMutators(android.RegisterVisibilityRuleGatherer)
90 ctx.PostDepsMutators(android.RegisterVisibilityRuleEnforcer)
91
Paul Duffin82d90432019-11-30 09:24:33 +000092 // from java package
Paul Duffinf9b1da02019-12-18 19:51:55 +000093 java.RegisterJavaBuildComponents(ctx)
94 java.RegisterAppBuildComponents(ctx)
Paul Duffindd46f712020-02-10 13:37:10 +000095 java.RegisterSdkLibraryBuildComponents(ctx)
Paul Duffin884363e2019-12-19 10:21:09 +000096 java.RegisterStubsBuildComponents(ctx)
Paul Duffin7b81f5e2020-01-13 21:03:22 +000097 java.RegisterSystemModulesBuildComponents(ctx)
Paul Duffin82d90432019-11-30 09:24:33 +000098
99 // from cc package
Paul Duffin77980a82019-12-19 16:01:36 +0000100 cc.RegisterRequiredBuildComponentsForTest(ctx)
Paul Duffin82d90432019-11-30 09:24:33 +0000101
102 // from apex package
103 ctx.RegisterModuleType("apex", apex.BundleFactory)
104 ctx.RegisterModuleType("apex_key", apex.ApexKeyFactory)
105 ctx.PostDepsMutators(apex.RegisterPostDepsMutators)
106
107 // from this package
Paul Duffin8150da62019-12-16 17:21:27 +0000108 ctx.RegisterModuleType("sdk", SdkModuleFactory)
Paul Duffin82d90432019-11-30 09:24:33 +0000109 ctx.RegisterModuleType("sdk_snapshot", SnapshotModuleFactory)
Paul Duffin8150da62019-12-16 17:21:27 +0000110 ctx.RegisterModuleType("module_exports", ModuleExportsFactory)
111 ctx.RegisterModuleType("module_exports_snapshot", ModuleExportsSnapshotsFactory)
Paul Duffin82d90432019-11-30 09:24:33 +0000112 ctx.PreDepsMutators(RegisterPreDepsMutators)
113 ctx.PostDepsMutators(RegisterPostDepsMutators)
114
Colin Cross98be1bb2019-12-13 20:41:13 -0800115 ctx.Register(config)
Paul Duffin82d90432019-11-30 09:24:33 +0000116
117 return ctx, config
118}
119
Paul Duffinc3c5d5e2019-11-29 20:45:22 +0000120func testSdkWithFs(t *testing.T, bp string, fs map[string][]byte) *testSdkResult {
121 t.Helper()
122 ctx, config := testSdkContext(bp, fs)
Paul Duffin593b3c92019-12-05 14:31:48 +0000123 _, errs := ctx.ParseBlueprintsFiles(".")
Paul Duffin82d90432019-11-30 09:24:33 +0000124 android.FailIfErrored(t, errs)
125 _, errs = ctx.PrepareBuildActions(config)
126 android.FailIfErrored(t, errs)
Paul Duffinc3c5d5e2019-11-29 20:45:22 +0000127 return &testSdkResult{
128 TestHelper: TestHelper{t: t},
129 ctx: ctx,
130 config: config,
131 }
Paul Duffin82d90432019-11-30 09:24:33 +0000132}
133
134func testSdkError(t *testing.T, pattern, bp string) {
135 t.Helper()
Paul Duffinc3c5d5e2019-11-29 20:45:22 +0000136 ctx, config := testSdkContext(bp, nil)
Paul Duffin82d90432019-11-30 09:24:33 +0000137 _, errs := ctx.ParseFileList(".", []string{"Android.bp"})
138 if len(errs) > 0 {
139 android.FailIfNoMatchingErrors(t, pattern, errs)
140 return
141 }
142 _, errs = ctx.PrepareBuildActions(config)
143 if len(errs) > 0 {
144 android.FailIfNoMatchingErrors(t, pattern, errs)
145 return
146 }
147
148 t.Fatalf("missing expected error %q (0 errors are returned)", pattern)
149}
150
151func ensureListContains(t *testing.T, result []string, expected string) {
152 t.Helper()
153 if !android.InList(expected, result) {
154 t.Errorf("%q is not found in %v", expected, result)
155 }
156}
157
158func pathsToStrings(paths android.Paths) []string {
159 var ret []string
160 for _, p := range paths {
161 ret = append(ret, p.String())
162 }
163 return ret
164}
165
Paul Duffinc3c5d5e2019-11-29 20:45:22 +0000166// Provides general test support.
167type TestHelper struct {
168 t *testing.T
169}
170
171func (h *TestHelper) AssertStringEquals(message string, expected string, actual string) {
172 h.t.Helper()
173 if actual != expected {
174 h.t.Errorf("%s: expected %s, actual %s", message, expected, actual)
Paul Duffin82d90432019-11-30 09:24:33 +0000175 }
176}
177
Paul Duffin4b8b7932020-05-06 12:35:38 +0100178func (h *TestHelper) AssertErrorMessageEquals(message string, expected string, actual error) {
179 h.t.Helper()
180 if actual == nil {
181 h.t.Errorf("Expected error but was nil")
182 } else if actual.Error() != expected {
183 h.t.Errorf("%s: expected %s, actual %s", message, expected, actual.Error())
184 }
185}
186
Paul Duffinc3c5d5e2019-11-29 20:45:22 +0000187func (h *TestHelper) AssertTrimmedStringEquals(message string, expected string, actual string) {
188 h.t.Helper()
189 h.AssertStringEquals(message, strings.TrimSpace(expected), strings.TrimSpace(actual))
190}
191
Paul Duffinb07fa512020-03-10 22:17:04 +0000192func (h *TestHelper) AssertDeepEquals(message string, expected interface{}, actual interface{}) {
193 h.t.Helper()
194 if !reflect.DeepEqual(actual, expected) {
195 h.t.Errorf("%s: expected %#v, actual %#v", message, expected, actual)
196 }
197}
198
Paul Duffinc3c5d5e2019-11-29 20:45:22 +0000199// Encapsulates result of processing an SDK definition. Provides support for
200// checking the state of the build structures.
201type testSdkResult struct {
202 TestHelper
203 ctx *android.TestContext
204 config android.Config
205}
206
207// Analyse the sdk build rules to extract information about what it is doing.
208
209// e.g. find the src/dest pairs from each cp command, the various zip files
210// generated, etc.
211func (r *testSdkResult) getSdkSnapshotBuildInfo(sdk *sdk) *snapshotBuildInfo {
Paul Duffin11108272020-05-11 22:59:25 +0100212 androidBpContents := sdk.GetAndroidBpContentsForTests()
Paul Duffinc3c5d5e2019-11-29 20:45:22 +0000213
214 info := &snapshotBuildInfo{
215 r: r,
216 androidBpContents: androidBpContents,
217 }
218
219 buildParams := sdk.BuildParamsForTests()
220 copyRules := &strings.Builder{}
Nicolas Geoffray1228e9c2020-02-27 13:45:35 +0000221 otherCopyRules := &strings.Builder{}
Paul Duffine1ddcc92020-03-03 16:01:26 +0000222 snapshotDirPrefix := sdk.builderForTests.snapshotDir.String() + "/"
Paul Duffinc3c5d5e2019-11-29 20:45:22 +0000223 for _, bp := range buildParams {
224 switch bp.Rule.String() {
225 case android.Cp.String():
Paul Duffine1ddcc92020-03-03 16:01:26 +0000226 output := bp.Output
Nicolas Geoffray1228e9c2020-02-27 13:45:35 +0000227 // Get destination relative to the snapshot root
228 dest := output.Rel()
229 src := android.NormalizePathForTesting(bp.Input)
230 // We differentiate between copy rules for the snapshot, and copy rules for the install file.
Paul Duffine1ddcc92020-03-03 16:01:26 +0000231 if strings.HasPrefix(output.String(), snapshotDirPrefix) {
232 // Get source relative to build directory.
Paul Duffine1ddcc92020-03-03 16:01:26 +0000233 _, _ = fmt.Fprintf(copyRules, "%s -> %s\n", src, dest)
234 info.snapshotContents = append(info.snapshotContents, dest)
Nicolas Geoffray1228e9c2020-02-27 13:45:35 +0000235 } else {
236 _, _ = fmt.Fprintf(otherCopyRules, "%s -> %s\n", src, dest)
Paul Duffine1ddcc92020-03-03 16:01:26 +0000237 }
Paul Duffinc3c5d5e2019-11-29 20:45:22 +0000238
239 case repackageZip.String():
240 // Add the destdir to the snapshot contents as that is effectively where
241 // the content of the repackaged zip is copied.
242 dest := bp.Args["destdir"]
243 info.snapshotContents = append(info.snapshotContents, dest)
244
245 case zipFiles.String():
246 // This could be an intermediate zip file and not the actual output zip.
247 // In that case this will be overridden when the rule to merge the zips
248 // is processed.
Paul Duffin9b478b02019-12-10 13:41:51 +0000249 info.outputZip = android.NormalizePathForTesting(bp.Output)
Paul Duffinc3c5d5e2019-11-29 20:45:22 +0000250
251 case mergeZips.String():
252 // Copy the current outputZip to the intermediateZip.
253 info.intermediateZip = info.outputZip
Paul Duffin9b478b02019-12-10 13:41:51 +0000254 mergeInput := android.NormalizePathForTesting(bp.Input)
Paul Duffinc3c5d5e2019-11-29 20:45:22 +0000255 if info.intermediateZip != mergeInput {
256 r.t.Errorf("Expected intermediate zip %s to be an input to merge zips but found %s instead",
257 info.intermediateZip, mergeInput)
258 }
259
260 // Override output zip (which was actually the intermediate zip file) with the actual
261 // output zip.
Paul Duffin9b478b02019-12-10 13:41:51 +0000262 info.outputZip = android.NormalizePathForTesting(bp.Output)
Paul Duffinc3c5d5e2019-11-29 20:45:22 +0000263
264 // Save the zips to be merged into the intermediate zip.
Paul Duffin9b478b02019-12-10 13:41:51 +0000265 info.mergeZips = android.NormalizePathsForTesting(bp.Inputs)
Paul Duffinc3c5d5e2019-11-29 20:45:22 +0000266 }
267 }
268
269 info.copyRules = copyRules.String()
Nicolas Geoffray1228e9c2020-02-27 13:45:35 +0000270 info.otherCopyRules = otherCopyRules.String()
Paul Duffinc3c5d5e2019-11-29 20:45:22 +0000271
272 return info
273}
274
275func (r *testSdkResult) Module(name string, variant string) android.Module {
276 return r.ctx.ModuleForTests(name, variant).Module()
277}
278
279func (r *testSdkResult) ModuleForTests(name string, variant string) android.TestingModule {
280 return r.ctx.ModuleForTests(name, variant)
281}
282
Paul Duffinc3c5d5e2019-11-29 20:45:22 +0000283// Check the snapshot build rules.
284//
285// Takes a list of functions which check different facets of the snapshot build rules.
286// Allows each test to customize what is checked without duplicating lots of code
287// or proliferating check methods of different flavors.
Paul Duffin1356d8c2020-02-25 19:26:33 +0000288func (r *testSdkResult) CheckSnapshot(name string, dir string, checkers ...snapshotBuildInfoChecker) {
Paul Duffinc3c5d5e2019-11-29 20:45:22 +0000289 r.t.Helper()
290
Paul Duffin1356d8c2020-02-25 19:26:33 +0000291 // The sdk CommonOS variant is always responsible for generating the snapshot.
292 variant := android.CommonOS.Name
293
Paul Duffinc3c5d5e2019-11-29 20:45:22 +0000294 sdk := r.Module(name, variant).(*sdk)
295
296 snapshotBuildInfo := r.getSdkSnapshotBuildInfo(sdk)
297
298 // Check state of the snapshot build.
299 for _, checker := range checkers {
300 checker(snapshotBuildInfo)
301 }
302
303 // Make sure that the generated zip file is in the correct place.
304 actual := snapshotBuildInfo.outputZip
Paul Duffin593b3c92019-12-05 14:31:48 +0000305 if dir != "" {
306 dir = filepath.Clean(dir) + "/"
307 }
Paul Duffinc3c5d5e2019-11-29 20:45:22 +0000308 r.AssertStringEquals("Snapshot zip file in wrong place",
Paul Duffin593b3c92019-12-05 14:31:48 +0000309 fmt.Sprintf(".intermediates/%s%s/%s/%s-current.zip", dir, name, variant, name), actual)
Paul Duffinc3c5d5e2019-11-29 20:45:22 +0000310
311 // Populate a mock filesystem with the files that would have been copied by
312 // the rules.
313 fs := make(map[string][]byte)
314 for _, dest := range snapshotBuildInfo.snapshotContents {
315 fs[dest] = nil
316 }
317
318 // Process the generated bp file to make sure it is valid.
319 testSdkWithFs(r.t, snapshotBuildInfo.androidBpContents, fs)
320}
321
322type snapshotBuildInfoChecker func(info *snapshotBuildInfo)
323
324// Check that the snapshot's generated Android.bp is correct.
325//
326// Both the expected and actual string are both trimmed before comparing.
327func checkAndroidBpContents(expected string) snapshotBuildInfoChecker {
328 return func(info *snapshotBuildInfo) {
329 info.r.t.Helper()
330 info.r.AssertTrimmedStringEquals("Android.bp contents do not match", expected, info.androidBpContents)
331 }
332}
333
334// Check that the snapshot's copy rules are correct.
335//
336// The copy rules are formatted as <src> -> <dest>, one per line and then compared
337// to the supplied expected string. Both the expected and actual string are trimmed
338// before comparing.
339func checkAllCopyRules(expected string) snapshotBuildInfoChecker {
340 return func(info *snapshotBuildInfo) {
341 info.r.t.Helper()
342 info.r.AssertTrimmedStringEquals("Incorrect copy rules", expected, info.copyRules)
343 }
344}
345
Nicolas Geoffray1228e9c2020-02-27 13:45:35 +0000346func checkAllOtherCopyRules(expected string) snapshotBuildInfoChecker {
347 return func(info *snapshotBuildInfo) {
348 info.r.t.Helper()
349 info.r.AssertTrimmedStringEquals("Incorrect copy rules", expected, info.otherCopyRules)
350 }
351}
352
Paul Duffin3d1248c2020-04-09 00:10:17 +0100353// Check that the specified paths match the list of zips to merge with the intermediate zip.
354func checkMergeZips(expected ...string) snapshotBuildInfoChecker {
Paul Duffinc3c5d5e2019-11-29 20:45:22 +0000355 return func(info *snapshotBuildInfo) {
356 info.r.t.Helper()
357 if info.intermediateZip == "" {
358 info.r.t.Errorf("No intermediate zip file was created")
359 }
Paul Duffin3d1248c2020-04-09 00:10:17 +0100360
361 info.r.AssertDeepEquals("mismatching merge zip files", expected, info.mergeZips)
Paul Duffinc3c5d5e2019-11-29 20:45:22 +0000362 }
363}
364
365// Encapsulates information about the snapshot build structure in order to insulate tests from
366// knowing too much about internal structures.
367//
368// All source/input paths are relative either the build directory. All dest/output paths are
369// relative to the snapshot root directory.
370type snapshotBuildInfo struct {
371 r *testSdkResult
372
373 // The contents of the generated Android.bp file
374 androidBpContents string
375
376 // The paths, relative to the snapshot root, of all files and directories copied into the
377 // snapshot.
378 snapshotContents []string
379
Nicolas Geoffray1228e9c2020-02-27 13:45:35 +0000380 // A formatted representation of the src/dest pairs for a snapshot, one pair per line,
381 // of the format src -> dest
Paul Duffinc3c5d5e2019-11-29 20:45:22 +0000382 copyRules string
383
Nicolas Geoffray1228e9c2020-02-27 13:45:35 +0000384 // A formatted representation of the src/dest pairs for files not in a snapshot, one pair
385 // per line, of the format src -> dest
386 otherCopyRules string
387
Paul Duffinc3c5d5e2019-11-29 20:45:22 +0000388 // The path to the intermediate zip, which is a zip created from the source files copied
389 // into the snapshot directory and which will be merged with other zips to form the final output.
390 // Is am empty string if there is no intermediate zip because there are no zips to merge in.
391 intermediateZip string
392
393 // The paths to the zips to merge into the output zip, does not include the intermediate
394 // zip.
395 mergeZips []string
396
397 // The final output zip.
398 outputZip string
399}
400
Paul Duffin82d90432019-11-30 09:24:33 +0000401var buildDir string
402
403func setUp() {
404 var err error
405 buildDir, err = ioutil.TempDir("", "soong_sdk_test")
406 if err != nil {
407 panic(err)
408 }
409}
410
411func tearDown() {
412 _ = os.RemoveAll(buildDir)
413}
414
415func runTestWithBuildDir(m *testing.M) {
416 run := func() int {
417 setUp()
418 defer tearDown()
419
420 return m.Run()
421 }
422
423 os.Exit(run())
424}