1// Copyright 2021 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. 14package android 15 16import ( 17 "fmt" 18 "testing" 19 20 "android/soong/android/allowlists" 21 "android/soong/bazel" 22 23 "github.com/google/blueprint" 24 "github.com/google/blueprint/proptools" 25) 26 27func TestConvertAllModulesInPackage(t *testing.T) { 28 testCases := []struct { 29 prefixes allowlists.Bp2BuildConfig 30 packageDir string 31 }{ 32 { 33 prefixes: allowlists.Bp2BuildConfig{ 34 "a": allowlists.Bp2BuildDefaultTrueRecursively, 35 }, 36 packageDir: "a", 37 }, 38 { 39 prefixes: allowlists.Bp2BuildConfig{ 40 "a/b": allowlists.Bp2BuildDefaultTrueRecursively, 41 }, 42 packageDir: "a/b", 43 }, 44 { 45 prefixes: allowlists.Bp2BuildConfig{ 46 "a/b": allowlists.Bp2BuildDefaultTrueRecursively, 47 "a/b/c": allowlists.Bp2BuildDefaultTrueRecursively, 48 }, 49 packageDir: "a/b", 50 }, 51 { 52 prefixes: allowlists.Bp2BuildConfig{ 53 "a": allowlists.Bp2BuildDefaultTrueRecursively, 54 "d/e/f": allowlists.Bp2BuildDefaultTrueRecursively, 55 }, 56 packageDir: "a/b", 57 }, 58 { 59 prefixes: allowlists.Bp2BuildConfig{ 60 "a": allowlists.Bp2BuildDefaultFalse, 61 "a/b": allowlists.Bp2BuildDefaultTrueRecursively, 62 "a/b/c": allowlists.Bp2BuildDefaultFalse, 63 }, 64 packageDir: "a/b", 65 }, 66 { 67 prefixes: allowlists.Bp2BuildConfig{ 68 "a": allowlists.Bp2BuildDefaultTrueRecursively, 69 "a/b": allowlists.Bp2BuildDefaultFalse, 70 "a/b/c": allowlists.Bp2BuildDefaultTrueRecursively, 71 }, 72 packageDir: "a", 73 }, 74 { 75 prefixes: allowlists.Bp2BuildConfig{ 76 "a": allowlists.Bp2BuildDefaultFalseRecursively, 77 "a/b": allowlists.Bp2BuildDefaultTrue, 78 }, 79 packageDir: "a/b", 80 }, 81 { 82 prefixes: allowlists.Bp2BuildConfig{ 83 "a": allowlists.Bp2BuildDefaultFalseRecursively, 84 "a/b": allowlists.Bp2BuildDefaultTrueRecursively, 85 }, 86 packageDir: "a/b/c", 87 }, 88 } 89 90 for _, test := range testCases { 91 if ok, _ := bp2buildDefaultTrueRecursively(test.packageDir, test.prefixes); !ok { 92 t.Errorf("Expected to convert all modules in %s based on %v, but failed.", test.packageDir, test.prefixes) 93 } 94 } 95} 96 97func TestModuleOptIn(t *testing.T) { 98 testCases := []struct { 99 prefixes allowlists.Bp2BuildConfig 100 packageDir string 101 }{ 102 { 103 prefixes: allowlists.Bp2BuildConfig{ 104 "a/b": allowlists.Bp2BuildDefaultFalse, 105 }, 106 packageDir: "a/b", 107 }, 108 { 109 prefixes: allowlists.Bp2BuildConfig{ 110 "a": allowlists.Bp2BuildDefaultFalse, 111 "a/b": allowlists.Bp2BuildDefaultTrueRecursively, 112 }, 113 packageDir: "a", 114 }, 115 { 116 prefixes: allowlists.Bp2BuildConfig{ 117 "a/b": allowlists.Bp2BuildDefaultTrueRecursively, 118 }, 119 packageDir: "a", // opt-in by default 120 }, 121 { 122 prefixes: allowlists.Bp2BuildConfig{ 123 "a/b/c": allowlists.Bp2BuildDefaultTrueRecursively, 124 }, 125 packageDir: "a/b", 126 }, 127 { 128 prefixes: allowlists.Bp2BuildConfig{ 129 "a": allowlists.Bp2BuildDefaultTrueRecursively, 130 "d/e/f": allowlists.Bp2BuildDefaultTrueRecursively, 131 }, 132 packageDir: "foo/bar", 133 }, 134 { 135 prefixes: allowlists.Bp2BuildConfig{ 136 "a": allowlists.Bp2BuildDefaultTrueRecursively, 137 "a/b": allowlists.Bp2BuildDefaultFalse, 138 "a/b/c": allowlists.Bp2BuildDefaultTrueRecursively, 139 }, 140 packageDir: "a/b", 141 }, 142 { 143 prefixes: allowlists.Bp2BuildConfig{ 144 "a": allowlists.Bp2BuildDefaultFalse, 145 "a/b": allowlists.Bp2BuildDefaultTrueRecursively, 146 "a/b/c": allowlists.Bp2BuildDefaultFalse, 147 }, 148 packageDir: "a", 149 }, 150 { 151 prefixes: allowlists.Bp2BuildConfig{ 152 "a": allowlists.Bp2BuildDefaultFalseRecursively, 153 "a/b": allowlists.Bp2BuildDefaultTrue, 154 }, 155 packageDir: "a/b/c", 156 }, 157 { 158 prefixes: allowlists.Bp2BuildConfig{ 159 "a": allowlists.Bp2BuildDefaultTrueRecursively, 160 "a/b": allowlists.Bp2BuildDefaultFalseRecursively, 161 }, 162 packageDir: "a/b/c", 163 }, 164 } 165 166 for _, test := range testCases { 167 if ok, _ := bp2buildDefaultTrueRecursively(test.packageDir, test.prefixes); ok { 168 t.Errorf("Expected to allow module opt-in in %s based on %v, but failed.", test.packageDir, test.prefixes) 169 } 170 } 171} 172 173type TestBazelModule struct { 174 bazel.TestModuleInfo 175 BazelModuleBase 176} 177 178var _ blueprint.Module = TestBazelModule{} 179 180func (m TestBazelModule) Name() string { 181 return m.TestModuleInfo.ModuleName 182} 183 184func (m TestBazelModule) GenerateBuildActions(blueprint.ModuleContext) { 185} 186 187type TestBazelConversionContext struct { 188 omc bazel.OtherModuleTestContext 189 allowlist Bp2BuildConversionAllowlist 190 errors []string 191} 192 193var _ bazelOtherModuleContext = &TestBazelConversionContext{} 194 195func (bcc *TestBazelConversionContext) OtherModuleType(m blueprint.Module) string { 196 return bcc.omc.OtherModuleType(m) 197} 198 199func (bcc *TestBazelConversionContext) OtherModuleName(m blueprint.Module) string { 200 return bcc.omc.OtherModuleName(m) 201} 202 203func (bcc *TestBazelConversionContext) OtherModuleDir(m blueprint.Module) string { 204 return bcc.omc.OtherModuleDir(m) 205} 206 207func (bcc *TestBazelConversionContext) ModuleErrorf(format string, args ...interface{}) { 208 bcc.errors = append(bcc.errors, fmt.Sprintf(format, args...)) 209} 210 211func (bcc *TestBazelConversionContext) Config() Config { 212 return Config{ 213 &config{ 214 Bp2buildPackageConfig: bcc.allowlist, 215 }, 216 } 217} 218 219var bazelableBazelModuleBase = BazelModuleBase{ 220 bazelProperties: properties{ 221 Bazel_module: bazelModuleProperties{ 222 CanConvertToBazel: true, 223 }, 224 }, 225} 226 227func TestBp2BuildAllowlist(t *testing.T) { 228 testCases := []struct { 229 description string 230 shouldConvert bool 231 expectedErrors []string 232 module TestBazelModule 233 allowlist Bp2BuildConversionAllowlist 234 }{ 235 { 236 description: "allowlist enables module", 237 shouldConvert: true, 238 module: TestBazelModule{ 239 TestModuleInfo: bazel.TestModuleInfo{ 240 ModuleName: "foo", 241 Typ: "rule1", 242 Dir: "dir1", 243 }, 244 BazelModuleBase: bazelableBazelModuleBase, 245 }, 246 allowlist: Bp2BuildConversionAllowlist{ 247 moduleAlwaysConvert: map[string]bool{ 248 "foo": true, 249 }, 250 }, 251 }, 252 { 253 description: "module in name allowlist and type allowlist fails", 254 shouldConvert: false, 255 expectedErrors: []string{"A module cannot be in moduleAlwaysConvert and also be in moduleTypeAlwaysConvert"}, 256 module: TestBazelModule{ 257 TestModuleInfo: bazel.TestModuleInfo{ 258 ModuleName: "foo", 259 Typ: "rule1", 260 Dir: "dir1", 261 }, 262 BazelModuleBase: bazelableBazelModuleBase, 263 }, 264 allowlist: Bp2BuildConversionAllowlist{ 265 moduleAlwaysConvert: map[string]bool{ 266 "foo": true, 267 }, 268 moduleTypeAlwaysConvert: map[string]bool{ 269 "rule1": true, 270 }, 271 }, 272 }, 273 { 274 description: "module in allowlist and denylist fails", 275 shouldConvert: false, 276 expectedErrors: []string{"a module cannot be in moduleDoNotConvert and also be in moduleAlwaysConvert"}, 277 module: TestBazelModule{ 278 TestModuleInfo: bazel.TestModuleInfo{ 279 ModuleName: "foo", 280 Typ: "rule1", 281 Dir: "dir1", 282 }, 283 BazelModuleBase: bazelableBazelModuleBase, 284 }, 285 allowlist: Bp2BuildConversionAllowlist{ 286 moduleAlwaysConvert: map[string]bool{ 287 "foo": true, 288 }, 289 moduleDoNotConvert: map[string]bool{ 290 "foo": true, 291 }, 292 }, 293 }, 294 { 295 description: "module allowlist and enabled directory", 296 shouldConvert: false, 297 expectedErrors: []string{"A module cannot be in a directory marked Bp2BuildDefaultTrue or Bp2BuildDefaultTrueRecursively and also be in moduleAlwaysConvert. Directory: 'existing/build/dir' Module: 'foo'"}, 298 module: TestBazelModule{ 299 TestModuleInfo: bazel.TestModuleInfo{ 300 ModuleName: "foo", 301 Typ: "rule1", 302 Dir: "existing/build/dir", 303 }, 304 BazelModuleBase: bazelableBazelModuleBase, 305 }, 306 allowlist: Bp2BuildConversionAllowlist{ 307 moduleAlwaysConvert: map[string]bool{ 308 "foo": true, 309 }, 310 defaultConfig: allowlists.Bp2BuildConfig{ 311 "existing/build/dir": allowlists.Bp2BuildDefaultTrue, 312 }, 313 }, 314 }, 315 { 316 description: "module allowlist and enabled subdirectory", 317 shouldConvert: false, 318 expectedErrors: []string{"A module cannot be in a directory marked Bp2BuildDefaultTrue or Bp2BuildDefaultTrueRecursively and also be in moduleAlwaysConvert. Directory: 'existing/build/dir' Module: 'foo'"}, 319 module: TestBazelModule{ 320 TestModuleInfo: bazel.TestModuleInfo{ 321 ModuleName: "foo", 322 Typ: "rule1", 323 Dir: "existing/build/dir/subdir", 324 }, 325 BazelModuleBase: bazelableBazelModuleBase, 326 }, 327 allowlist: Bp2BuildConversionAllowlist{ 328 moduleAlwaysConvert: map[string]bool{ 329 "foo": true, 330 }, 331 defaultConfig: allowlists.Bp2BuildConfig{ 332 "existing/build/dir": allowlists.Bp2BuildDefaultTrueRecursively, 333 }, 334 }, 335 }, 336 { 337 description: "module enabled in unit test short-circuits other allowlists", 338 shouldConvert: true, 339 module: TestBazelModule{ 340 TestModuleInfo: bazel.TestModuleInfo{ 341 ModuleName: "foo", 342 Typ: "rule1", 343 Dir: ".", 344 }, 345 BazelModuleBase: BazelModuleBase{ 346 bazelProperties: properties{ 347 Bazel_module: bazelModuleProperties{ 348 CanConvertToBazel: true, 349 Bp2build_available: proptools.BoolPtr(true), 350 }, 351 }, 352 }, 353 }, 354 allowlist: Bp2BuildConversionAllowlist{ 355 moduleAlwaysConvert: map[string]bool{ 356 "foo": true, 357 }, 358 moduleDoNotConvert: map[string]bool{ 359 "foo": true, 360 }, 361 }, 362 }, 363 } 364 365 for _, test := range testCases { 366 t.Run(test.description, func(t *testing.T) { 367 bcc := &TestBazelConversionContext{ 368 omc: bazel.OtherModuleTestContext{ 369 Modules: []bazel.TestModuleInfo{ 370 test.module.TestModuleInfo, 371 }, 372 }, 373 allowlist: test.allowlist, 374 } 375 376 shouldConvert := test.module.shouldConvertWithBp2build(bcc, test.module.TestModuleInfo) 377 if test.shouldConvert != shouldConvert { 378 t.Errorf("Module shouldConvert expected to be: %v, but was: %v", test.shouldConvert, shouldConvert) 379 } 380 381 errorsMatch := true 382 if len(test.expectedErrors) != len(bcc.errors) { 383 errorsMatch = false 384 } else { 385 for i, err := range test.expectedErrors { 386 if err != bcc.errors[i] { 387 errorsMatch = false 388 } 389 } 390 } 391 if !errorsMatch { 392 t.Errorf("Expected errors to be: %v, but were: %v", test.expectedErrors, bcc.errors) 393 } 394 }) 395 } 396} 397 398func TestBp2buildAllowList(t *testing.T) { 399 allowlist := GetBp2BuildAllowList() 400 for k, v := range allowlists.Bp2buildDefaultConfig { 401 if allowlist.defaultConfig[k] != v { 402 t.Errorf("bp2build default config of %s: expected: %v, got: %v", k, v, allowlist.defaultConfig[k]) 403 } 404 } 405 for k, v := range allowlists.Bp2buildKeepExistingBuildFile { 406 if allowlist.keepExistingBuildFile[k] != v { 407 t.Errorf("bp2build keep existing build file of %s: expected: %v, got: %v", k, v, allowlist.keepExistingBuildFile[k]) 408 } 409 } 410 for _, k := range allowlists.Bp2buildModuleTypeAlwaysConvertList { 411 if !allowlist.moduleTypeAlwaysConvert[k] { 412 t.Errorf("bp2build module type always convert of %s: expected: true, got: %v", k, allowlist.moduleTypeAlwaysConvert[k]) 413 } 414 } 415 for _, k := range allowlists.Bp2buildModuleDoNotConvertList { 416 if !allowlist.moduleDoNotConvert[k] { 417 t.Errorf("bp2build module do not convert of %s: expected: true, got: %v", k, allowlist.moduleDoNotConvert[k]) 418 } 419 } 420} 421 422func TestShouldKeepExistingBuildFileForDir(t *testing.T) { 423 allowlist := NewBp2BuildAllowlist() 424 // entry "a/b2/c2" is moot because of its parent "a/b2" 425 allowlist.SetKeepExistingBuildFile(map[string]bool{"a": false, "a/b1": false, "a/b2": true, "a/b1/c1": true, "a/b2/c2": false}) 426 truths := []string{"a", "a/b1", "a/b2", "a/b1/c1", "a/b2/c", "a/b2/c2", "a/b2/c2/d"} 427 falsities := []string{"a1", "a/b", "a/b1/c"} 428 for _, dir := range truths { 429 if !allowlist.ShouldKeepExistingBuildFileForDir(dir) { 430 t.Errorf("%s expected TRUE but was FALSE", dir) 431 } 432 } 433 for _, dir := range falsities { 434 if allowlist.ShouldKeepExistingBuildFileForDir(dir) { 435 t.Errorf("%s expected FALSE but was TRUE", dir) 436 } 437 } 438} 439