1// 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 android 16 17import ( 18 "strings" 19 "testing" 20 21 "github.com/google/blueprint" 22 "github.com/google/blueprint/proptools" 23) 24 25// Module to be packaged 26type componentTestModule struct { 27 ModuleBase 28 props struct { 29 Deps []string 30 Skip_install *bool 31 } 32} 33 34// dep tag used in this test. All dependencies are considered as installable. 35type installDepTag struct { 36 blueprint.BaseDependencyTag 37 InstallAlwaysNeededDependencyTag 38} 39 40func componentTestModuleFactory() Module { 41 m := &componentTestModule{} 42 m.AddProperties(&m.props) 43 InitAndroidArchModule(m, HostAndDeviceSupported, MultilibBoth) 44 return m 45} 46 47func (m *componentTestModule) DepsMutator(ctx BottomUpMutatorContext) { 48 ctx.AddDependency(ctx.Module(), installDepTag{}, m.props.Deps...) 49} 50 51func (m *componentTestModule) GenerateAndroidBuildActions(ctx ModuleContext) { 52 builtFile := PathForModuleOut(ctx, m.Name()) 53 dir := ctx.Target().Arch.ArchType.Multilib 54 installDir := PathForModuleInstall(ctx, dir) 55 if proptools.Bool(m.props.Skip_install) { 56 m.SkipInstall() 57 } 58 ctx.InstallFile(installDir, m.Name(), builtFile) 59} 60 61// Module that itself is a package 62type packageTestModule struct { 63 ModuleBase 64 PackagingBase 65 properties struct { 66 Install_deps []string `android:` 67 } 68 entries []string 69} 70 71func packageTestModuleFactory(multiTarget bool, depsCollectFirstTargetOnly bool) Module { 72 module := &packageTestModule{} 73 InitPackageModule(module) 74 module.DepsCollectFirstTargetOnly = depsCollectFirstTargetOnly 75 if multiTarget { 76 InitAndroidMultiTargetsArchModule(module, DeviceSupported, MultilibCommon) 77 } else { 78 InitAndroidArchModule(module, DeviceSupported, MultilibBoth) 79 } 80 module.AddProperties(&module.properties) 81 return module 82} 83 84type packagingDepTag struct { 85 blueprint.BaseDependencyTag 86 PackagingItemAlwaysDepTag 87} 88 89func (m *packageTestModule) DepsMutator(ctx BottomUpMutatorContext) { 90 m.AddDeps(ctx, packagingDepTag{}) 91 ctx.AddDependency(ctx.Module(), installDepTag{}, m.properties.Install_deps...) 92} 93 94func (m *packageTestModule) GenerateAndroidBuildActions(ctx ModuleContext) { 95 zipFile := PathForModuleOut(ctx, "myzip.zip") 96 m.entries = m.CopyDepsToZip(ctx, m.GatherPackagingSpecs(ctx), zipFile) 97} 98 99type testConfig struct { 100 multiTarget bool 101 depsCollectFirstTargetOnly bool 102 debuggable bool 103} 104 105func runPackagingTest(t *testing.T, config testConfig, bp string, expected []string) { 106 t.Helper() 107 108 var archVariant string 109 if config.multiTarget { 110 archVariant = "android_common" 111 } else { 112 archVariant = "android_arm64_armv8-a" 113 } 114 115 moduleFactory := func() Module { 116 return packageTestModuleFactory(config.multiTarget, config.depsCollectFirstTargetOnly) 117 } 118 119 result := GroupFixturePreparers( 120 PrepareForTestWithArchMutator, 121 FixtureRegisterWithContext(func(ctx RegistrationContext) { 122 ctx.RegisterModuleType("component", componentTestModuleFactory) 123 ctx.RegisterModuleType("package_module", moduleFactory) 124 }), 125 FixtureModifyProductVariables(func(variables FixtureProductVariables) { 126 variables.Debuggable = proptools.BoolPtr(config.debuggable) 127 }), 128 FixtureWithRootAndroidBp(bp), 129 ).RunTest(t) 130 131 p := result.Module("package", archVariant).(*packageTestModule) 132 actual := p.entries 133 actual = SortedUniqueStrings(actual) 134 expected = SortedUniqueStrings(expected) 135 AssertDeepEquals(t, "package entries", expected, actual) 136} 137 138func TestPackagingBaseMultiTarget(t *testing.T) { 139 config := testConfig{ 140 multiTarget: true, 141 depsCollectFirstTargetOnly: false, 142 } 143 runPackagingTest(t, config, 144 ` 145 component { 146 name: "foo", 147 } 148 149 package_module { 150 name: "package", 151 deps: ["foo"], 152 } 153 `, []string{"lib64/foo"}) 154 155 runPackagingTest(t, config, 156 ` 157 component { 158 name: "foo", 159 deps: ["bar"], 160 } 161 162 component { 163 name: "bar", 164 } 165 166 package_module { 167 name: "package", 168 deps: ["foo"], 169 } 170 `, []string{"lib64/foo", "lib64/bar"}) 171 172 runPackagingTest(t, config, 173 ` 174 component { 175 name: "foo", 176 deps: ["bar"], 177 } 178 179 component { 180 name: "bar", 181 } 182 183 package_module { 184 name: "package", 185 deps: ["foo"], 186 compile_multilib: "both", 187 } 188 `, []string{"lib32/foo", "lib32/bar", "lib64/foo", "lib64/bar"}) 189 190 runPackagingTest(t, config, 191 ` 192 component { 193 name: "foo", 194 } 195 196 component { 197 name: "bar", 198 compile_multilib: "32", 199 } 200 201 package_module { 202 name: "package", 203 deps: ["foo"], 204 multilib: { 205 lib32: { 206 deps: ["bar"], 207 }, 208 }, 209 compile_multilib: "both", 210 } 211 `, []string{"lib32/foo", "lib32/bar", "lib64/foo"}) 212 213 runPackagingTest(t, config, 214 ` 215 component { 216 name: "foo", 217 } 218 219 component { 220 name: "bar", 221 } 222 223 package_module { 224 name: "package", 225 deps: ["foo"], 226 multilib: { 227 first: { 228 deps: ["bar"], 229 }, 230 }, 231 compile_multilib: "both", 232 } 233 `, []string{"lib32/foo", "lib64/foo", "lib64/bar"}) 234 235 runPackagingTest(t, config, 236 ` 237 component { 238 name: "foo", 239 } 240 241 component { 242 name: "bar", 243 } 244 245 component { 246 name: "baz", 247 } 248 249 package_module { 250 name: "package", 251 deps: ["foo"], 252 arch: { 253 arm64: { 254 deps: ["bar"], 255 }, 256 x86_64: { 257 deps: ["baz"], 258 }, 259 }, 260 compile_multilib: "both", 261 } 262 `, []string{"lib32/foo", "lib64/foo", "lib64/bar"}) 263} 264 265func TestPackagingBaseSingleTarget(t *testing.T) { 266 config := testConfig{ 267 multiTarget: false, 268 depsCollectFirstTargetOnly: false, 269 } 270 runPackagingTest(t, config, 271 ` 272 component { 273 name: "foo", 274 } 275 276 package_module { 277 name: "package", 278 deps: ["foo"], 279 } 280 `, []string{"lib64/foo"}) 281 282 runPackagingTest(t, config, 283 ` 284 component { 285 name: "foo", 286 deps: ["bar"], 287 } 288 289 component { 290 name: "bar", 291 } 292 293 package_module { 294 name: "package", 295 deps: ["foo"], 296 } 297 `, []string{"lib64/foo", "lib64/bar"}) 298 299 runPackagingTest(t, config, 300 ` 301 component { 302 name: "foo", 303 } 304 305 component { 306 name: "bar", 307 compile_multilib: "32", 308 } 309 310 package_module { 311 name: "package", 312 deps: ["foo"], 313 multilib: { 314 lib32: { 315 deps: ["bar"], 316 }, 317 }, 318 } 319 `, []string{"lib64/foo"}) 320 321 runPackagingTest(t, config, 322 ` 323 component { 324 name: "foo", 325 } 326 327 component { 328 name: "bar", 329 } 330 331 package_module { 332 name: "package", 333 deps: ["foo"], 334 multilib: { 335 lib64: { 336 deps: ["bar"], 337 }, 338 }, 339 } 340 `, []string{"lib64/foo", "lib64/bar"}) 341 342 runPackagingTest(t, config, 343 ` 344 component { 345 name: "foo", 346 } 347 348 component { 349 name: "bar", 350 } 351 352 component { 353 name: "baz", 354 } 355 356 package_module { 357 name: "package", 358 deps: ["foo"], 359 arch: { 360 arm64: { 361 deps: ["bar"], 362 }, 363 x86_64: { 364 deps: ["baz"], 365 }, 366 }, 367 } 368 `, []string{"lib64/foo", "lib64/bar"}) 369 370 runPackagingTest(t, config, 371 ` 372 component { 373 name: "foo", 374 } 375 376 component { 377 name: "bar", 378 } 379 380 package_module { 381 name: "package", 382 deps: ["foo"], 383 install_deps: ["bar"], 384 } 385 `, []string{"lib64/foo"}) 386} 387 388func TestPackagingWithSkipInstallDeps(t *testing.T) { 389 // package -[dep]-> foo -[dep]-> bar -[dep]-> baz 390 // Packaging should continue transitively through modules that are not installed. 391 config := testConfig{ 392 multiTarget: false, 393 depsCollectFirstTargetOnly: false, 394 } 395 runPackagingTest(t, config, 396 ` 397 component { 398 name: "foo", 399 deps: ["bar"], 400 } 401 402 component { 403 name: "bar", 404 deps: ["baz"], 405 skip_install: true, 406 } 407 408 component { 409 name: "baz", 410 } 411 412 package_module { 413 name: "package", 414 deps: ["foo"], 415 } 416 `, []string{"lib64/foo", "lib64/bar", "lib64/baz"}) 417} 418 419func TestPackagingWithDepsCollectFirstTargetOnly(t *testing.T) { 420 config := testConfig{ 421 multiTarget: true, 422 depsCollectFirstTargetOnly: true, 423 } 424 runPackagingTest(t, config, 425 ` 426 component { 427 name: "foo", 428 } 429 430 package_module { 431 name: "package", 432 deps: ["foo"], 433 } 434 `, []string{"lib64/foo"}) 435 436 runPackagingTest(t, config, 437 ` 438 component { 439 name: "foo", 440 deps: ["bar"], 441 } 442 443 component { 444 name: "bar", 445 } 446 447 package_module { 448 name: "package", 449 deps: ["foo"], 450 } 451 `, []string{"lib64/foo", "lib64/bar"}) 452 453 runPackagingTest(t, config, 454 ` 455 component { 456 name: "foo", 457 deps: ["bar"], 458 } 459 460 component { 461 name: "bar", 462 } 463 464 package_module { 465 name: "package", 466 deps: ["foo"], 467 compile_multilib: "both", 468 } 469 `, []string{"lib64/foo", "lib64/bar"}) 470 471 runPackagingTest(t, config, 472 ` 473 component { 474 name: "foo", 475 } 476 477 component { 478 name: "bar", 479 compile_multilib: "32", 480 } 481 482 package_module { 483 name: "package", 484 deps: ["foo"], 485 multilib: { 486 lib32: { 487 deps: ["bar"], 488 }, 489 }, 490 compile_multilib: "both", 491 } 492 `, []string{"lib32/bar", "lib64/foo"}) 493 494 runPackagingTest(t, config, 495 ` 496 component { 497 name: "foo", 498 } 499 500 component { 501 name: "bar", 502 } 503 504 package_module { 505 name: "package", 506 deps: ["foo"], 507 multilib: { 508 both: { 509 deps: ["bar"], 510 }, 511 }, 512 compile_multilib: "both", 513 } 514 `, []string{"lib64/foo", "lib32/bar", "lib64/bar"}) 515 516 runPackagingTest(t, config, 517 ` 518 component { 519 name: "foo", 520 } 521 522 component { 523 name: "bar", 524 } 525 526 component { 527 name: "baz", 528 } 529 530 package_module { 531 name: "package", 532 deps: ["foo"], 533 arch: { 534 arm64: { 535 deps: ["bar"], 536 }, 537 x86_64: { 538 deps: ["baz"], 539 }, 540 }, 541 compile_multilib: "both", 542 } 543 `, []string{"lib64/foo", "lib64/bar"}) 544} 545 546func TestDebuggableDeps(t *testing.T) { 547 bp := ` 548 component { 549 name: "foo", 550 } 551 552 component { 553 name: "bar", 554 deps: ["baz"], 555 } 556 557 component { 558 name: "baz", 559 } 560 561 package_module { 562 name: "package", 563 deps: ["foo"] + select(product_variable("debuggable"), { 564 true: ["bar"], 565 default: [], 566 }), 567 }` 568 testcases := []struct { 569 debuggable bool 570 expected []string 571 }{ 572 { 573 debuggable: true, 574 expected: []string{"lib64/foo", "lib64/bar", "lib64/baz"}, 575 }, 576 { 577 debuggable: false, 578 expected: []string{"lib64/foo"}, 579 }, 580 } 581 for _, tc := range testcases { 582 config := testConfig{ 583 debuggable: tc.debuggable, 584 } 585 runPackagingTest(t, config, bp, tc.expected) 586 } 587} 588 589func TestPrefer32Deps(t *testing.T) { 590 bpTemplate := ` 591 component { 592 name: "foo", 593 compile_multilib: "both", // not needed but for clarity 594 } 595 596 component { 597 name: "foo_32only", 598 compile_multilib: "prefer32", 599 } 600 601 component { 602 name: "foo_64only", 603 compile_multilib: "64", 604 } 605 606 package_module { 607 name: "package", 608 compile_multilib: "%COMPILE_MULTILIB%", 609 multilib: { 610 prefer32: { 611 deps: %DEPS%, 612 }, 613 }, 614 } 615 ` 616 617 testcases := []struct { 618 compileMultilib string 619 deps []string 620 expected []string 621 }{ 622 { 623 compileMultilib: "first", 624 deps: []string{"foo", "foo_64only"}, 625 expected: []string{"lib64/foo", "lib64/foo_64only"}, 626 }, 627 { 628 compileMultilib: "64", 629 deps: []string{"foo", "foo_64only"}, 630 expected: []string{"lib64/foo", "lib64/foo_64only"}, 631 }, 632 { 633 compileMultilib: "32", 634 deps: []string{"foo", "foo_32only"}, 635 expected: []string{"lib32/foo", "lib32/foo_32only"}, 636 }, 637 { 638 compileMultilib: "both", 639 deps: []string{"foo", "foo_32only", "foo_64only"}, 640 expected: []string{"lib32/foo", "lib32/foo_32only", "lib64/foo_64only"}, 641 }, 642 } 643 for _, tc := range testcases { 644 config := testConfig{ 645 multiTarget: true, 646 depsCollectFirstTargetOnly: true, 647 } 648 bp := strings.Replace(bpTemplate, "%COMPILE_MULTILIB%", tc.compileMultilib, -1) 649 bp = strings.Replace(bp, "%DEPS%", `["`+strings.Join(tc.deps, `", "`)+`"]`, -1) 650 runPackagingTest(t, config, bp, tc.expected) 651 } 652} 653