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