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 blueprint 16 17import ( 18 "fmt" 19 "reflect" 20 "strings" 21 "testing" 22) 23 24type providerTestModule struct { 25 SimpleName 26 properties struct { 27 Deps []string 28 } 29 30 mutatorProviderValues []string 31 generateBuildActionsProviderValues []string 32} 33 34func newProviderTestModule() (Module, []interface{}) { 35 m := &providerTestModule{} 36 return m, []interface{}{&m.properties, &m.SimpleName.Properties} 37} 38 39type providerTestMutatorInfo struct { 40 Values []string 41} 42 43type providerTestGenerateBuildActionsInfo struct { 44 Value string 45} 46 47type providerTestUnsetInfo string 48 49var providerTestMutatorInfoProvider = NewMutatorProvider[*providerTestMutatorInfo]("provider_mutator") 50var providerTestGenerateBuildActionsInfoProvider = NewProvider[*providerTestGenerateBuildActionsInfo]() 51var providerTestUnsetInfoProvider = NewMutatorProvider[providerTestUnsetInfo]("provider_mutator") 52var providerTestUnusedMutatorProvider = NewMutatorProvider[*struct{ unused string }]("nonexistent_mutator") 53 54func (p *providerTestModule) GenerateBuildActions(ctx ModuleContext) { 55 unset, ok := ModuleProvider(ctx, providerTestUnsetInfoProvider) 56 if ok { 57 panic(fmt.Errorf("expected false return value for providerTestGenerateBuildActionsInfoProvider before it was set")) 58 } 59 if unset != "" { 60 panic(fmt.Errorf("expected zero value for providerTestGenerateBuildActionsInfoProvider before it was set, got %q", 61 unset)) 62 } 63 64 // Verify reading providerTestUnusedMutatorProvider doesn't panic 65 _, _ = ModuleProvider(ctx, providerTestUnusedMutatorProvider) 66 67 SetProvider(ctx, providerTestGenerateBuildActionsInfoProvider, &providerTestGenerateBuildActionsInfo{ 68 Value: ctx.ModuleName(), 69 }) 70 71 mp, ok := ModuleProvider(ctx, providerTestMutatorInfoProvider) 72 if ok { 73 p.mutatorProviderValues = mp.Values 74 } 75 76 ctx.VisitDirectDeps(func(module Module) { 77 gbap, _ := OtherModuleProvider(ctx, module, providerTestGenerateBuildActionsInfoProvider) 78 if gbap != nil { 79 p.generateBuildActionsProviderValues = append(p.generateBuildActionsProviderValues, gbap.Value) 80 } 81 }) 82} 83 84func providerTestDepsMutator(ctx BottomUpMutatorContext) { 85 if p, ok := ctx.Module().(*providerTestModule); ok { 86 ctx.AddDependency(ctx.Module(), nil, p.properties.Deps...) 87 } 88} 89 90func providerTestMutator(ctx BottomUpMutatorContext) { 91 values := []string{strings.ToLower(ctx.ModuleName())} 92 93 ctx.VisitDirectDeps(func(module Module) { 94 mp, _ := OtherModuleProvider(ctx, module, providerTestMutatorInfoProvider) 95 if mp != nil { 96 values = append(values, mp.Values...) 97 } 98 }) 99 100 SetProvider(ctx, providerTestMutatorInfoProvider, &providerTestMutatorInfo{ 101 Values: values, 102 }) 103} 104 105func providerTestAfterMutator(ctx BottomUpMutatorContext) { 106 // Verify reading providerTestUnusedMutatorProvider doesn't panic 107 _, _ = ModuleProvider(ctx, providerTestMutatorInfoProvider) 108} 109 110func TestProviders(t *testing.T) { 111 ctx := NewContext() 112 ctx.RegisterModuleType("provider_module", newProviderTestModule) 113 ctx.RegisterBottomUpMutator("provider_deps_mutator", providerTestDepsMutator) 114 ctx.RegisterBottomUpMutator("provider_mutator", providerTestMutator) 115 ctx.RegisterBottomUpMutator("provider_after_mutator", providerTestAfterMutator) 116 117 ctx.MockFileSystem(map[string][]byte{ 118 "Android.bp": []byte(` 119 provider_module { 120 name: "A", 121 deps: ["B"], 122 } 123 124 provider_module { 125 name: "B", 126 deps: ["C", "D"], 127 } 128 129 provider_module { 130 name: "C", 131 deps: ["D"], 132 } 133 134 provider_module { 135 name: "D", 136 } 137 `), 138 }) 139 140 _, errs := ctx.ParseBlueprintsFiles("Android.bp", nil) 141 if len(errs) == 0 { 142 _, errs = ctx.ResolveDependencies(nil) 143 } 144 if len(errs) == 0 { 145 _, errs = ctx.PrepareBuildActions(nil) 146 } 147 if len(errs) > 0 { 148 t.Errorf("unexpected errors:") 149 for _, err := range errs { 150 t.Errorf(" %s", err) 151 } 152 t.FailNow() 153 } 154 155 aModule := ctx.moduleGroupFromName("A", nil).moduleByVariantName("").logicModule.(*providerTestModule) 156 if g, w := aModule.generateBuildActionsProviderValues, []string{"B"}; !reflect.DeepEqual(g, w) { 157 t.Errorf("expected A.generateBuildActionsProviderValues %q, got %q", w, g) 158 } 159 if g, w := aModule.mutatorProviderValues, []string{"a", "b", "c", "d", "d"}; !reflect.DeepEqual(g, w) { 160 t.Errorf("expected A.mutatorProviderValues %q, got %q", w, g) 161 } 162 163 bModule := ctx.moduleGroupFromName("B", nil).moduleByVariantName("").logicModule.(*providerTestModule) 164 if g, w := bModule.generateBuildActionsProviderValues, []string{"C", "D"}; !reflect.DeepEqual(g, w) { 165 t.Errorf("expected B.generateBuildActionsProviderValues %q, got %q", w, g) 166 } 167 if g, w := bModule.mutatorProviderValues, []string{"b", "c", "d", "d"}; !reflect.DeepEqual(g, w) { 168 t.Errorf("expected B.mutatorProviderValues %q, got %q", w, g) 169 } 170} 171 172type invalidProviderUsageMutatorInfo string 173type invalidProviderUsageGenerateBuildActionsInfo string 174 175var invalidProviderUsageMutatorInfoProvider = NewMutatorProvider[invalidProviderUsageMutatorInfo]("mutator_under_test") 176var invalidProviderUsageGenerateBuildActionsInfoProvider = NewProvider[invalidProviderUsageGenerateBuildActionsInfo]() 177 178type invalidProviderUsageTestModule struct { 179 SimpleName 180 properties struct { 181 Deps []string 182 183 Early_mutator_set_of_mutator_provider bool 184 Late_mutator_set_of_mutator_provider bool 185 Late_build_actions_set_of_mutator_provider bool 186 Early_mutator_set_of_build_actions_provider bool 187 188 Early_mutator_get_of_mutator_provider bool 189 Early_mutator_get_of_build_actions_provider bool 190 191 Duplicate_set bool 192 } 193} 194 195func invalidProviderUsageDepsMutator(ctx BottomUpMutatorContext) { 196 if i, ok := ctx.Module().(*invalidProviderUsageTestModule); ok { 197 ctx.AddDependency(ctx.Module(), nil, i.properties.Deps...) 198 } 199} 200 201func invalidProviderUsageBeforeMutator(ctx BottomUpMutatorContext) { 202 if i, ok := ctx.Module().(*invalidProviderUsageTestModule); ok { 203 if i.properties.Early_mutator_set_of_mutator_provider { 204 // A mutator attempting to set the value of a provider associated with a later mutator. 205 SetProvider(ctx, invalidProviderUsageMutatorInfoProvider, invalidProviderUsageMutatorInfo("")) 206 } 207 if i.properties.Early_mutator_get_of_mutator_provider { 208 // A mutator attempting to get the value of a provider associated with a later mutator. 209 _, _ = ModuleProvider(ctx, invalidProviderUsageMutatorInfoProvider) 210 } 211 } 212} 213 214func invalidProviderUsageMutatorUnderTest(ctx BottomUpMutatorContext) { 215 if i, ok := ctx.Module().(*invalidProviderUsageTestModule); ok { 216 if i.properties.Early_mutator_set_of_build_actions_provider { 217 // A mutator attempting to set the value of a non-mutator provider. 218 SetProvider(ctx, invalidProviderUsageGenerateBuildActionsInfoProvider, invalidProviderUsageGenerateBuildActionsInfo("")) 219 } 220 if i.properties.Early_mutator_get_of_build_actions_provider { 221 // A mutator attempting to get the value of a non-mutator provider. 222 _, _ = ModuleProvider(ctx, invalidProviderUsageGenerateBuildActionsInfoProvider) 223 } 224 } 225} 226 227func invalidProviderUsageAfterMutator(ctx BottomUpMutatorContext) { 228 if i, ok := ctx.Module().(*invalidProviderUsageTestModule); ok { 229 if i.properties.Late_mutator_set_of_mutator_provider { 230 // A mutator trying to set the value of a provider associated with an earlier mutator. 231 SetProvider(ctx, invalidProviderUsageMutatorInfoProvider, invalidProviderUsageMutatorInfo("")) 232 } 233 if i.properties.Late_mutator_set_of_mutator_provider { 234 // A mutator trying to set the value of a provider associated with an earlier mutator. 235 SetProvider(ctx, invalidProviderUsageMutatorInfoProvider, invalidProviderUsageMutatorInfo("")) 236 } 237 } 238} 239 240func (i *invalidProviderUsageTestModule) GenerateBuildActions(ctx ModuleContext) { 241 if i.properties.Late_build_actions_set_of_mutator_provider { 242 // A GenerateBuildActions trying to set the value of a provider associated with a mutator. 243 SetProvider(ctx, invalidProviderUsageMutatorInfoProvider, invalidProviderUsageMutatorInfo("")) 244 } 245 if i.properties.Duplicate_set { 246 SetProvider(ctx, invalidProviderUsageGenerateBuildActionsInfoProvider, invalidProviderUsageGenerateBuildActionsInfo("")) 247 SetProvider(ctx, invalidProviderUsageGenerateBuildActionsInfoProvider, invalidProviderUsageGenerateBuildActionsInfo("")) 248 } 249} 250 251func TestInvalidProvidersUsage(t *testing.T) { 252 run := func(t *testing.T, module string, prop string, panicMsg string) { 253 t.Helper() 254 ctx := NewContext() 255 ctx.RegisterModuleType("invalid_provider_usage_test_module", func() (Module, []interface{}) { 256 m := &invalidProviderUsageTestModule{} 257 return m, []interface{}{&m.properties, &m.SimpleName.Properties} 258 }) 259 ctx.RegisterBottomUpMutator("deps", invalidProviderUsageDepsMutator) 260 ctx.RegisterBottomUpMutator("before", invalidProviderUsageBeforeMutator) 261 ctx.RegisterBottomUpMutator("mutator_under_test", invalidProviderUsageMutatorUnderTest) 262 ctx.RegisterBottomUpMutator("after", invalidProviderUsageAfterMutator) 263 264 // Don't invalidate the parent pointer and before GenerateBuildActions. 265 ctx.SkipCloneModulesAfterMutators = true 266 267 var parentBP, moduleUnderTestBP, childBP string 268 269 prop += ": true," 270 271 switch module { 272 case "parent": 273 parentBP = prop 274 case "module_under_test": 275 moduleUnderTestBP = prop 276 case "child": 277 childBP = prop 278 } 279 280 bp := fmt.Sprintf(` 281 invalid_provider_usage_test_module { 282 name: "parent", 283 deps: ["module_under_test"], 284 %s 285 } 286 287 invalid_provider_usage_test_module { 288 name: "module_under_test", 289 deps: ["child"], 290 %s 291 } 292 293 invalid_provider_usage_test_module { 294 name: "child", 295 %s 296 } 297 298 `, 299 parentBP, 300 moduleUnderTestBP, 301 childBP) 302 303 ctx.MockFileSystem(map[string][]byte{ 304 "Android.bp": []byte(bp), 305 }) 306 307 _, errs := ctx.ParseBlueprintsFiles("Android.bp", nil) 308 309 if len(errs) == 0 { 310 _, errs = ctx.ResolveDependencies(nil) 311 } 312 313 if len(errs) == 0 { 314 _, errs = ctx.PrepareBuildActions(nil) 315 } 316 317 if len(errs) == 0 { 318 t.Fatal("expected an error") 319 } 320 321 if len(errs) > 1 { 322 t.Errorf("expected a single error, got %d:", len(errs)) 323 for i, err := range errs { 324 t.Errorf("%d: %s", i, err) 325 } 326 t.FailNow() 327 } 328 329 if panicErr, ok := errs[0].(panicError); ok { 330 if panicErr.panic != panicMsg { 331 t.Fatalf("expected panic %q, got %q", panicMsg, panicErr.panic) 332 } 333 } else { 334 t.Fatalf("expected a panicError, got %T: %s", errs[0], errs[0].Error()) 335 } 336 337 } 338 339 tests := []struct { 340 prop string 341 module string 342 343 panicMsg string 344 skip string 345 }{ 346 { 347 prop: "early_mutator_set_of_mutator_provider", 348 module: "module_under_test", 349 panicMsg: "Can't set value of provider blueprint.invalidProviderUsageMutatorInfo before mutator mutator_under_test started", 350 }, 351 { 352 prop: "late_mutator_set_of_mutator_provider", 353 module: "module_under_test", 354 panicMsg: "Can't set value of provider blueprint.invalidProviderUsageMutatorInfo after mutator mutator_under_test finished", 355 }, 356 { 357 prop: "late_build_actions_set_of_mutator_provider", 358 module: "module_under_test", 359 panicMsg: "Can't set value of provider blueprint.invalidProviderUsageMutatorInfo after mutator mutator_under_test finished", 360 }, 361 { 362 prop: "early_mutator_set_of_build_actions_provider", 363 module: "module_under_test", 364 panicMsg: "Can't set value of provider blueprint.invalidProviderUsageGenerateBuildActionsInfo before GenerateBuildActions started", 365 }, 366 367 { 368 prop: "early_mutator_get_of_mutator_provider", 369 module: "module_under_test", 370 panicMsg: "Can't get value of provider blueprint.invalidProviderUsageMutatorInfo before mutator mutator_under_test finished", 371 }, 372 { 373 prop: "early_mutator_get_of_build_actions_provider", 374 module: "module_under_test", 375 panicMsg: "Can't get value of provider blueprint.invalidProviderUsageGenerateBuildActionsInfo before GenerateBuildActions finished", 376 }, 377 { 378 prop: "duplicate_set", 379 module: "module_under_test", 380 panicMsg: "Value of provider blueprint.invalidProviderUsageGenerateBuildActionsInfo is already set", 381 }, 382 } 383 384 for _, tt := range tests { 385 t.Run(tt.prop, func(t *testing.T) { 386 run(t, tt.module, tt.prop, tt.panicMsg) 387 }) 388 } 389} 390