1package android 2 3import ( 4 "testing" 5 6 "github.com/google/blueprint" 7) 8 9var licensesTests = []struct { 10 name string 11 fs MockFS 12 expectedErrors []string 13 effectivePackage map[string]string 14 effectiveNotices map[string][]string 15 effectiveKinds map[string][]string 16 effectiveConditions map[string][]string 17}{ 18 { 19 name: "invalid module type without licenses property", 20 fs: map[string][]byte{ 21 "top/Android.bp": []byte(` 22 mock_bad_module { 23 name: "libexample", 24 }`), 25 }, 26 expectedErrors: []string{`module type "mock_bad_module" must have an applicable licenses property`}, 27 }, 28 { 29 name: "license must exist", 30 fs: map[string][]byte{ 31 "top/Android.bp": []byte(` 32 mock_library { 33 name: "libexample", 34 licenses: ["notice"], 35 }`), 36 }, 37 expectedErrors: []string{`"libexample" depends on undefined module "notice"`}, 38 }, 39 { 40 name: "all good", 41 fs: map[string][]byte{ 42 "top/Android.bp": []byte(` 43 license_kind { 44 name: "notice", 45 conditions: ["shownotice"], 46 } 47 48 license { 49 name: "top_Apache2", 50 license_kinds: ["notice"], 51 package_name: "topDog", 52 license_text: ["LICENSE", "NOTICE"], 53 } 54 55 mock_library { 56 name: "libexample1", 57 licenses: ["top_Apache2"], 58 }`), 59 "top/nested/Android.bp": []byte(` 60 mock_library { 61 name: "libnested", 62 licenses: ["top_Apache2"], 63 }`), 64 "other/Android.bp": []byte(` 65 mock_library { 66 name: "libother", 67 licenses: ["top_Apache2"], 68 }`), 69 }, 70 effectiveKinds: map[string][]string{ 71 "libexample1": []string{"notice"}, 72 "libnested": []string{"notice"}, 73 "libother": []string{"notice"}, 74 }, 75 effectivePackage: map[string]string{ 76 "libexample1": "topDog", 77 "libnested": "topDog", 78 "libother": "topDog", 79 }, 80 effectiveConditions: map[string][]string{ 81 "libexample1": []string{"shownotice"}, 82 "libnested": []string{"shownotice"}, 83 "libother": []string{"shownotice"}, 84 }, 85 effectiveNotices: map[string][]string{ 86 "libexample1": []string{"top/LICENSE:topDog", "top/NOTICE:topDog"}, 87 "libnested": []string{"top/LICENSE:topDog", "top/NOTICE:topDog"}, 88 "libother": []string{"top/LICENSE:topDog", "top/NOTICE:topDog"}, 89 }, 90 }, 91 92 // Defaults propagation tests 93 { 94 // Check that licenses is the union of the defaults modules. 95 name: "defaults union, basic", 96 fs: map[string][]byte{ 97 "top/Android.bp": []byte(` 98 license_kind { 99 name: "top_notice", 100 conditions: ["notice"], 101 } 102 103 license { 104 name: "top_other", 105 license_kinds: ["top_notice"], 106 } 107 108 mock_defaults { 109 name: "libexample_defaults", 110 licenses: ["top_other"], 111 } 112 mock_library { 113 name: "libexample", 114 licenses: ["nested_other"], 115 defaults: ["libexample_defaults"], 116 } 117 mock_library { 118 name: "libsamepackage", 119 deps: ["libexample"], 120 }`), 121 "top/nested/Android.bp": []byte(` 122 license_kind { 123 name: "nested_notice", 124 conditions: ["notice"], 125 } 126 127 license { 128 name: "nested_other", 129 license_kinds: ["nested_notice"], 130 } 131 132 mock_library { 133 name: "libnested", 134 deps: ["libexample"], 135 }`), 136 "other/Android.bp": []byte(` 137 mock_library { 138 name: "libother", 139 deps: ["libexample"], 140 }`), 141 }, 142 effectiveKinds: map[string][]string{ 143 "libexample": []string{"nested_notice", "top_notice"}, 144 "libsamepackage": []string{}, 145 "libnested": []string{}, 146 "libother": []string{}, 147 }, 148 effectiveConditions: map[string][]string{ 149 "libexample": []string{"notice"}, 150 "libsamepackage": []string{}, 151 "libnested": []string{}, 152 "libother": []string{}, 153 }, 154 }, 155 { 156 name: "defaults union, multiple defaults", 157 fs: map[string][]byte{ 158 "top/Android.bp": []byte(` 159 license { 160 name: "top", 161 } 162 mock_defaults { 163 name: "libexample_defaults_1", 164 licenses: ["other"], 165 } 166 mock_defaults { 167 name: "libexample_defaults_2", 168 licenses: ["top_nested"], 169 } 170 mock_library { 171 name: "libexample", 172 defaults: ["libexample_defaults_1", "libexample_defaults_2"], 173 } 174 mock_library { 175 name: "libsamepackage", 176 deps: ["libexample"], 177 }`), 178 "top/nested/Android.bp": []byte(` 179 license { 180 name: "top_nested", 181 license_text: ["LICENSE.txt"], 182 } 183 mock_library { 184 name: "libnested", 185 deps: ["libexample"], 186 }`), 187 "other/Android.bp": []byte(` 188 license { 189 name: "other", 190 } 191 mock_library { 192 name: "libother", 193 deps: ["libexample"], 194 }`), 195 "outsider/Android.bp": []byte(` 196 mock_library { 197 name: "liboutsider", 198 deps: ["libexample"], 199 }`), 200 }, 201 effectiveKinds: map[string][]string{ 202 "libexample": []string{}, 203 "libsamepackage": []string{}, 204 "libnested": []string{}, 205 "libother": []string{}, 206 "liboutsider": []string{}, 207 }, 208 effectiveNotices: map[string][]string{ 209 "libexample": []string{"top/nested/LICENSE.txt"}, 210 "libsamepackage": []string{}, 211 "libnested": []string{}, 212 "libother": []string{}, 213 "liboutsider": []string{}, 214 }, 215 }, 216 217 // Defaults module's defaults_licenses tests 218 { 219 name: "defaults_licenses invalid", 220 fs: map[string][]byte{ 221 "top/Android.bp": []byte(` 222 mock_defaults { 223 name: "top_defaults", 224 licenses: ["notice"], 225 }`), 226 }, 227 expectedErrors: []string{`"top_defaults" depends on undefined module "notice"`}, 228 }, 229 { 230 name: "defaults_licenses overrides package default", 231 fs: map[string][]byte{ 232 "top/Android.bp": []byte(` 233 package { 234 default_applicable_licenses: ["by_exception_only"], 235 } 236 license { 237 name: "by_exception_only", 238 } 239 license { 240 name: "notice", 241 } 242 mock_defaults { 243 name: "top_defaults", 244 licenses: ["notice"], 245 } 246 mock_library { 247 name: "libexample", 248 } 249 mock_library { 250 name: "libdefaults", 251 defaults: ["top_defaults"], 252 }`), 253 }, 254 }, 255 256 // Package default_applicable_licenses tests 257 { 258 name: "package default_applicable_licenses must exist", 259 fs: map[string][]byte{ 260 "top/Android.bp": []byte(` 261 package { 262 default_applicable_licenses: ["notice"], 263 }`), 264 }, 265 expectedErrors: []string{`"//top" depends on undefined module "notice"`}, 266 }, 267 { 268 // This test relies on the default licenses being legacy_public. 269 name: "package default_applicable_licenses property used when no licenses specified", 270 fs: map[string][]byte{ 271 "top/Android.bp": []byte(` 272 package { 273 default_applicable_licenses: ["top_notice"], 274 } 275 276 license { 277 name: "top_notice", 278 } 279 mock_library { 280 name: "libexample", 281 }`), 282 "outsider/Android.bp": []byte(` 283 mock_library { 284 name: "liboutsider", 285 deps: ["libexample"], 286 }`), 287 }, 288 }, 289 { 290 name: "package default_applicable_licenses not inherited to subpackages", 291 fs: map[string][]byte{ 292 "top/Android.bp": []byte(` 293 package { 294 default_applicable_licenses: ["top_notice"], 295 } 296 license { 297 name: "top_notice", 298 } 299 mock_library { 300 name: "libexample", 301 }`), 302 "top/nested/Android.bp": []byte(` 303 package { 304 default_applicable_licenses: ["outsider"], 305 } 306 307 mock_library { 308 name: "libnested", 309 }`), 310 "top/other/Android.bp": []byte(` 311 mock_library { 312 name: "libother", 313 }`), 314 "outsider/Android.bp": []byte(` 315 license { 316 name: "outsider", 317 } 318 mock_library { 319 name: "liboutsider", 320 deps: ["libexample", "libother", "libnested"], 321 }`), 322 }, 323 }, 324 { 325 name: "verify that prebuilt dependencies are included", 326 fs: map[string][]byte{ 327 "prebuilts/Android.bp": []byte(` 328 license { 329 name: "prebuilt" 330 } 331 prebuilt { 332 name: "module", 333 licenses: ["prebuilt"], 334 }`), 335 "top/sources/source_file": nil, 336 "top/sources/Android.bp": []byte(` 337 license { 338 name: "top_sources" 339 } 340 source { 341 name: "module", 342 licenses: ["top_sources"], 343 }`), 344 "top/other/source_file": nil, 345 "top/other/Android.bp": []byte(` 346 source { 347 name: "other", 348 deps: [":module"], 349 }`), 350 }, 351 }, 352 { 353 name: "verify that prebuilt dependencies are ignored for licenses reasons (preferred)", 354 fs: map[string][]byte{ 355 "prebuilts/Android.bp": []byte(` 356 license { 357 name: "prebuilt" 358 } 359 prebuilt { 360 name: "module", 361 licenses: ["prebuilt"], 362 prefer: true, 363 }`), 364 "top/sources/source_file": nil, 365 "top/sources/Android.bp": []byte(` 366 license { 367 name: "top_sources" 368 } 369 source { 370 name: "module", 371 licenses: ["top_sources"], 372 }`), 373 "top/other/source_file": nil, 374 "top/other/Android.bp": []byte(` 375 source { 376 name: "other", 377 deps: [":module"], 378 }`), 379 }, 380 }, 381} 382 383func TestLicenses(t *testing.T) { 384 for _, test := range licensesTests { 385 t.Run(test.name, func(t *testing.T) { 386 // Customize the common license text fixture factory. 387 result := GroupFixturePreparers( 388 prepareForLicenseTest, 389 FixtureRegisterWithContext(func(ctx RegistrationContext) { 390 ctx.RegisterModuleType("mock_bad_module", newMockLicensesBadModule) 391 ctx.RegisterModuleType("mock_library", newMockLicensesLibraryModule) 392 ctx.RegisterModuleType("mock_defaults", defaultsLicensesFactory) 393 }), 394 test.fs.AddToFixture(), 395 ). 396 ExtendWithErrorHandler(FixtureExpectsAllErrorsToMatchAPattern(test.expectedErrors)). 397 RunTest(t) 398 399 if test.effectivePackage != nil { 400 checkEffectivePackage(t, result, test.effectivePackage) 401 } 402 403 if test.effectiveNotices != nil { 404 checkEffectiveNotices(t, result, test.effectiveNotices) 405 } 406 407 if test.effectiveKinds != nil { 408 checkEffectiveKinds(t, result, test.effectiveKinds) 409 } 410 411 if test.effectiveConditions != nil { 412 checkEffectiveConditions(t, result, test.effectiveConditions) 413 } 414 }) 415 } 416} 417 418func checkEffectivePackage(t *testing.T, result *TestResult, effectivePackage map[string]string) { 419 actualPackage := make(map[string]string) 420 result.Context.Context.VisitAllModules(func(m blueprint.Module) { 421 if _, ok := m.(*licenseModule); ok { 422 return 423 } 424 if _, ok := m.(*licenseKindModule); ok { 425 return 426 } 427 if _, ok := m.(*packageModule); ok { 428 return 429 } 430 module, ok := m.(Module) 431 if !ok { 432 t.Errorf("%q not a module", m.Name()) 433 return 434 } 435 base := module.base() 436 if base == nil { 437 return 438 } 439 440 if base.commonProperties.Effective_package_name == nil { 441 actualPackage[m.Name()] = "" 442 } else { 443 actualPackage[m.Name()] = *base.commonProperties.Effective_package_name 444 } 445 }) 446 447 for moduleName, expectedPackage := range effectivePackage { 448 packageName, ok := actualPackage[moduleName] 449 if !ok { 450 packageName = "" 451 } 452 if expectedPackage != packageName { 453 t.Errorf("effective package mismatch for module %q: expected %q, found %q", moduleName, expectedPackage, packageName) 454 } 455 } 456} 457 458func checkEffectiveNotices(t *testing.T, result *TestResult, effectiveNotices map[string][]string) { 459 actualNotices := make(map[string][]string) 460 result.Context.Context.VisitAllModules(func(m blueprint.Module) { 461 if _, ok := m.(*licenseModule); ok { 462 return 463 } 464 if _, ok := m.(*licenseKindModule); ok { 465 return 466 } 467 if _, ok := m.(*packageModule); ok { 468 return 469 } 470 module, ok := m.(Module) 471 if !ok { 472 t.Errorf("%q not a module", m.Name()) 473 return 474 } 475 base := module.base() 476 if base == nil { 477 return 478 } 479 actualNotices[m.Name()] = base.commonProperties.Effective_license_text.Strings() 480 }) 481 482 for moduleName, expectedNotices := range effectiveNotices { 483 notices, ok := actualNotices[moduleName] 484 if !ok { 485 notices = []string{} 486 } 487 if !compareUnorderedStringArrays(expectedNotices, notices) { 488 t.Errorf("effective notice files mismatch for module %q: expected %q, found %q", moduleName, expectedNotices, notices) 489 } 490 } 491} 492 493func checkEffectiveKinds(t *testing.T, result *TestResult, effectiveKinds map[string][]string) { 494 actualKinds := make(map[string][]string) 495 result.Context.Context.VisitAllModules(func(m blueprint.Module) { 496 if _, ok := m.(*licenseModule); ok { 497 return 498 } 499 if _, ok := m.(*licenseKindModule); ok { 500 return 501 } 502 if _, ok := m.(*packageModule); ok { 503 return 504 } 505 module, ok := m.(Module) 506 if !ok { 507 t.Errorf("%q not a module", m.Name()) 508 return 509 } 510 base := module.base() 511 if base == nil { 512 return 513 } 514 actualKinds[m.Name()] = base.commonProperties.Effective_license_kinds 515 }) 516 517 for moduleName, expectedKinds := range effectiveKinds { 518 kinds, ok := actualKinds[moduleName] 519 if !ok { 520 kinds = []string{} 521 } 522 if !compareUnorderedStringArrays(expectedKinds, kinds) { 523 t.Errorf("effective license kinds mismatch for module %q: expected %q, found %q", moduleName, expectedKinds, kinds) 524 } 525 } 526} 527 528func checkEffectiveConditions(t *testing.T, result *TestResult, effectiveConditions map[string][]string) { 529 actualConditions := make(map[string][]string) 530 result.Context.Context.VisitAllModules(func(m blueprint.Module) { 531 if _, ok := m.(*licenseModule); ok { 532 return 533 } 534 if _, ok := m.(*licenseKindModule); ok { 535 return 536 } 537 if _, ok := m.(*packageModule); ok { 538 return 539 } 540 module, ok := m.(Module) 541 if !ok { 542 t.Errorf("%q not a module", m.Name()) 543 return 544 } 545 base := module.base() 546 if base == nil { 547 return 548 } 549 actualConditions[m.Name()] = base.commonProperties.Effective_license_conditions 550 }) 551 552 for moduleName, expectedConditions := range effectiveConditions { 553 conditions, ok := actualConditions[moduleName] 554 if !ok { 555 conditions = []string{} 556 } 557 if !compareUnorderedStringArrays(expectedConditions, conditions) { 558 t.Errorf("effective license conditions mismatch for module %q: expected %q, found %q", moduleName, expectedConditions, conditions) 559 } 560 } 561} 562 563func compareUnorderedStringArrays(expected, actual []string) bool { 564 if len(expected) != len(actual) { 565 return false 566 } 567 s := make(map[string]int) 568 for _, v := range expected { 569 s[v] += 1 570 } 571 for _, v := range actual { 572 c, ok := s[v] 573 if !ok { 574 return false 575 } 576 if c < 1 { 577 return false 578 } 579 s[v] -= 1 580 } 581 return true 582} 583 584type mockLicensesBadProperties struct { 585 Visibility []string 586} 587 588type mockLicensesBadModule struct { 589 ModuleBase 590 DefaultableModuleBase 591 properties mockLicensesBadProperties 592} 593 594func newMockLicensesBadModule() Module { 595 m := &mockLicensesBadModule{} 596 597 base := m.base() 598 m.AddProperties(&base.nameProperties, &m.properties) 599 600 // The default_visibility property needs to be checked and parsed by the visibility module during 601 // its checking and parsing phases so make it the primary visibility property. 602 setPrimaryVisibilityProperty(m, "visibility", &m.properties.Visibility) 603 604 initAndroidModuleBase(m) 605 InitDefaultableModule(m) 606 607 return m 608} 609 610func (m *mockLicensesBadModule) GenerateAndroidBuildActions(ModuleContext) { 611} 612 613type mockLicensesLibraryProperties struct { 614 Deps []string 615} 616 617type mockLicensesLibraryModule struct { 618 ModuleBase 619 DefaultableModuleBase 620 properties mockLicensesLibraryProperties 621} 622 623func newMockLicensesLibraryModule() Module { 624 m := &mockLicensesLibraryModule{} 625 m.AddProperties(&m.properties) 626 InitAndroidArchModule(m, HostAndDeviceSupported, MultilibCommon) 627 InitDefaultableModule(m) 628 return m 629} 630 631type dependencyLicensesTag struct { 632 blueprint.BaseDependencyTag 633 name string 634} 635 636func (j *mockLicensesLibraryModule) DepsMutator(ctx BottomUpMutatorContext) { 637 ctx.AddVariationDependencies(nil, dependencyLicensesTag{name: "mockdeps"}, j.properties.Deps...) 638} 639 640func (p *mockLicensesLibraryModule) GenerateAndroidBuildActions(ModuleContext) { 641} 642 643type mockLicensesDefaults struct { 644 ModuleBase 645 DefaultsModuleBase 646} 647 648func defaultsLicensesFactory() Module { 649 m := &mockLicensesDefaults{} 650 InitDefaultsModule(m) 651 return m 652} 653