blob: f5e40466aed5b0786eb58f0cc8db9c8c677af07a [file] [log] [blame]
Sasha Smundak7a894a62020-05-06 21:23:08 -07001// 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 main
16
17import (
Colin Crossffbcd1d2021-11-12 12:19:42 -080018 "bytes"
Sasha Smundak7a894a62020-05-06 21:23:08 -070019 "fmt"
Sasha Smundak7a894a62020-05-06 21:23:08 -070020 "reflect"
21 "testing"
22
Dan Willemsen4591b642021-05-24 14:24:12 -070023 "google.golang.org/protobuf/encoding/prototext"
Jaewoong Jung11c1e0f2020-06-29 19:18:44 -070024
Sasha Smundak7a894a62020-05-06 21:23:08 -070025 bp "android/soong/cmd/extract_apks/bundle_proto"
26 "android/soong/third_party/zip"
27)
28
Sasha Smundak827c55f2020-05-20 13:10:59 -070029type testConfigDesc struct {
Sasha Smundak7a894a62020-05-06 21:23:08 -070030 name string
31 targetConfig TargetConfig
32 expected SelectionResult
33}
34
Sasha Smundak827c55f2020-05-20 13:10:59 -070035type testDesc struct {
Sasha Smundak7a894a62020-05-06 21:23:08 -070036 protoText string
Sasha Smundak827c55f2020-05-20 13:10:59 -070037 configs []testConfigDesc
Sasha Smundak7a894a62020-05-06 21:23:08 -070038}
39
Jaewoong Jungfa00c062020-05-14 14:15:24 -070040func TestSelectApks_ApkSet(t *testing.T) {
Sasha Smundak827c55f2020-05-20 13:10:59 -070041 testCases := []testDesc{
Sasha Smundak7a894a62020-05-06 21:23:08 -070042 {
43 protoText: `
44variant {
45 targeting {
Jaewoong Jungfa00c062020-05-14 14:15:24 -070046 sdk_version_targeting {
Sasha Smundak7a894a62020-05-06 21:23:08 -070047 value { min { value: 29 } } } }
48 apk_set {
Jaewoong Jungfa00c062020-05-14 14:15:24 -070049 module_metadata {
Sasha Smundak7a894a62020-05-06 21:23:08 -070050 name: "base" targeting {} delivery_type: INSTALL_TIME }
51 apk_description {
52 targeting {
Jaewoong Jungfa00c062020-05-14 14:15:24 -070053 screen_density_targeting {
Sasha Smundak7a894a62020-05-06 21:23:08 -070054 value { density_alias: LDPI } }
55 sdk_version_targeting {
56 value { min { value: 21 } } } }
57 path: "splits/base-ldpi.apk"
58 split_apk_metadata { split_id: "config.ldpi" } }
59 apk_description {
60 targeting {
61 screen_density_targeting {
62 value { density_alias: MDPI } }
63 sdk_version_targeting {
64 value { min { value: 21 } } } }
65 path: "splits/base-mdpi.apk"
66 split_apk_metadata { split_id: "config.mdpi" } }
67 apk_description {
68 targeting {
69 sdk_version_targeting {
70 value { min { value: 21 } } } }
71 path: "splits/base-master.apk"
72 split_apk_metadata { is_master_split: true } }
73 apk_description {
74 targeting {
75 abi_targeting {
Jaewoong Jungfa00c062020-05-14 14:15:24 -070076 value { alias: ARMEABI_V7A }
77 alternatives { alias: ARM64_V8A }
78 alternatives { alias: X86 }
79 alternatives { alias: X86_64 } }
Sasha Smundak7a894a62020-05-06 21:23:08 -070080 sdk_version_targeting {
81 value { min { value: 21 } } } }
82 path: "splits/base-armeabi_v7a.apk"
83 split_apk_metadata { split_id: "config.armeabi_v7a" } }
84 apk_description {
85 targeting {
86 abi_targeting {
Jaewoong Jungfa00c062020-05-14 14:15:24 -070087 value { alias: ARM64_V8A }
88 alternatives { alias: ARMEABI_V7A }
89 alternatives { alias: X86 }
90 alternatives { alias: X86_64 } }
Sasha Smundak7a894a62020-05-06 21:23:08 -070091 sdk_version_targeting {
92 value { min { value: 21 } } } }
93 path: "splits/base-arm64_v8a.apk"
94 split_apk_metadata { split_id: "config.arm64_v8a" } }
95 apk_description {
96 targeting {
97 abi_targeting {
Jaewoong Jungfa00c062020-05-14 14:15:24 -070098 value { alias: X86 }
99 alternatives { alias: ARMEABI_V7A }
100 alternatives { alias: ARM64_V8A }
101 alternatives { alias: X86_64 } }
Sasha Smundak7a894a62020-05-06 21:23:08 -0700102 sdk_version_targeting {
103 value { min { value: 21 } } } }
104 path: "splits/base-x86.apk"
105 split_apk_metadata { split_id: "config.x86" } }
106 apk_description {
107 targeting {
108 abi_targeting {
Jaewoong Jungfa00c062020-05-14 14:15:24 -0700109 value { alias: X86_64 }
110 alternatives { alias: ARMEABI_V7A }
111 alternatives { alias: ARM64_V8A }
112 alternatives { alias: X86 } }
Sasha Smundak7a894a62020-05-06 21:23:08 -0700113 sdk_version_targeting {
114 value { min { value: 21 } } } }
115 path: "splits/base-x86_64.apk"
116 split_apk_metadata { split_id: "config.x86_64" } } }
117}
118bundletool {
119 version: "0.10.3" }
120
121`,
Sasha Smundak827c55f2020-05-20 13:10:59 -0700122 configs: []testConfigDesc{
Sasha Smundak7a894a62020-05-06 21:23:08 -0700123 {
124 name: "one",
125 targetConfig: TargetConfig{
126 sdkVersion: 29,
127 screenDpi: map[bp.ScreenDensity_DensityAlias]bool{
128 bp.ScreenDensity_DENSITY_UNSPECIFIED: true,
129 },
Jaewoong Jungfa00c062020-05-14 14:15:24 -0700130 abis: map[bp.Abi_AbiAlias]int{
131 bp.Abi_ARMEABI_V7A: 0,
132 bp.Abi_ARM64_V8A: 1,
Sasha Smundak7a894a62020-05-06 21:23:08 -0700133 },
134 },
135 expected: SelectionResult{
136 "base",
137 []string{
138 "splits/base-ldpi.apk",
139 "splits/base-mdpi.apk",
140 "splits/base-master.apk",
141 "splits/base-armeabi_v7a.apk",
Sasha Smundak7a894a62020-05-06 21:23:08 -0700142 },
143 },
144 },
145 {
146 name: "two",
147 targetConfig: TargetConfig{
148 sdkVersion: 29,
149 screenDpi: map[bp.ScreenDensity_DensityAlias]bool{
150 bp.ScreenDensity_LDPI: true,
151 },
Jaewoong Jungfa00c062020-05-14 14:15:24 -0700152 abis: map[bp.Abi_AbiAlias]int{},
Sasha Smundak7a894a62020-05-06 21:23:08 -0700153 },
154 expected: SelectionResult{
155 "base",
156 []string{
157 "splits/base-ldpi.apk",
158 "splits/base-master.apk",
159 },
160 },
161 },
162 {
163 name: "three",
164 targetConfig: TargetConfig{
165 sdkVersion: 20,
166 screenDpi: map[bp.ScreenDensity_DensityAlias]bool{
167 bp.ScreenDensity_LDPI: true,
168 },
Jaewoong Jungfa00c062020-05-14 14:15:24 -0700169 abis: map[bp.Abi_AbiAlias]int{},
Sasha Smundak7a894a62020-05-06 21:23:08 -0700170 },
171 expected: SelectionResult{
172 "",
173 nil,
174 },
175 },
Jaewoong Jungfa00c062020-05-14 14:15:24 -0700176 {
177 name: "four",
178 targetConfig: TargetConfig{
179 sdkVersion: 29,
180 screenDpi: map[bp.ScreenDensity_DensityAlias]bool{
181 bp.ScreenDensity_MDPI: true,
182 },
183 abis: map[bp.Abi_AbiAlias]int{
184 bp.Abi_ARM64_V8A: 0,
185 bp.Abi_ARMEABI_V7A: 1,
186 },
187 },
188 expected: SelectionResult{
189 "base",
190 []string{
191 "splits/base-mdpi.apk",
192 "splits/base-master.apk",
193 "splits/base-arm64_v8a.apk",
194 },
195 },
196 },
Sasha Smundak7a894a62020-05-06 21:23:08 -0700197 },
198 },
199 {
200 protoText: `
201variant {
202 targeting {
Jaewoong Jungfa00c062020-05-14 14:15:24 -0700203 sdk_version_targeting {
Sasha Smundak7a894a62020-05-06 21:23:08 -0700204 value { min { value: 10000 } } } }
205 apk_set {
Jaewoong Jungfa00c062020-05-14 14:15:24 -0700206 module_metadata {
Sasha Smundak7a894a62020-05-06 21:23:08 -0700207 name: "base" targeting {} delivery_type: INSTALL_TIME }
208 apk_description {
209 targeting {
210 sdk_version_targeting {
211 value { min { value: 21 } } } }
212 path: "splits/base-master.apk"
213 split_apk_metadata { is_master_split: true } } } }`,
Sasha Smundak827c55f2020-05-20 13:10:59 -0700214 configs: []testConfigDesc{
Sasha Smundak7a894a62020-05-06 21:23:08 -0700215 {
216 name: "Prerelease",
217 targetConfig: TargetConfig{
218 sdkVersion: 30,
219 screenDpi: map[bp.ScreenDensity_DensityAlias]bool{},
Jaewoong Jungfa00c062020-05-14 14:15:24 -0700220 abis: map[bp.Abi_AbiAlias]int{},
Sasha Smundak7a894a62020-05-06 21:23:08 -0700221 allowPrereleased: true,
222 },
223 expected: SelectionResult{
224 "base",
225 []string{"splits/base-master.apk"},
226 },
227 },
228 },
229 },
Sasha Smundak827c55f2020-05-20 13:10:59 -0700230 {
231 protoText: `
232variant {
233 targeting {
234 sdk_version_targeting {
235 value { min { value: 29 } } } }
236 apk_set {
237 module_metadata {
238 name: "base" targeting {} delivery_type: INSTALL_TIME }
239 apk_description {
240 targeting {}
241 path: "universal.apk"
242 standalone_apk_metadata { fused_module_name: "base" } } } }`,
243 configs: []testConfigDesc{
244 {
245 name: "Universal",
246 targetConfig: TargetConfig{sdkVersion: 30},
247 expected: SelectionResult{
248 "base",
249 []string{"universal.apk"},
250 },
251 },
252 },
253 },
Sasha Smundak7a894a62020-05-06 21:23:08 -0700254 }
Jaewoong Jungfa00c062020-05-14 14:15:24 -0700255 for _, testCase := range testCases {
256 var toc bp.BuildApksResult
Dan Willemsen4591b642021-05-24 14:24:12 -0700257 if err := prototext.Unmarshal([]byte(testCase.protoText), &toc); err != nil {
Jaewoong Jungfa00c062020-05-14 14:15:24 -0700258 t.Fatal(err)
259 }
260 for _, config := range testCase.configs {
261 actual := selectApks(&toc, config.targetConfig)
262 if !reflect.DeepEqual(config.expected, actual) {
263 t.Errorf("%s: expected %v, got %v", config.name, config.expected, actual)
264 }
265 }
266 }
267}
Sasha Smundak7a894a62020-05-06 21:23:08 -0700268
Jaewoong Jungfa00c062020-05-14 14:15:24 -0700269func TestSelectApks_ApexSet(t *testing.T) {
Sasha Smundak827c55f2020-05-20 13:10:59 -0700270 testCases := []testDesc{
Jaewoong Jungfa00c062020-05-14 14:15:24 -0700271 {
272 protoText: `
273variant {
274 targeting {
275 sdk_version_targeting {
276 value { min { value: 29 } } } }
277 apk_set {
278 module_metadata {
279 name: "base" targeting {} delivery_type: INSTALL_TIME }
280 apk_description {
281 targeting {
282 multi_abi_targeting {
283 value { abi { alias: ARMEABI_V7A } }
284 alternatives { abi { alias: ARM64_V8A } }
285 alternatives { abi { alias: X86 } }
286 alternatives { abi { alias: X86_64 } } }
287 sdk_version_targeting {
288 value { min { value: 21 } } } }
289 path: "standalones/standalone-armeabi_v7a.apex"
290 apex_apk_metadata { } }
291 apk_description {
292 targeting {
293 multi_abi_targeting {
294 value { abi { alias: ARM64_V8A } }
295 alternatives { abi { alias: ARMEABI_V7A } }
296 alternatives { abi { alias: X86 } }
297 alternatives { abi { alias: X86_64 } } }
298 sdk_version_targeting {
299 value { min { value: 21 } } } }
300 path: "standalones/standalone-arm64_v8a.apex"
301 apex_apk_metadata { } }
302 apk_description {
303 targeting {
304 multi_abi_targeting {
305 value { abi { alias: X86 } }
306 alternatives { abi { alias: ARMEABI_V7A } }
307 alternatives { abi { alias: ARM64_V8A } }
308 alternatives { abi { alias: X86_64 } } }
309 sdk_version_targeting {
310 value { min { value: 21 } } } }
311 path: "standalones/standalone-x86.apex"
312 apex_apk_metadata { } }
313 apk_description {
314 targeting {
315 multi_abi_targeting {
316 value { abi { alias: X86_64 } }
317 alternatives { abi { alias: ARMEABI_V7A } }
318 alternatives { abi { alias: ARM64_V8A } }
319 alternatives { abi { alias: X86 } } }
320 sdk_version_targeting {
321 value { min { value: 21 } } } }
322 path: "standalones/standalone-x86_64.apex"
323 apex_apk_metadata { } } }
324}
325bundletool {
326 version: "0.10.3" }
327
328`,
Sasha Smundak827c55f2020-05-20 13:10:59 -0700329 configs: []testConfigDesc{
Jaewoong Jungfa00c062020-05-14 14:15:24 -0700330 {
331 name: "order matches priorities",
332 targetConfig: TargetConfig{
333 sdkVersion: 29,
334 screenDpi: map[bp.ScreenDensity_DensityAlias]bool{
335 bp.ScreenDensity_DENSITY_UNSPECIFIED: true,
336 },
337 abis: map[bp.Abi_AbiAlias]int{
338 bp.Abi_ARM64_V8A: 0,
339 bp.Abi_ARMEABI_V7A: 1,
340 },
341 },
342 expected: SelectionResult{
343 "base",
344 []string{
345 "standalones/standalone-arm64_v8a.apex",
346 },
347 },
348 },
349 {
350 name: "order doesn't match priorities",
351 targetConfig: TargetConfig{
352 sdkVersion: 29,
353 screenDpi: map[bp.ScreenDensity_DensityAlias]bool{
354 bp.ScreenDensity_DENSITY_UNSPECIFIED: true,
355 },
356 abis: map[bp.Abi_AbiAlias]int{
357 bp.Abi_ARMEABI_V7A: 0,
358 bp.Abi_ARM64_V8A: 1,
359 },
360 },
361 expected: SelectionResult{
362 "base",
363 []string{
364 "standalones/standalone-arm64_v8a.apex",
365 },
366 },
367 },
368 {
369 name: "single choice",
370 targetConfig: TargetConfig{
371 sdkVersion: 29,
372 screenDpi: map[bp.ScreenDensity_DensityAlias]bool{
373 bp.ScreenDensity_DENSITY_UNSPECIFIED: true,
374 },
375 abis: map[bp.Abi_AbiAlias]int{
376 bp.Abi_ARMEABI_V7A: 0,
377 },
378 },
379 expected: SelectionResult{
380 "base",
381 []string{
382 "standalones/standalone-armeabi_v7a.apex",
383 },
384 },
385 },
386 {
387 name: "cross platform",
388 targetConfig: TargetConfig{
389 sdkVersion: 29,
390 screenDpi: map[bp.ScreenDensity_DensityAlias]bool{
391 bp.ScreenDensity_DENSITY_UNSPECIFIED: true,
392 },
393 abis: map[bp.Abi_AbiAlias]int{
394 bp.Abi_ARM64_V8A: 0,
395 bp.Abi_MIPS64: 1,
396 bp.Abi_X86: 2,
397 },
398 },
399 expected: SelectionResult{
400 "base",
401 []string{
402 "standalones/standalone-x86.apex",
403 },
404 },
405 },
406 },
407 },
408 }
Sasha Smundak7a894a62020-05-06 21:23:08 -0700409 for _, testCase := range testCases {
410 var toc bp.BuildApksResult
Dan Willemsen4591b642021-05-24 14:24:12 -0700411 if err := prototext.Unmarshal([]byte(testCase.protoText), &toc); err != nil {
Sasha Smundak7a894a62020-05-06 21:23:08 -0700412 t.Fatal(err)
413 }
414 for _, config := range testCase.configs {
415 actual := selectApks(&toc, config.targetConfig)
416 if !reflect.DeepEqual(config.expected, actual) {
417 t.Errorf("%s: expected %v, got %v", config.name, config.expected, actual)
418 }
419 }
420 }
421}
422
423type testZip2ZipWriter struct {
424 entries map[string]string
425}
426
427func (w testZip2ZipWriter) CopyFrom(file *zip.File, out string) error {
428 if x, ok := w.entries[out]; ok {
429 return fmt.Errorf("%s and %s both write to %s", x, file.Name, out)
430 }
431 w.entries[out] = file.Name
432 return nil
433}
434
Jaewoong Jung11c1e0f2020-06-29 19:18:44 -0700435type testCaseWriteApks struct {
Sasha Smundak827c55f2020-05-20 13:10:59 -0700436 name string
437 moduleName string
438 stem string
Jaewoong Jung11c1e0f2020-06-29 19:18:44 -0700439 partition string
Sasha Smundak7a894a62020-05-06 21:23:08 -0700440 // what we write from what
Colin Crossffbcd1d2021-11-12 12:19:42 -0800441 zipEntries map[string]string
442 expectedApkcerts []string
Sasha Smundak827c55f2020-05-20 13:10:59 -0700443}
444
Jaewoong Jung11c1e0f2020-06-29 19:18:44 -0700445func TestWriteApks(t *testing.T) {
446 testCases := []testCaseWriteApks{
Sasha Smundak827c55f2020-05-20 13:10:59 -0700447 {
448 name: "splits",
449 moduleName: "mybase",
450 stem: "Foo",
Jaewoong Jung11c1e0f2020-06-29 19:18:44 -0700451 partition: "system",
Colin Crossffbcd1d2021-11-12 12:19:42 -0800452 zipEntries: map[string]string{
Sasha Smundak827c55f2020-05-20 13:10:59 -0700453 "Foo.apk": "splits/mybase-master.apk",
454 "Foo-xhdpi.apk": "splits/mybase-xhdpi.apk",
455 },
Jaewoong Jung11c1e0f2020-06-29 19:18:44 -0700456 expectedApkcerts: []string{
457 `name="Foo-xhdpi.apk" certificate="PRESIGNED" private_key="" partition="system"`,
458 `name="Foo.apk" certificate="PRESIGNED" private_key="" partition="system"`,
459 },
Sasha Smundak827c55f2020-05-20 13:10:59 -0700460 },
461 {
462 name: "universal",
463 moduleName: "base",
464 stem: "Bar",
Jaewoong Jung11c1e0f2020-06-29 19:18:44 -0700465 partition: "product",
Colin Crossffbcd1d2021-11-12 12:19:42 -0800466 zipEntries: map[string]string{
Sasha Smundak827c55f2020-05-20 13:10:59 -0700467 "Bar.apk": "universal.apk",
468 },
Jaewoong Jung11c1e0f2020-06-29 19:18:44 -0700469 expectedApkcerts: []string{
470 `name="Bar.apk" certificate="PRESIGNED" private_key="" partition="product"`,
471 },
Sasha Smundak827c55f2020-05-20 13:10:59 -0700472 },
Sasha Smundak7a894a62020-05-06 21:23:08 -0700473 }
Sasha Smundak827c55f2020-05-20 13:10:59 -0700474 for _, testCase := range testCases {
Colin Crossffbcd1d2021-11-12 12:19:42 -0800475 t.Run(testCase.name, func(t *testing.T) {
476 testZipBuf := &bytes.Buffer{}
477 testZip := zip.NewWriter(testZipBuf)
478 for _, in := range testCase.zipEntries {
479 f, _ := testZip.Create(in)
480 f.Write([]byte(in))
481 }
482 testZip.Close()
483
484 zipReader, _ := zip.NewReader(bytes.NewReader(testZipBuf.Bytes()), int64(testZipBuf.Len()))
485
486 apkSet := ApkSet{entries: make(map[string]*zip.File)}
487 sel := SelectionResult{moduleName: testCase.moduleName}
488 for _, f := range zipReader.File {
489 apkSet.entries[f.Name] = f
490 sel.entries = append(sel.entries, f.Name)
491 }
492
493 zipWriter := testZip2ZipWriter{make(map[string]string)}
494 outWriter := &bytes.Buffer{}
495 config := TargetConfig{stem: testCase.stem}
496 apkcerts, err := apkSet.writeApks(sel, config, outWriter, zipWriter, testCase.partition)
497 if err != nil {
498 t.Error(err)
499 }
500 expectedZipEntries := make(map[string]string)
501 for k, v := range testCase.zipEntries {
502 if k != testCase.stem+".apk" {
503 expectedZipEntries[k] = v
504 }
505 }
506 if !reflect.DeepEqual(expectedZipEntries, zipWriter.entries) {
507 t.Errorf("expected zip entries %v, got %v", testCase.zipEntries, zipWriter.entries)
508 }
509 if !reflect.DeepEqual(testCase.expectedApkcerts, apkcerts) {
510 t.Errorf("expected apkcerts %v, got %v", testCase.expectedApkcerts, apkcerts)
511 }
512 if g, w := outWriter.String(), testCase.zipEntries[testCase.stem+".apk"]; !reflect.DeepEqual(g, w) {
513 t.Errorf("expected output file contents %q, got %q", testCase.stem+".apk", outWriter.String())
514 }
515 })
Sasha Smundak7a894a62020-05-06 21:23:08 -0700516 }
517}