1*1fa6dee9SAndroid Build Coastguard Worker// Copyright 2014 Google Inc. All rights reserved. 2*1fa6dee9SAndroid Build Coastguard Worker// 3*1fa6dee9SAndroid Build Coastguard Worker// Licensed under the Apache License, Version 2.0 (the "License"); 4*1fa6dee9SAndroid Build Coastguard Worker// you may not use this file except in compliance with the License. 5*1fa6dee9SAndroid Build Coastguard Worker// You may obtain a copy of the License at 6*1fa6dee9SAndroid Build Coastguard Worker// 7*1fa6dee9SAndroid Build Coastguard Worker// http://www.apache.org/licenses/LICENSE-2.0 8*1fa6dee9SAndroid Build Coastguard Worker// 9*1fa6dee9SAndroid Build Coastguard Worker// Unless required by applicable law or agreed to in writing, software 10*1fa6dee9SAndroid Build Coastguard Worker// distributed under the License is distributed on an "AS IS" BASIS, 11*1fa6dee9SAndroid Build Coastguard Worker// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12*1fa6dee9SAndroid Build Coastguard Worker// See the License for the specific language governing permissions and 13*1fa6dee9SAndroid Build Coastguard Worker// limitations under the License. 14*1fa6dee9SAndroid Build Coastguard Worker 15*1fa6dee9SAndroid Build Coastguard Workerpackage blueprint 16*1fa6dee9SAndroid Build Coastguard Worker 17*1fa6dee9SAndroid Build Coastguard Workerimport ( 18*1fa6dee9SAndroid Build Coastguard Worker "bytes" 19*1fa6dee9SAndroid Build Coastguard Worker "errors" 20*1fa6dee9SAndroid Build Coastguard Worker "fmt" 21*1fa6dee9SAndroid Build Coastguard Worker "hash/fnv" 22*1fa6dee9SAndroid Build Coastguard Worker "os" 23*1fa6dee9SAndroid Build Coastguard Worker "reflect" 24*1fa6dee9SAndroid Build Coastguard Worker "slices" 25*1fa6dee9SAndroid Build Coastguard Worker "strconv" 26*1fa6dee9SAndroid Build Coastguard Worker "strings" 27*1fa6dee9SAndroid Build Coastguard Worker "sync" 28*1fa6dee9SAndroid Build Coastguard Worker "testing" 29*1fa6dee9SAndroid Build Coastguard Worker "text/scanner" 30*1fa6dee9SAndroid Build Coastguard Worker "time" 31*1fa6dee9SAndroid Build Coastguard Worker 32*1fa6dee9SAndroid Build Coastguard Worker "github.com/google/blueprint/parser" 33*1fa6dee9SAndroid Build Coastguard Worker "github.com/google/blueprint/proptools" 34*1fa6dee9SAndroid Build Coastguard Worker) 35*1fa6dee9SAndroid Build Coastguard Worker 36*1fa6dee9SAndroid Build Coastguard Workertype Walker interface { 37*1fa6dee9SAndroid Build Coastguard Worker Walk() bool 38*1fa6dee9SAndroid Build Coastguard Worker} 39*1fa6dee9SAndroid Build Coastguard Worker 40*1fa6dee9SAndroid Build Coastguard Workerfunc walkDependencyGraph(ctx *Context, topModule *moduleInfo, allowDuplicates bool) (string, string) { 41*1fa6dee9SAndroid Build Coastguard Worker var outputDown string 42*1fa6dee9SAndroid Build Coastguard Worker var outputUp string 43*1fa6dee9SAndroid Build Coastguard Worker ctx.walkDeps(topModule, allowDuplicates, 44*1fa6dee9SAndroid Build Coastguard Worker func(dep depInfo, parent *moduleInfo) bool { 45*1fa6dee9SAndroid Build Coastguard Worker outputDown += ctx.ModuleName(dep.module.logicModule) 46*1fa6dee9SAndroid Build Coastguard Worker if tag, ok := dep.tag.(walkerDepsTag); ok { 47*1fa6dee9SAndroid Build Coastguard Worker if !tag.follow { 48*1fa6dee9SAndroid Build Coastguard Worker return false 49*1fa6dee9SAndroid Build Coastguard Worker } 50*1fa6dee9SAndroid Build Coastguard Worker } 51*1fa6dee9SAndroid Build Coastguard Worker if dep.module.logicModule.(Walker).Walk() { 52*1fa6dee9SAndroid Build Coastguard Worker return true 53*1fa6dee9SAndroid Build Coastguard Worker } 54*1fa6dee9SAndroid Build Coastguard Worker 55*1fa6dee9SAndroid Build Coastguard Worker return false 56*1fa6dee9SAndroid Build Coastguard Worker }, 57*1fa6dee9SAndroid Build Coastguard Worker func(dep depInfo, parent *moduleInfo) { 58*1fa6dee9SAndroid Build Coastguard Worker outputUp += ctx.ModuleName(dep.module.logicModule) 59*1fa6dee9SAndroid Build Coastguard Worker }) 60*1fa6dee9SAndroid Build Coastguard Worker return outputDown, outputUp 61*1fa6dee9SAndroid Build Coastguard Worker} 62*1fa6dee9SAndroid Build Coastguard Worker 63*1fa6dee9SAndroid Build Coastguard Workertype depsProvider interface { 64*1fa6dee9SAndroid Build Coastguard Worker Deps() []string 65*1fa6dee9SAndroid Build Coastguard Worker IgnoreDeps() []string 66*1fa6dee9SAndroid Build Coastguard Worker} 67*1fa6dee9SAndroid Build Coastguard Worker 68*1fa6dee9SAndroid Build Coastguard Workertype IncrementalTestProvider struct { 69*1fa6dee9SAndroid Build Coastguard Worker Value string 70*1fa6dee9SAndroid Build Coastguard Worker} 71*1fa6dee9SAndroid Build Coastguard Worker 72*1fa6dee9SAndroid Build Coastguard Workervar IncrementalTestProviderKey = NewProvider[IncrementalTestProvider]() 73*1fa6dee9SAndroid Build Coastguard Worker 74*1fa6dee9SAndroid Build Coastguard Workertype baseTestModule struct { 75*1fa6dee9SAndroid Build Coastguard Worker SimpleName 76*1fa6dee9SAndroid Build Coastguard Worker properties struct { 77*1fa6dee9SAndroid Build Coastguard Worker Deps []string 78*1fa6dee9SAndroid Build Coastguard Worker Ignored_deps []string 79*1fa6dee9SAndroid Build Coastguard Worker } 80*1fa6dee9SAndroid Build Coastguard Worker GenerateBuildActionsCalled bool 81*1fa6dee9SAndroid Build Coastguard Worker} 82*1fa6dee9SAndroid Build Coastguard Worker 83*1fa6dee9SAndroid Build Coastguard Workerfunc (b *baseTestModule) Deps() []string { 84*1fa6dee9SAndroid Build Coastguard Worker return b.properties.Deps 85*1fa6dee9SAndroid Build Coastguard Worker} 86*1fa6dee9SAndroid Build Coastguard Worker 87*1fa6dee9SAndroid Build Coastguard Workerfunc (b *baseTestModule) IgnoreDeps() []string { 88*1fa6dee9SAndroid Build Coastguard Worker return b.properties.Ignored_deps 89*1fa6dee9SAndroid Build Coastguard Worker} 90*1fa6dee9SAndroid Build Coastguard Worker 91*1fa6dee9SAndroid Build Coastguard Workervar pctx PackageContext 92*1fa6dee9SAndroid Build Coastguard Worker 93*1fa6dee9SAndroid Build Coastguard Workerfunc init() { 94*1fa6dee9SAndroid Build Coastguard Worker pctx = NewPackageContext("android/blueprint") 95*1fa6dee9SAndroid Build Coastguard Worker} 96*1fa6dee9SAndroid Build Coastguard Workerfunc (b *baseTestModule) GenerateBuildActions(ctx ModuleContext) { 97*1fa6dee9SAndroid Build Coastguard Worker b.GenerateBuildActionsCalled = true 98*1fa6dee9SAndroid Build Coastguard Worker outputFile := ctx.ModuleName() + "_phony_output" 99*1fa6dee9SAndroid Build Coastguard Worker ctx.Build(pctx, BuildParams{ 100*1fa6dee9SAndroid Build Coastguard Worker Rule: Phony, 101*1fa6dee9SAndroid Build Coastguard Worker Outputs: []string{outputFile}, 102*1fa6dee9SAndroid Build Coastguard Worker }) 103*1fa6dee9SAndroid Build Coastguard Worker SetProvider(ctx, IncrementalTestProviderKey, IncrementalTestProvider{ 104*1fa6dee9SAndroid Build Coastguard Worker Value: ctx.ModuleName(), 105*1fa6dee9SAndroid Build Coastguard Worker }) 106*1fa6dee9SAndroid Build Coastguard Worker} 107*1fa6dee9SAndroid Build Coastguard Worker 108*1fa6dee9SAndroid Build Coastguard Workertype fooModule struct { 109*1fa6dee9SAndroid Build Coastguard Worker baseTestModule 110*1fa6dee9SAndroid Build Coastguard Worker} 111*1fa6dee9SAndroid Build Coastguard Worker 112*1fa6dee9SAndroid Build Coastguard Workerfunc newFooModule() (Module, []interface{}) { 113*1fa6dee9SAndroid Build Coastguard Worker m := &fooModule{} 114*1fa6dee9SAndroid Build Coastguard Worker return m, []interface{}{&m.baseTestModule.properties, &m.SimpleName.Properties} 115*1fa6dee9SAndroid Build Coastguard Worker} 116*1fa6dee9SAndroid Build Coastguard Worker 117*1fa6dee9SAndroid Build Coastguard Workerfunc (f *fooModule) Walk() bool { 118*1fa6dee9SAndroid Build Coastguard Worker return true 119*1fa6dee9SAndroid Build Coastguard Worker} 120*1fa6dee9SAndroid Build Coastguard Worker 121*1fa6dee9SAndroid Build Coastguard Workertype barModule struct { 122*1fa6dee9SAndroid Build Coastguard Worker SimpleName 123*1fa6dee9SAndroid Build Coastguard Worker baseTestModule 124*1fa6dee9SAndroid Build Coastguard Worker} 125*1fa6dee9SAndroid Build Coastguard Worker 126*1fa6dee9SAndroid Build Coastguard Workerfunc newBarModule() (Module, []interface{}) { 127*1fa6dee9SAndroid Build Coastguard Worker m := &barModule{} 128*1fa6dee9SAndroid Build Coastguard Worker return m, []interface{}{&m.baseTestModule.properties, &m.SimpleName.Properties} 129*1fa6dee9SAndroid Build Coastguard Worker} 130*1fa6dee9SAndroid Build Coastguard Worker 131*1fa6dee9SAndroid Build Coastguard Workerfunc (b *barModule) Walk() bool { 132*1fa6dee9SAndroid Build Coastguard Worker return false 133*1fa6dee9SAndroid Build Coastguard Worker} 134*1fa6dee9SAndroid Build Coastguard Worker 135*1fa6dee9SAndroid Build Coastguard Workertype incrementalModule struct { 136*1fa6dee9SAndroid Build Coastguard Worker SimpleName 137*1fa6dee9SAndroid Build Coastguard Worker baseTestModule 138*1fa6dee9SAndroid Build Coastguard Worker IncrementalModule 139*1fa6dee9SAndroid Build Coastguard Worker} 140*1fa6dee9SAndroid Build Coastguard Worker 141*1fa6dee9SAndroid Build Coastguard Workervar _ Incremental = &incrementalModule{} 142*1fa6dee9SAndroid Build Coastguard Worker 143*1fa6dee9SAndroid Build Coastguard Workerfunc newIncrementalModule() (Module, []interface{}) { 144*1fa6dee9SAndroid Build Coastguard Worker m := &incrementalModule{} 145*1fa6dee9SAndroid Build Coastguard Worker return m, []interface{}{&m.baseTestModule.properties, &m.SimpleName.Properties} 146*1fa6dee9SAndroid Build Coastguard Worker} 147*1fa6dee9SAndroid Build Coastguard Worker 148*1fa6dee9SAndroid Build Coastguard Workertype walkerDepsTag struct { 149*1fa6dee9SAndroid Build Coastguard Worker BaseDependencyTag 150*1fa6dee9SAndroid Build Coastguard Worker // True if the dependency should be followed, false otherwise. 151*1fa6dee9SAndroid Build Coastguard Worker follow bool 152*1fa6dee9SAndroid Build Coastguard Worker} 153*1fa6dee9SAndroid Build Coastguard Worker 154*1fa6dee9SAndroid Build Coastguard Workerfunc depsMutator(mctx BottomUpMutatorContext) { 155*1fa6dee9SAndroid Build Coastguard Worker if m, ok := mctx.Module().(depsProvider); ok { 156*1fa6dee9SAndroid Build Coastguard Worker mctx.AddDependency(mctx.Module(), walkerDepsTag{follow: false}, m.IgnoreDeps()...) 157*1fa6dee9SAndroid Build Coastguard Worker mctx.AddDependency(mctx.Module(), walkerDepsTag{follow: true}, m.Deps()...) 158*1fa6dee9SAndroid Build Coastguard Worker } 159*1fa6dee9SAndroid Build Coastguard Worker} 160*1fa6dee9SAndroid Build Coastguard Worker 161*1fa6dee9SAndroid Build Coastguard Workerfunc TestContextParse(t *testing.T) { 162*1fa6dee9SAndroid Build Coastguard Worker ctx := NewContext() 163*1fa6dee9SAndroid Build Coastguard Worker ctx.RegisterModuleType("foo_module", newFooModule) 164*1fa6dee9SAndroid Build Coastguard Worker ctx.RegisterModuleType("bar_module", newBarModule) 165*1fa6dee9SAndroid Build Coastguard Worker 166*1fa6dee9SAndroid Build Coastguard Worker r := bytes.NewBufferString(` 167*1fa6dee9SAndroid Build Coastguard Worker foo_module { 168*1fa6dee9SAndroid Build Coastguard Worker name: "MyFooModule", 169*1fa6dee9SAndroid Build Coastguard Worker deps: ["MyBarModule"], 170*1fa6dee9SAndroid Build Coastguard Worker } 171*1fa6dee9SAndroid Build Coastguard Worker 172*1fa6dee9SAndroid Build Coastguard Worker bar_module { 173*1fa6dee9SAndroid Build Coastguard Worker name: "MyBarModule", 174*1fa6dee9SAndroid Build Coastguard Worker } 175*1fa6dee9SAndroid Build Coastguard Worker `) 176*1fa6dee9SAndroid Build Coastguard Worker 177*1fa6dee9SAndroid Build Coastguard Worker _, _, errs := ctx.parseOne(".", "Blueprint", r, parser.NewScope(nil), nil) 178*1fa6dee9SAndroid Build Coastguard Worker if len(errs) > 0 { 179*1fa6dee9SAndroid Build Coastguard Worker t.Errorf("unexpected parse errors:") 180*1fa6dee9SAndroid Build Coastguard Worker for _, err := range errs { 181*1fa6dee9SAndroid Build Coastguard Worker t.Errorf(" %s", err) 182*1fa6dee9SAndroid Build Coastguard Worker } 183*1fa6dee9SAndroid Build Coastguard Worker t.FailNow() 184*1fa6dee9SAndroid Build Coastguard Worker } 185*1fa6dee9SAndroid Build Coastguard Worker 186*1fa6dee9SAndroid Build Coastguard Worker _, errs = ctx.ResolveDependencies(nil) 187*1fa6dee9SAndroid Build Coastguard Worker if len(errs) > 0 { 188*1fa6dee9SAndroid Build Coastguard Worker t.Errorf("unexpected dep errors:") 189*1fa6dee9SAndroid Build Coastguard Worker for _, err := range errs { 190*1fa6dee9SAndroid Build Coastguard Worker t.Errorf(" %s", err) 191*1fa6dee9SAndroid Build Coastguard Worker } 192*1fa6dee9SAndroid Build Coastguard Worker t.FailNow() 193*1fa6dee9SAndroid Build Coastguard Worker } 194*1fa6dee9SAndroid Build Coastguard Worker} 195*1fa6dee9SAndroid Build Coastguard Worker 196*1fa6dee9SAndroid Build Coastguard Worker// > |===B---D - represents a non-walkable edge 197*1fa6dee9SAndroid Build Coastguard Worker// > A = represents a walkable edge 198*1fa6dee9SAndroid Build Coastguard Worker// > |===C===E---G 199*1fa6dee9SAndroid Build Coastguard Worker// > | | A should not be visited because it's the root node. 200*1fa6dee9SAndroid Build Coastguard Worker// > |===F===| B, D and E should not be walked. 201*1fa6dee9SAndroid Build Coastguard Workerfunc TestWalkDeps(t *testing.T) { 202*1fa6dee9SAndroid Build Coastguard Worker ctx := NewContext() 203*1fa6dee9SAndroid Build Coastguard Worker ctx.MockFileSystem(map[string][]byte{ 204*1fa6dee9SAndroid Build Coastguard Worker "Android.bp": []byte(` 205*1fa6dee9SAndroid Build Coastguard Worker foo_module { 206*1fa6dee9SAndroid Build Coastguard Worker name: "A", 207*1fa6dee9SAndroid Build Coastguard Worker deps: ["B", "C"], 208*1fa6dee9SAndroid Build Coastguard Worker } 209*1fa6dee9SAndroid Build Coastguard Worker 210*1fa6dee9SAndroid Build Coastguard Worker bar_module { 211*1fa6dee9SAndroid Build Coastguard Worker name: "B", 212*1fa6dee9SAndroid Build Coastguard Worker deps: ["D"], 213*1fa6dee9SAndroid Build Coastguard Worker } 214*1fa6dee9SAndroid Build Coastguard Worker 215*1fa6dee9SAndroid Build Coastguard Worker foo_module { 216*1fa6dee9SAndroid Build Coastguard Worker name: "C", 217*1fa6dee9SAndroid Build Coastguard Worker deps: ["E", "F"], 218*1fa6dee9SAndroid Build Coastguard Worker } 219*1fa6dee9SAndroid Build Coastguard Worker 220*1fa6dee9SAndroid Build Coastguard Worker foo_module { 221*1fa6dee9SAndroid Build Coastguard Worker name: "D", 222*1fa6dee9SAndroid Build Coastguard Worker } 223*1fa6dee9SAndroid Build Coastguard Worker 224*1fa6dee9SAndroid Build Coastguard Worker bar_module { 225*1fa6dee9SAndroid Build Coastguard Worker name: "E", 226*1fa6dee9SAndroid Build Coastguard Worker deps: ["G"], 227*1fa6dee9SAndroid Build Coastguard Worker } 228*1fa6dee9SAndroid Build Coastguard Worker 229*1fa6dee9SAndroid Build Coastguard Worker foo_module { 230*1fa6dee9SAndroid Build Coastguard Worker name: "F", 231*1fa6dee9SAndroid Build Coastguard Worker deps: ["G"], 232*1fa6dee9SAndroid Build Coastguard Worker } 233*1fa6dee9SAndroid Build Coastguard Worker 234*1fa6dee9SAndroid Build Coastguard Worker foo_module { 235*1fa6dee9SAndroid Build Coastguard Worker name: "G", 236*1fa6dee9SAndroid Build Coastguard Worker } 237*1fa6dee9SAndroid Build Coastguard Worker `), 238*1fa6dee9SAndroid Build Coastguard Worker }) 239*1fa6dee9SAndroid Build Coastguard Worker 240*1fa6dee9SAndroid Build Coastguard Worker ctx.RegisterModuleType("foo_module", newFooModule) 241*1fa6dee9SAndroid Build Coastguard Worker ctx.RegisterModuleType("bar_module", newBarModule) 242*1fa6dee9SAndroid Build Coastguard Worker ctx.RegisterBottomUpMutator("deps", depsMutator) 243*1fa6dee9SAndroid Build Coastguard Worker _, errs := ctx.ParseBlueprintsFiles("Android.bp", nil) 244*1fa6dee9SAndroid Build Coastguard Worker if len(errs) > 0 { 245*1fa6dee9SAndroid Build Coastguard Worker t.Errorf("unexpected parse errors:") 246*1fa6dee9SAndroid Build Coastguard Worker for _, err := range errs { 247*1fa6dee9SAndroid Build Coastguard Worker t.Errorf(" %s", err) 248*1fa6dee9SAndroid Build Coastguard Worker } 249*1fa6dee9SAndroid Build Coastguard Worker t.FailNow() 250*1fa6dee9SAndroid Build Coastguard Worker } 251*1fa6dee9SAndroid Build Coastguard Worker 252*1fa6dee9SAndroid Build Coastguard Worker _, errs = ctx.ResolveDependencies(nil) 253*1fa6dee9SAndroid Build Coastguard Worker if len(errs) > 0 { 254*1fa6dee9SAndroid Build Coastguard Worker t.Errorf("unexpected dep errors:") 255*1fa6dee9SAndroid Build Coastguard Worker for _, err := range errs { 256*1fa6dee9SAndroid Build Coastguard Worker t.Errorf(" %s", err) 257*1fa6dee9SAndroid Build Coastguard Worker } 258*1fa6dee9SAndroid Build Coastguard Worker t.FailNow() 259*1fa6dee9SAndroid Build Coastguard Worker } 260*1fa6dee9SAndroid Build Coastguard Worker 261*1fa6dee9SAndroid Build Coastguard Worker topModule := ctx.moduleGroupFromName("A", nil).modules.firstModule() 262*1fa6dee9SAndroid Build Coastguard Worker outputDown, outputUp := walkDependencyGraph(ctx, topModule, false) 263*1fa6dee9SAndroid Build Coastguard Worker if outputDown != "BCEFG" { 264*1fa6dee9SAndroid Build Coastguard Worker t.Errorf("unexpected walkDeps behaviour: %s\ndown should be: BCEFG", outputDown) 265*1fa6dee9SAndroid Build Coastguard Worker } 266*1fa6dee9SAndroid Build Coastguard Worker if outputUp != "BEGFC" { 267*1fa6dee9SAndroid Build Coastguard Worker t.Errorf("unexpected walkDeps behaviour: %s\nup should be: BEGFC", outputUp) 268*1fa6dee9SAndroid Build Coastguard Worker } 269*1fa6dee9SAndroid Build Coastguard Worker} 270*1fa6dee9SAndroid Build Coastguard Worker 271*1fa6dee9SAndroid Build Coastguard Worker// > |===B---D - represents a non-walkable edge 272*1fa6dee9SAndroid Build Coastguard Worker// > A = represents a walkable edge 273*1fa6dee9SAndroid Build Coastguard Worker// > |===C===E===\ A should not be visited because it's the root node. 274*1fa6dee9SAndroid Build Coastguard Worker// > | | B, D should not be walked. 275*1fa6dee9SAndroid Build Coastguard Worker// > |===F===G===H G should be visited multiple times 276*1fa6dee9SAndroid Build Coastguard Worker// > \===/ H should only be visited once 277*1fa6dee9SAndroid Build Coastguard Workerfunc TestWalkDepsDuplicates(t *testing.T) { 278*1fa6dee9SAndroid Build Coastguard Worker ctx := NewContext() 279*1fa6dee9SAndroid Build Coastguard Worker ctx.MockFileSystem(map[string][]byte{ 280*1fa6dee9SAndroid Build Coastguard Worker "Android.bp": []byte(` 281*1fa6dee9SAndroid Build Coastguard Worker foo_module { 282*1fa6dee9SAndroid Build Coastguard Worker name: "A", 283*1fa6dee9SAndroid Build Coastguard Worker deps: ["B", "C"], 284*1fa6dee9SAndroid Build Coastguard Worker } 285*1fa6dee9SAndroid Build Coastguard Worker 286*1fa6dee9SAndroid Build Coastguard Worker bar_module { 287*1fa6dee9SAndroid Build Coastguard Worker name: "B", 288*1fa6dee9SAndroid Build Coastguard Worker deps: ["D"], 289*1fa6dee9SAndroid Build Coastguard Worker } 290*1fa6dee9SAndroid Build Coastguard Worker 291*1fa6dee9SAndroid Build Coastguard Worker foo_module { 292*1fa6dee9SAndroid Build Coastguard Worker name: "C", 293*1fa6dee9SAndroid Build Coastguard Worker deps: ["E", "F"], 294*1fa6dee9SAndroid Build Coastguard Worker } 295*1fa6dee9SAndroid Build Coastguard Worker 296*1fa6dee9SAndroid Build Coastguard Worker foo_module { 297*1fa6dee9SAndroid Build Coastguard Worker name: "D", 298*1fa6dee9SAndroid Build Coastguard Worker } 299*1fa6dee9SAndroid Build Coastguard Worker 300*1fa6dee9SAndroid Build Coastguard Worker foo_module { 301*1fa6dee9SAndroid Build Coastguard Worker name: "E", 302*1fa6dee9SAndroid Build Coastguard Worker deps: ["G"], 303*1fa6dee9SAndroid Build Coastguard Worker } 304*1fa6dee9SAndroid Build Coastguard Worker 305*1fa6dee9SAndroid Build Coastguard Worker foo_module { 306*1fa6dee9SAndroid Build Coastguard Worker name: "F", 307*1fa6dee9SAndroid Build Coastguard Worker deps: ["G", "G"], 308*1fa6dee9SAndroid Build Coastguard Worker } 309*1fa6dee9SAndroid Build Coastguard Worker 310*1fa6dee9SAndroid Build Coastguard Worker foo_module { 311*1fa6dee9SAndroid Build Coastguard Worker name: "G", 312*1fa6dee9SAndroid Build Coastguard Worker deps: ["H"], 313*1fa6dee9SAndroid Build Coastguard Worker } 314*1fa6dee9SAndroid Build Coastguard Worker 315*1fa6dee9SAndroid Build Coastguard Worker foo_module { 316*1fa6dee9SAndroid Build Coastguard Worker name: "H", 317*1fa6dee9SAndroid Build Coastguard Worker } 318*1fa6dee9SAndroid Build Coastguard Worker `), 319*1fa6dee9SAndroid Build Coastguard Worker }) 320*1fa6dee9SAndroid Build Coastguard Worker 321*1fa6dee9SAndroid Build Coastguard Worker ctx.RegisterModuleType("foo_module", newFooModule) 322*1fa6dee9SAndroid Build Coastguard Worker ctx.RegisterModuleType("bar_module", newBarModule) 323*1fa6dee9SAndroid Build Coastguard Worker ctx.RegisterBottomUpMutator("deps", depsMutator) 324*1fa6dee9SAndroid Build Coastguard Worker _, errs := ctx.ParseBlueprintsFiles("Android.bp", nil) 325*1fa6dee9SAndroid Build Coastguard Worker if len(errs) > 0 { 326*1fa6dee9SAndroid Build Coastguard Worker t.Errorf("unexpected parse errors:") 327*1fa6dee9SAndroid Build Coastguard Worker for _, err := range errs { 328*1fa6dee9SAndroid Build Coastguard Worker t.Errorf(" %s", err) 329*1fa6dee9SAndroid Build Coastguard Worker } 330*1fa6dee9SAndroid Build Coastguard Worker t.FailNow() 331*1fa6dee9SAndroid Build Coastguard Worker } 332*1fa6dee9SAndroid Build Coastguard Worker 333*1fa6dee9SAndroid Build Coastguard Worker _, errs = ctx.ResolveDependencies(nil) 334*1fa6dee9SAndroid Build Coastguard Worker if len(errs) > 0 { 335*1fa6dee9SAndroid Build Coastguard Worker t.Errorf("unexpected dep errors:") 336*1fa6dee9SAndroid Build Coastguard Worker for _, err := range errs { 337*1fa6dee9SAndroid Build Coastguard Worker t.Errorf(" %s", err) 338*1fa6dee9SAndroid Build Coastguard Worker } 339*1fa6dee9SAndroid Build Coastguard Worker t.FailNow() 340*1fa6dee9SAndroid Build Coastguard Worker } 341*1fa6dee9SAndroid Build Coastguard Worker 342*1fa6dee9SAndroid Build Coastguard Worker topModule := ctx.moduleGroupFromName("A", nil).modules.firstModule() 343*1fa6dee9SAndroid Build Coastguard Worker outputDown, outputUp := walkDependencyGraph(ctx, topModule, true) 344*1fa6dee9SAndroid Build Coastguard Worker if outputDown != "BCEGHFGG" { 345*1fa6dee9SAndroid Build Coastguard Worker t.Errorf("unexpected walkDeps behaviour: %s\ndown should be: BCEGHFGG", outputDown) 346*1fa6dee9SAndroid Build Coastguard Worker } 347*1fa6dee9SAndroid Build Coastguard Worker if outputUp != "BHGEGGFC" { 348*1fa6dee9SAndroid Build Coastguard Worker t.Errorf("unexpected walkDeps behaviour: %s\nup should be: BHGEGGFC", outputUp) 349*1fa6dee9SAndroid Build Coastguard Worker } 350*1fa6dee9SAndroid Build Coastguard Worker} 351*1fa6dee9SAndroid Build Coastguard Worker 352*1fa6dee9SAndroid Build Coastguard Worker// > - represents a non-walkable edge 353*1fa6dee9SAndroid Build Coastguard Worker// > A = represents a walkable edge 354*1fa6dee9SAndroid Build Coastguard Worker// > |===B-------\ A should not be visited because it's the root node. 355*1fa6dee9SAndroid Build Coastguard Worker// > | | B -> D should not be walked. 356*1fa6dee9SAndroid Build Coastguard Worker// > |===C===D===E B -> C -> D -> E should be walked 357*1fa6dee9SAndroid Build Coastguard Workerfunc TestWalkDepsDuplicates_IgnoreFirstPath(t *testing.T) { 358*1fa6dee9SAndroid Build Coastguard Worker ctx := NewContext() 359*1fa6dee9SAndroid Build Coastguard Worker ctx.MockFileSystem(map[string][]byte{ 360*1fa6dee9SAndroid Build Coastguard Worker "Android.bp": []byte(` 361*1fa6dee9SAndroid Build Coastguard Worker foo_module { 362*1fa6dee9SAndroid Build Coastguard Worker name: "A", 363*1fa6dee9SAndroid Build Coastguard Worker deps: ["B"], 364*1fa6dee9SAndroid Build Coastguard Worker } 365*1fa6dee9SAndroid Build Coastguard Worker 366*1fa6dee9SAndroid Build Coastguard Worker foo_module { 367*1fa6dee9SAndroid Build Coastguard Worker name: "B", 368*1fa6dee9SAndroid Build Coastguard Worker deps: ["C"], 369*1fa6dee9SAndroid Build Coastguard Worker ignored_deps: ["D"], 370*1fa6dee9SAndroid Build Coastguard Worker } 371*1fa6dee9SAndroid Build Coastguard Worker 372*1fa6dee9SAndroid Build Coastguard Worker foo_module { 373*1fa6dee9SAndroid Build Coastguard Worker name: "C", 374*1fa6dee9SAndroid Build Coastguard Worker deps: ["D"], 375*1fa6dee9SAndroid Build Coastguard Worker } 376*1fa6dee9SAndroid Build Coastguard Worker 377*1fa6dee9SAndroid Build Coastguard Worker foo_module { 378*1fa6dee9SAndroid Build Coastguard Worker name: "D", 379*1fa6dee9SAndroid Build Coastguard Worker deps: ["E"], 380*1fa6dee9SAndroid Build Coastguard Worker } 381*1fa6dee9SAndroid Build Coastguard Worker 382*1fa6dee9SAndroid Build Coastguard Worker foo_module { 383*1fa6dee9SAndroid Build Coastguard Worker name: "E", 384*1fa6dee9SAndroid Build Coastguard Worker } 385*1fa6dee9SAndroid Build Coastguard Worker `), 386*1fa6dee9SAndroid Build Coastguard Worker }) 387*1fa6dee9SAndroid Build Coastguard Worker 388*1fa6dee9SAndroid Build Coastguard Worker ctx.RegisterModuleType("foo_module", newFooModule) 389*1fa6dee9SAndroid Build Coastguard Worker ctx.RegisterModuleType("bar_module", newBarModule) 390*1fa6dee9SAndroid Build Coastguard Worker ctx.RegisterBottomUpMutator("deps", depsMutator) 391*1fa6dee9SAndroid Build Coastguard Worker _, errs := ctx.ParseBlueprintsFiles("Android.bp", nil) 392*1fa6dee9SAndroid Build Coastguard Worker if len(errs) > 0 { 393*1fa6dee9SAndroid Build Coastguard Worker t.Errorf("unexpected parse errors:") 394*1fa6dee9SAndroid Build Coastguard Worker for _, err := range errs { 395*1fa6dee9SAndroid Build Coastguard Worker t.Errorf(" %s", err) 396*1fa6dee9SAndroid Build Coastguard Worker } 397*1fa6dee9SAndroid Build Coastguard Worker t.FailNow() 398*1fa6dee9SAndroid Build Coastguard Worker } 399*1fa6dee9SAndroid Build Coastguard Worker 400*1fa6dee9SAndroid Build Coastguard Worker _, errs = ctx.ResolveDependencies(nil) 401*1fa6dee9SAndroid Build Coastguard Worker if len(errs) > 0 { 402*1fa6dee9SAndroid Build Coastguard Worker t.Errorf("unexpected dep errors:") 403*1fa6dee9SAndroid Build Coastguard Worker for _, err := range errs { 404*1fa6dee9SAndroid Build Coastguard Worker t.Errorf(" %s", err) 405*1fa6dee9SAndroid Build Coastguard Worker } 406*1fa6dee9SAndroid Build Coastguard Worker t.FailNow() 407*1fa6dee9SAndroid Build Coastguard Worker } 408*1fa6dee9SAndroid Build Coastguard Worker 409*1fa6dee9SAndroid Build Coastguard Worker topModule := ctx.moduleGroupFromName("A", nil).modules.firstModule() 410*1fa6dee9SAndroid Build Coastguard Worker outputDown, outputUp := walkDependencyGraph(ctx, topModule, true) 411*1fa6dee9SAndroid Build Coastguard Worker expectedDown := "BDCDE" 412*1fa6dee9SAndroid Build Coastguard Worker if outputDown != expectedDown { 413*1fa6dee9SAndroid Build Coastguard Worker t.Errorf("unexpected walkDeps behaviour: %s\ndown should be: %s", outputDown, expectedDown) 414*1fa6dee9SAndroid Build Coastguard Worker } 415*1fa6dee9SAndroid Build Coastguard Worker expectedUp := "DEDCB" 416*1fa6dee9SAndroid Build Coastguard Worker if outputUp != expectedUp { 417*1fa6dee9SAndroid Build Coastguard Worker t.Errorf("unexpected walkDeps behaviour: %s\nup should be: %s", outputUp, expectedUp) 418*1fa6dee9SAndroid Build Coastguard Worker } 419*1fa6dee9SAndroid Build Coastguard Worker} 420*1fa6dee9SAndroid Build Coastguard Worker 421*1fa6dee9SAndroid Build Coastguard Workerfunc TestCreateModule(t *testing.T) { 422*1fa6dee9SAndroid Build Coastguard Worker ctx := newContext() 423*1fa6dee9SAndroid Build Coastguard Worker ctx.MockFileSystem(map[string][]byte{ 424*1fa6dee9SAndroid Build Coastguard Worker "Android.bp": []byte(` 425*1fa6dee9SAndroid Build Coastguard Worker foo_module { 426*1fa6dee9SAndroid Build Coastguard Worker name: "A", 427*1fa6dee9SAndroid Build Coastguard Worker deps: ["B", "C"], 428*1fa6dee9SAndroid Build Coastguard Worker } 429*1fa6dee9SAndroid Build Coastguard Worker `), 430*1fa6dee9SAndroid Build Coastguard Worker }) 431*1fa6dee9SAndroid Build Coastguard Worker 432*1fa6dee9SAndroid Build Coastguard Worker ctx.RegisterBottomUpMutator("create", createTestMutator).UsesCreateModule() 433*1fa6dee9SAndroid Build Coastguard Worker ctx.RegisterBottomUpMutator("deps", depsMutator) 434*1fa6dee9SAndroid Build Coastguard Worker 435*1fa6dee9SAndroid Build Coastguard Worker ctx.RegisterModuleType("foo_module", newFooModule) 436*1fa6dee9SAndroid Build Coastguard Worker ctx.RegisterModuleType("bar_module", newBarModule) 437*1fa6dee9SAndroid Build Coastguard Worker _, errs := ctx.ParseBlueprintsFiles("Android.bp", nil) 438*1fa6dee9SAndroid Build Coastguard Worker if len(errs) > 0 { 439*1fa6dee9SAndroid Build Coastguard Worker t.Errorf("unexpected parse errors:") 440*1fa6dee9SAndroid Build Coastguard Worker for _, err := range errs { 441*1fa6dee9SAndroid Build Coastguard Worker t.Errorf(" %s", err) 442*1fa6dee9SAndroid Build Coastguard Worker } 443*1fa6dee9SAndroid Build Coastguard Worker t.FailNow() 444*1fa6dee9SAndroid Build Coastguard Worker } 445*1fa6dee9SAndroid Build Coastguard Worker 446*1fa6dee9SAndroid Build Coastguard Worker _, errs = ctx.ResolveDependencies(nil) 447*1fa6dee9SAndroid Build Coastguard Worker if len(errs) > 0 { 448*1fa6dee9SAndroid Build Coastguard Worker t.Errorf("unexpected dep errors:") 449*1fa6dee9SAndroid Build Coastguard Worker for _, err := range errs { 450*1fa6dee9SAndroid Build Coastguard Worker t.Errorf(" %s", err) 451*1fa6dee9SAndroid Build Coastguard Worker } 452*1fa6dee9SAndroid Build Coastguard Worker t.FailNow() 453*1fa6dee9SAndroid Build Coastguard Worker } 454*1fa6dee9SAndroid Build Coastguard Worker 455*1fa6dee9SAndroid Build Coastguard Worker a := ctx.moduleGroupFromName("A", nil).modules.firstModule().logicModule.(*fooModule) 456*1fa6dee9SAndroid Build Coastguard Worker b := ctx.moduleGroupFromName("B", nil).modules.firstModule().logicModule.(*barModule) 457*1fa6dee9SAndroid Build Coastguard Worker c := ctx.moduleGroupFromName("C", nil).modules.firstModule().logicModule.(*barModule) 458*1fa6dee9SAndroid Build Coastguard Worker d := ctx.moduleGroupFromName("D", nil).modules.firstModule().logicModule.(*fooModule) 459*1fa6dee9SAndroid Build Coastguard Worker 460*1fa6dee9SAndroid Build Coastguard Worker checkDeps := func(m Module, expected string) { 461*1fa6dee9SAndroid Build Coastguard Worker var deps []string 462*1fa6dee9SAndroid Build Coastguard Worker ctx.VisitDirectDeps(m, func(m Module) { 463*1fa6dee9SAndroid Build Coastguard Worker deps = append(deps, ctx.ModuleName(m)) 464*1fa6dee9SAndroid Build Coastguard Worker }) 465*1fa6dee9SAndroid Build Coastguard Worker got := strings.Join(deps, ",") 466*1fa6dee9SAndroid Build Coastguard Worker if got != expected { 467*1fa6dee9SAndroid Build Coastguard Worker t.Errorf("unexpected %q dependencies, got %q expected %q", 468*1fa6dee9SAndroid Build Coastguard Worker ctx.ModuleName(m), got, expected) 469*1fa6dee9SAndroid Build Coastguard Worker } 470*1fa6dee9SAndroid Build Coastguard Worker } 471*1fa6dee9SAndroid Build Coastguard Worker 472*1fa6dee9SAndroid Build Coastguard Worker checkDeps(a, "B,C") 473*1fa6dee9SAndroid Build Coastguard Worker checkDeps(b, "D") 474*1fa6dee9SAndroid Build Coastguard Worker checkDeps(c, "D") 475*1fa6dee9SAndroid Build Coastguard Worker checkDeps(d, "") 476*1fa6dee9SAndroid Build Coastguard Worker} 477*1fa6dee9SAndroid Build Coastguard Worker 478*1fa6dee9SAndroid Build Coastguard Workerfunc createTestMutator(ctx BottomUpMutatorContext) { 479*1fa6dee9SAndroid Build Coastguard Worker type props struct { 480*1fa6dee9SAndroid Build Coastguard Worker Name string 481*1fa6dee9SAndroid Build Coastguard Worker Deps []string 482*1fa6dee9SAndroid Build Coastguard Worker } 483*1fa6dee9SAndroid Build Coastguard Worker 484*1fa6dee9SAndroid Build Coastguard Worker ctx.CreateModule(newBarModule, "new_bar", &props{ 485*1fa6dee9SAndroid Build Coastguard Worker Name: "B", 486*1fa6dee9SAndroid Build Coastguard Worker Deps: []string{"D"}, 487*1fa6dee9SAndroid Build Coastguard Worker }) 488*1fa6dee9SAndroid Build Coastguard Worker 489*1fa6dee9SAndroid Build Coastguard Worker ctx.CreateModule(newBarModule, "new_bar", &props{ 490*1fa6dee9SAndroid Build Coastguard Worker Name: "C", 491*1fa6dee9SAndroid Build Coastguard Worker Deps: []string{"D"}, 492*1fa6dee9SAndroid Build Coastguard Worker }) 493*1fa6dee9SAndroid Build Coastguard Worker 494*1fa6dee9SAndroid Build Coastguard Worker ctx.CreateModule(newFooModule, "new_foo", &props{ 495*1fa6dee9SAndroid Build Coastguard Worker Name: "D", 496*1fa6dee9SAndroid Build Coastguard Worker }) 497*1fa6dee9SAndroid Build Coastguard Worker} 498*1fa6dee9SAndroid Build Coastguard Worker 499*1fa6dee9SAndroid Build Coastguard Workerfunc TestWalkFileOrder(t *testing.T) { 500*1fa6dee9SAndroid Build Coastguard Worker // Run the test once to see how long it normally takes 501*1fa6dee9SAndroid Build Coastguard Worker start := time.Now() 502*1fa6dee9SAndroid Build Coastguard Worker doTestWalkFileOrder(t, time.Duration(0)) 503*1fa6dee9SAndroid Build Coastguard Worker duration := time.Since(start) 504*1fa6dee9SAndroid Build Coastguard Worker 505*1fa6dee9SAndroid Build Coastguard Worker // Run the test again, but put enough of a sleep into each visitor to detect ordering 506*1fa6dee9SAndroid Build Coastguard Worker // problems if they exist 507*1fa6dee9SAndroid Build Coastguard Worker doTestWalkFileOrder(t, duration) 508*1fa6dee9SAndroid Build Coastguard Worker} 509*1fa6dee9SAndroid Build Coastguard Worker 510*1fa6dee9SAndroid Build Coastguard Worker// test that WalkBlueprintsFiles calls asyncVisitor in the right order 511*1fa6dee9SAndroid Build Coastguard Workerfunc doTestWalkFileOrder(t *testing.T, sleepDuration time.Duration) { 512*1fa6dee9SAndroid Build Coastguard Worker // setup mock context 513*1fa6dee9SAndroid Build Coastguard Worker ctx := newContext() 514*1fa6dee9SAndroid Build Coastguard Worker mockFiles := map[string][]byte{ 515*1fa6dee9SAndroid Build Coastguard Worker "Android.bp": []byte(` 516*1fa6dee9SAndroid Build Coastguard Worker sample_module { 517*1fa6dee9SAndroid Build Coastguard Worker name: "a", 518*1fa6dee9SAndroid Build Coastguard Worker } 519*1fa6dee9SAndroid Build Coastguard Worker `), 520*1fa6dee9SAndroid Build Coastguard Worker "dir1/Android.bp": []byte(` 521*1fa6dee9SAndroid Build Coastguard Worker sample_module { 522*1fa6dee9SAndroid Build Coastguard Worker name: "b", 523*1fa6dee9SAndroid Build Coastguard Worker } 524*1fa6dee9SAndroid Build Coastguard Worker `), 525*1fa6dee9SAndroid Build Coastguard Worker "dir1/dir2/Android.bp": []byte(` 526*1fa6dee9SAndroid Build Coastguard Worker sample_module { 527*1fa6dee9SAndroid Build Coastguard Worker name: "c", 528*1fa6dee9SAndroid Build Coastguard Worker } 529*1fa6dee9SAndroid Build Coastguard Worker `), 530*1fa6dee9SAndroid Build Coastguard Worker } 531*1fa6dee9SAndroid Build Coastguard Worker ctx.MockFileSystem(mockFiles) 532*1fa6dee9SAndroid Build Coastguard Worker 533*1fa6dee9SAndroid Build Coastguard Worker // prepare to monitor the visit order 534*1fa6dee9SAndroid Build Coastguard Worker visitOrder := []string{} 535*1fa6dee9SAndroid Build Coastguard Worker visitLock := sync.Mutex{} 536*1fa6dee9SAndroid Build Coastguard Worker correctVisitOrder := []string{"Android.bp", "dir1/Android.bp", "dir1/dir2/Android.bp"} 537*1fa6dee9SAndroid Build Coastguard Worker 538*1fa6dee9SAndroid Build Coastguard Worker // sleep longer when processing the earlier files 539*1fa6dee9SAndroid Build Coastguard Worker chooseSleepDuration := func(fileName string) (duration time.Duration) { 540*1fa6dee9SAndroid Build Coastguard Worker duration = time.Duration(0) 541*1fa6dee9SAndroid Build Coastguard Worker for i := len(correctVisitOrder) - 1; i >= 0; i-- { 542*1fa6dee9SAndroid Build Coastguard Worker if fileName == correctVisitOrder[i] { 543*1fa6dee9SAndroid Build Coastguard Worker return duration 544*1fa6dee9SAndroid Build Coastguard Worker } 545*1fa6dee9SAndroid Build Coastguard Worker duration = duration + sleepDuration 546*1fa6dee9SAndroid Build Coastguard Worker } 547*1fa6dee9SAndroid Build Coastguard Worker panic("unrecognized file name " + fileName) 548*1fa6dee9SAndroid Build Coastguard Worker } 549*1fa6dee9SAndroid Build Coastguard Worker 550*1fa6dee9SAndroid Build Coastguard Worker visitor := func(file *parser.File) { 551*1fa6dee9SAndroid Build Coastguard Worker time.Sleep(chooseSleepDuration(file.Name)) 552*1fa6dee9SAndroid Build Coastguard Worker visitLock.Lock() 553*1fa6dee9SAndroid Build Coastguard Worker defer visitLock.Unlock() 554*1fa6dee9SAndroid Build Coastguard Worker visitOrder = append(visitOrder, file.Name) 555*1fa6dee9SAndroid Build Coastguard Worker } 556*1fa6dee9SAndroid Build Coastguard Worker keys := []string{"Android.bp", "dir1/Android.bp", "dir1/dir2/Android.bp"} 557*1fa6dee9SAndroid Build Coastguard Worker 558*1fa6dee9SAndroid Build Coastguard Worker // visit the blueprints files 559*1fa6dee9SAndroid Build Coastguard Worker ctx.WalkBlueprintsFiles(".", keys, visitor) 560*1fa6dee9SAndroid Build Coastguard Worker 561*1fa6dee9SAndroid Build Coastguard Worker // check the order 562*1fa6dee9SAndroid Build Coastguard Worker if !reflect.DeepEqual(visitOrder, correctVisitOrder) { 563*1fa6dee9SAndroid Build Coastguard Worker t.Errorf("Incorrect visit order; expected %v, got %v", correctVisitOrder, visitOrder) 564*1fa6dee9SAndroid Build Coastguard Worker } 565*1fa6dee9SAndroid Build Coastguard Worker} 566*1fa6dee9SAndroid Build Coastguard Worker 567*1fa6dee9SAndroid Build Coastguard Worker// test that WalkBlueprintsFiles reports syntax errors 568*1fa6dee9SAndroid Build Coastguard Workerfunc TestWalkingWithSyntaxError(t *testing.T) { 569*1fa6dee9SAndroid Build Coastguard Worker // setup mock context 570*1fa6dee9SAndroid Build Coastguard Worker ctx := newContext() 571*1fa6dee9SAndroid Build Coastguard Worker mockFiles := map[string][]byte{ 572*1fa6dee9SAndroid Build Coastguard Worker "Android.bp": []byte(` 573*1fa6dee9SAndroid Build Coastguard Worker sample_module { 574*1fa6dee9SAndroid Build Coastguard Worker name: "a" "b", 575*1fa6dee9SAndroid Build Coastguard Worker } 576*1fa6dee9SAndroid Build Coastguard Worker `), 577*1fa6dee9SAndroid Build Coastguard Worker "dir1/Android.bp": []byte(` 578*1fa6dee9SAndroid Build Coastguard Worker sample_module { 579*1fa6dee9SAndroid Build Coastguard Worker name: "b", 580*1fa6dee9SAndroid Build Coastguard Worker `), 581*1fa6dee9SAndroid Build Coastguard Worker "dir1/dir2/Android.bp": []byte(` 582*1fa6dee9SAndroid Build Coastguard Worker sample_module { 583*1fa6dee9SAndroid Build Coastguard Worker name: "c", 584*1fa6dee9SAndroid Build Coastguard Worker } 585*1fa6dee9SAndroid Build Coastguard Worker `), 586*1fa6dee9SAndroid Build Coastguard Worker } 587*1fa6dee9SAndroid Build Coastguard Worker ctx.MockFileSystem(mockFiles) 588*1fa6dee9SAndroid Build Coastguard Worker 589*1fa6dee9SAndroid Build Coastguard Worker keys := []string{"Android.bp", "dir1/Android.bp", "dir1/dir2/Android.bp"} 590*1fa6dee9SAndroid Build Coastguard Worker 591*1fa6dee9SAndroid Build Coastguard Worker // visit the blueprints files 592*1fa6dee9SAndroid Build Coastguard Worker _, errs := ctx.WalkBlueprintsFiles(".", keys, func(file *parser.File) {}) 593*1fa6dee9SAndroid Build Coastguard Worker 594*1fa6dee9SAndroid Build Coastguard Worker expectedErrs := []error{ 595*1fa6dee9SAndroid Build Coastguard Worker errors.New(`Android.bp:3:18: expected "}", found String`), 596*1fa6dee9SAndroid Build Coastguard Worker errors.New(`dir1/Android.bp:4:3: expected "}", found EOF`), 597*1fa6dee9SAndroid Build Coastguard Worker } 598*1fa6dee9SAndroid Build Coastguard Worker if fmt.Sprintf("%s", expectedErrs) != fmt.Sprintf("%s", errs) { 599*1fa6dee9SAndroid Build Coastguard Worker t.Errorf("Incorrect errors; expected:\n%s\ngot:\n%s", expectedErrs, errs) 600*1fa6dee9SAndroid Build Coastguard Worker } 601*1fa6dee9SAndroid Build Coastguard Worker 602*1fa6dee9SAndroid Build Coastguard Worker} 603*1fa6dee9SAndroid Build Coastguard Worker 604*1fa6dee9SAndroid Build Coastguard Workerfunc TestParseFailsForModuleWithoutName(t *testing.T) { 605*1fa6dee9SAndroid Build Coastguard Worker ctx := NewContext() 606*1fa6dee9SAndroid Build Coastguard Worker ctx.MockFileSystem(map[string][]byte{ 607*1fa6dee9SAndroid Build Coastguard Worker "Android.bp": []byte(` 608*1fa6dee9SAndroid Build Coastguard Worker foo_module { 609*1fa6dee9SAndroid Build Coastguard Worker name: "A", 610*1fa6dee9SAndroid Build Coastguard Worker } 611*1fa6dee9SAndroid Build Coastguard Worker 612*1fa6dee9SAndroid Build Coastguard Worker bar_module { 613*1fa6dee9SAndroid Build Coastguard Worker deps: ["A"], 614*1fa6dee9SAndroid Build Coastguard Worker } 615*1fa6dee9SAndroid Build Coastguard Worker `), 616*1fa6dee9SAndroid Build Coastguard Worker }) 617*1fa6dee9SAndroid Build Coastguard Worker ctx.RegisterModuleType("foo_module", newFooModule) 618*1fa6dee9SAndroid Build Coastguard Worker ctx.RegisterModuleType("bar_module", newBarModule) 619*1fa6dee9SAndroid Build Coastguard Worker 620*1fa6dee9SAndroid Build Coastguard Worker _, errs := ctx.ParseBlueprintsFiles("Android.bp", nil) 621*1fa6dee9SAndroid Build Coastguard Worker 622*1fa6dee9SAndroid Build Coastguard Worker expectedErrs := []error{ 623*1fa6dee9SAndroid Build Coastguard Worker errors.New(`Android.bp:6:4: property 'name' is missing from a module`), 624*1fa6dee9SAndroid Build Coastguard Worker } 625*1fa6dee9SAndroid Build Coastguard Worker if fmt.Sprintf("%s", expectedErrs) != fmt.Sprintf("%s", errs) { 626*1fa6dee9SAndroid Build Coastguard Worker t.Errorf("Incorrect errors; expected:\n%s\ngot:\n%s", expectedErrs, errs) 627*1fa6dee9SAndroid Build Coastguard Worker } 628*1fa6dee9SAndroid Build Coastguard Worker} 629*1fa6dee9SAndroid Build Coastguard Worker 630*1fa6dee9SAndroid Build Coastguard Workerfunc Test_findVariant(t *testing.T) { 631*1fa6dee9SAndroid Build Coastguard Worker module := &moduleInfo{ 632*1fa6dee9SAndroid Build Coastguard Worker variant: variant{ 633*1fa6dee9SAndroid Build Coastguard Worker name: "normal_local", 634*1fa6dee9SAndroid Build Coastguard Worker variations: variationMap{ 635*1fa6dee9SAndroid Build Coastguard Worker map[string]string{ 636*1fa6dee9SAndroid Build Coastguard Worker "normal": "normal", 637*1fa6dee9SAndroid Build Coastguard Worker }, 638*1fa6dee9SAndroid Build Coastguard Worker }, 639*1fa6dee9SAndroid Build Coastguard Worker }, 640*1fa6dee9SAndroid Build Coastguard Worker } 641*1fa6dee9SAndroid Build Coastguard Worker 642*1fa6dee9SAndroid Build Coastguard Worker type alias struct { 643*1fa6dee9SAndroid Build Coastguard Worker variant variant 644*1fa6dee9SAndroid Build Coastguard Worker target int 645*1fa6dee9SAndroid Build Coastguard Worker } 646*1fa6dee9SAndroid Build Coastguard Worker 647*1fa6dee9SAndroid Build Coastguard Worker makeDependencyGroup := func(in ...*moduleInfo) *moduleGroup { 648*1fa6dee9SAndroid Build Coastguard Worker group := &moduleGroup{ 649*1fa6dee9SAndroid Build Coastguard Worker name: "dep", 650*1fa6dee9SAndroid Build Coastguard Worker } 651*1fa6dee9SAndroid Build Coastguard Worker for _, m := range in { 652*1fa6dee9SAndroid Build Coastguard Worker m.group = group 653*1fa6dee9SAndroid Build Coastguard Worker group.modules = append(group.modules, m) 654*1fa6dee9SAndroid Build Coastguard Worker } 655*1fa6dee9SAndroid Build Coastguard Worker return group 656*1fa6dee9SAndroid Build Coastguard Worker } 657*1fa6dee9SAndroid Build Coastguard Worker 658*1fa6dee9SAndroid Build Coastguard Worker tests := []struct { 659*1fa6dee9SAndroid Build Coastguard Worker name string 660*1fa6dee9SAndroid Build Coastguard Worker possibleDeps *moduleGroup 661*1fa6dee9SAndroid Build Coastguard Worker variations []Variation 662*1fa6dee9SAndroid Build Coastguard Worker far bool 663*1fa6dee9SAndroid Build Coastguard Worker reverse bool 664*1fa6dee9SAndroid Build Coastguard Worker want string 665*1fa6dee9SAndroid Build Coastguard Worker }{ 666*1fa6dee9SAndroid Build Coastguard Worker { 667*1fa6dee9SAndroid Build Coastguard Worker name: "AddVariationDependencies(nil)", 668*1fa6dee9SAndroid Build Coastguard Worker // A dependency that matches the non-local variations of the module 669*1fa6dee9SAndroid Build Coastguard Worker possibleDeps: makeDependencyGroup( 670*1fa6dee9SAndroid Build Coastguard Worker &moduleInfo{ 671*1fa6dee9SAndroid Build Coastguard Worker variant: variant{ 672*1fa6dee9SAndroid Build Coastguard Worker name: "normal", 673*1fa6dee9SAndroid Build Coastguard Worker variations: variationMap{ 674*1fa6dee9SAndroid Build Coastguard Worker map[string]string{ 675*1fa6dee9SAndroid Build Coastguard Worker "normal": "normal", 676*1fa6dee9SAndroid Build Coastguard Worker }, 677*1fa6dee9SAndroid Build Coastguard Worker }, 678*1fa6dee9SAndroid Build Coastguard Worker }, 679*1fa6dee9SAndroid Build Coastguard Worker }, 680*1fa6dee9SAndroid Build Coastguard Worker ), 681*1fa6dee9SAndroid Build Coastguard Worker variations: nil, 682*1fa6dee9SAndroid Build Coastguard Worker far: false, 683*1fa6dee9SAndroid Build Coastguard Worker reverse: false, 684*1fa6dee9SAndroid Build Coastguard Worker want: "normal", 685*1fa6dee9SAndroid Build Coastguard Worker }, 686*1fa6dee9SAndroid Build Coastguard Worker { 687*1fa6dee9SAndroid Build Coastguard Worker name: "AddVariationDependencies(a)", 688*1fa6dee9SAndroid Build Coastguard Worker // A dependency with local variations 689*1fa6dee9SAndroid Build Coastguard Worker possibleDeps: makeDependencyGroup( 690*1fa6dee9SAndroid Build Coastguard Worker &moduleInfo{ 691*1fa6dee9SAndroid Build Coastguard Worker variant: variant{ 692*1fa6dee9SAndroid Build Coastguard Worker name: "normal_a", 693*1fa6dee9SAndroid Build Coastguard Worker variations: variationMap{ 694*1fa6dee9SAndroid Build Coastguard Worker map[string]string{ 695*1fa6dee9SAndroid Build Coastguard Worker "normal": "normal", 696*1fa6dee9SAndroid Build Coastguard Worker "a": "a", 697*1fa6dee9SAndroid Build Coastguard Worker }, 698*1fa6dee9SAndroid Build Coastguard Worker }, 699*1fa6dee9SAndroid Build Coastguard Worker }, 700*1fa6dee9SAndroid Build Coastguard Worker }, 701*1fa6dee9SAndroid Build Coastguard Worker ), 702*1fa6dee9SAndroid Build Coastguard Worker variations: []Variation{{"a", "a"}}, 703*1fa6dee9SAndroid Build Coastguard Worker far: false, 704*1fa6dee9SAndroid Build Coastguard Worker reverse: false, 705*1fa6dee9SAndroid Build Coastguard Worker want: "normal_a", 706*1fa6dee9SAndroid Build Coastguard Worker }, 707*1fa6dee9SAndroid Build Coastguard Worker { 708*1fa6dee9SAndroid Build Coastguard Worker name: "AddFarVariationDependencies(far)", 709*1fa6dee9SAndroid Build Coastguard Worker // A dependency with far variations 710*1fa6dee9SAndroid Build Coastguard Worker possibleDeps: makeDependencyGroup( 711*1fa6dee9SAndroid Build Coastguard Worker &moduleInfo{ 712*1fa6dee9SAndroid Build Coastguard Worker variant: variant{ 713*1fa6dee9SAndroid Build Coastguard Worker name: "", 714*1fa6dee9SAndroid Build Coastguard Worker variations: variationMap{}, 715*1fa6dee9SAndroid Build Coastguard Worker }, 716*1fa6dee9SAndroid Build Coastguard Worker }, 717*1fa6dee9SAndroid Build Coastguard Worker &moduleInfo{ 718*1fa6dee9SAndroid Build Coastguard Worker variant: variant{ 719*1fa6dee9SAndroid Build Coastguard Worker name: "far", 720*1fa6dee9SAndroid Build Coastguard Worker variations: variationMap{ 721*1fa6dee9SAndroid Build Coastguard Worker map[string]string{ 722*1fa6dee9SAndroid Build Coastguard Worker "far": "far", 723*1fa6dee9SAndroid Build Coastguard Worker }, 724*1fa6dee9SAndroid Build Coastguard Worker }, 725*1fa6dee9SAndroid Build Coastguard Worker }, 726*1fa6dee9SAndroid Build Coastguard Worker }, 727*1fa6dee9SAndroid Build Coastguard Worker ), 728*1fa6dee9SAndroid Build Coastguard Worker variations: []Variation{{"far", "far"}}, 729*1fa6dee9SAndroid Build Coastguard Worker far: true, 730*1fa6dee9SAndroid Build Coastguard Worker reverse: false, 731*1fa6dee9SAndroid Build Coastguard Worker want: "far", 732*1fa6dee9SAndroid Build Coastguard Worker }, 733*1fa6dee9SAndroid Build Coastguard Worker } 734*1fa6dee9SAndroid Build Coastguard Worker for _, tt := range tests { 735*1fa6dee9SAndroid Build Coastguard Worker t.Run(tt.name, func(t *testing.T) { 736*1fa6dee9SAndroid Build Coastguard Worker ctx := NewContext() 737*1fa6dee9SAndroid Build Coastguard Worker got, _, errs := ctx.findVariant(module, nil, tt.possibleDeps, tt.variations, tt.far, tt.reverse) 738*1fa6dee9SAndroid Build Coastguard Worker if errs != nil { 739*1fa6dee9SAndroid Build Coastguard Worker t.Fatal(errs) 740*1fa6dee9SAndroid Build Coastguard Worker } 741*1fa6dee9SAndroid Build Coastguard Worker if g, w := got == nil, tt.want == "nil"; g != w { 742*1fa6dee9SAndroid Build Coastguard Worker t.Fatalf("findVariant() got = %v, want %v", got, tt.want) 743*1fa6dee9SAndroid Build Coastguard Worker } 744*1fa6dee9SAndroid Build Coastguard Worker if got != nil { 745*1fa6dee9SAndroid Build Coastguard Worker if g, w := got.String(), fmt.Sprintf("module %q variant %q", "dep", tt.want); g != w { 746*1fa6dee9SAndroid Build Coastguard Worker t.Errorf("findVariant() got = %v, want %v", g, w) 747*1fa6dee9SAndroid Build Coastguard Worker } 748*1fa6dee9SAndroid Build Coastguard Worker } 749*1fa6dee9SAndroid Build Coastguard Worker }) 750*1fa6dee9SAndroid Build Coastguard Worker } 751*1fa6dee9SAndroid Build Coastguard Worker} 752*1fa6dee9SAndroid Build Coastguard Worker 753*1fa6dee9SAndroid Build Coastguard Workerfunc Test_parallelVisit(t *testing.T) { 754*1fa6dee9SAndroid Build Coastguard Worker addDep := func(from, to *moduleInfo) { 755*1fa6dee9SAndroid Build Coastguard Worker from.directDeps = append(from.directDeps, depInfo{to, nil}) 756*1fa6dee9SAndroid Build Coastguard Worker from.forwardDeps = append(from.forwardDeps, to) 757*1fa6dee9SAndroid Build Coastguard Worker to.reverseDeps = append(to.reverseDeps, from) 758*1fa6dee9SAndroid Build Coastguard Worker } 759*1fa6dee9SAndroid Build Coastguard Worker 760*1fa6dee9SAndroid Build Coastguard Worker create := func(name string) *moduleInfo { 761*1fa6dee9SAndroid Build Coastguard Worker m := &moduleInfo{ 762*1fa6dee9SAndroid Build Coastguard Worker group: &moduleGroup{ 763*1fa6dee9SAndroid Build Coastguard Worker name: name, 764*1fa6dee9SAndroid Build Coastguard Worker }, 765*1fa6dee9SAndroid Build Coastguard Worker } 766*1fa6dee9SAndroid Build Coastguard Worker m.group.modules = moduleList{m} 767*1fa6dee9SAndroid Build Coastguard Worker return m 768*1fa6dee9SAndroid Build Coastguard Worker } 769*1fa6dee9SAndroid Build Coastguard Worker moduleA := create("A") 770*1fa6dee9SAndroid Build Coastguard Worker moduleB := create("B") 771*1fa6dee9SAndroid Build Coastguard Worker moduleC := create("C") 772*1fa6dee9SAndroid Build Coastguard Worker moduleD := create("D") 773*1fa6dee9SAndroid Build Coastguard Worker moduleE := create("E") 774*1fa6dee9SAndroid Build Coastguard Worker moduleF := create("F") 775*1fa6dee9SAndroid Build Coastguard Worker moduleG := create("G") 776*1fa6dee9SAndroid Build Coastguard Worker 777*1fa6dee9SAndroid Build Coastguard Worker // A depends on B, B depends on C. Nothing depends on D through G, and they don't depend on 778*1fa6dee9SAndroid Build Coastguard Worker // anything. 779*1fa6dee9SAndroid Build Coastguard Worker addDep(moduleA, moduleB) 780*1fa6dee9SAndroid Build Coastguard Worker addDep(moduleB, moduleC) 781*1fa6dee9SAndroid Build Coastguard Worker 782*1fa6dee9SAndroid Build Coastguard Worker t.Run("no modules", func(t *testing.T) { 783*1fa6dee9SAndroid Build Coastguard Worker errs := parallelVisit(slices.Values([]*moduleInfo(nil)), bottomUpVisitorImpl{}, 1, 784*1fa6dee9SAndroid Build Coastguard Worker func(module *moduleInfo, pause chan<- pauseSpec) bool { 785*1fa6dee9SAndroid Build Coastguard Worker panic("unexpected call to visitor") 786*1fa6dee9SAndroid Build Coastguard Worker }) 787*1fa6dee9SAndroid Build Coastguard Worker if errs != nil { 788*1fa6dee9SAndroid Build Coastguard Worker t.Errorf("expected no errors, got %q", errs) 789*1fa6dee9SAndroid Build Coastguard Worker } 790*1fa6dee9SAndroid Build Coastguard Worker }) 791*1fa6dee9SAndroid Build Coastguard Worker t.Run("bottom up", func(t *testing.T) { 792*1fa6dee9SAndroid Build Coastguard Worker order := "" 793*1fa6dee9SAndroid Build Coastguard Worker errs := parallelVisit(slices.Values([]*moduleInfo{moduleA, moduleB, moduleC}), bottomUpVisitorImpl{}, 1, 794*1fa6dee9SAndroid Build Coastguard Worker func(module *moduleInfo, pause chan<- pauseSpec) bool { 795*1fa6dee9SAndroid Build Coastguard Worker order += module.group.name 796*1fa6dee9SAndroid Build Coastguard Worker return false 797*1fa6dee9SAndroid Build Coastguard Worker }) 798*1fa6dee9SAndroid Build Coastguard Worker if errs != nil { 799*1fa6dee9SAndroid Build Coastguard Worker t.Errorf("expected no errors, got %q", errs) 800*1fa6dee9SAndroid Build Coastguard Worker } 801*1fa6dee9SAndroid Build Coastguard Worker if g, w := order, "CBA"; g != w { 802*1fa6dee9SAndroid Build Coastguard Worker t.Errorf("expected order %q, got %q", w, g) 803*1fa6dee9SAndroid Build Coastguard Worker } 804*1fa6dee9SAndroid Build Coastguard Worker }) 805*1fa6dee9SAndroid Build Coastguard Worker t.Run("pause", func(t *testing.T) { 806*1fa6dee9SAndroid Build Coastguard Worker order := "" 807*1fa6dee9SAndroid Build Coastguard Worker errs := parallelVisit(slices.Values([]*moduleInfo{moduleA, moduleB, moduleC, moduleD}), bottomUpVisitorImpl{}, 1, 808*1fa6dee9SAndroid Build Coastguard Worker func(module *moduleInfo, pause chan<- pauseSpec) bool { 809*1fa6dee9SAndroid Build Coastguard Worker if module == moduleC { 810*1fa6dee9SAndroid Build Coastguard Worker // Pause module C on module D 811*1fa6dee9SAndroid Build Coastguard Worker unpause := make(chan struct{}) 812*1fa6dee9SAndroid Build Coastguard Worker pause <- pauseSpec{moduleC, moduleD, unpause} 813*1fa6dee9SAndroid Build Coastguard Worker <-unpause 814*1fa6dee9SAndroid Build Coastguard Worker } 815*1fa6dee9SAndroid Build Coastguard Worker order += module.group.name 816*1fa6dee9SAndroid Build Coastguard Worker return false 817*1fa6dee9SAndroid Build Coastguard Worker }) 818*1fa6dee9SAndroid Build Coastguard Worker if errs != nil { 819*1fa6dee9SAndroid Build Coastguard Worker t.Errorf("expected no errors, got %q", errs) 820*1fa6dee9SAndroid Build Coastguard Worker } 821*1fa6dee9SAndroid Build Coastguard Worker if g, w := order, "DCBA"; g != w { 822*1fa6dee9SAndroid Build Coastguard Worker t.Errorf("expected order %q, got %q", w, g) 823*1fa6dee9SAndroid Build Coastguard Worker } 824*1fa6dee9SAndroid Build Coastguard Worker }) 825*1fa6dee9SAndroid Build Coastguard Worker t.Run("cancel", func(t *testing.T) { 826*1fa6dee9SAndroid Build Coastguard Worker order := "" 827*1fa6dee9SAndroid Build Coastguard Worker errs := parallelVisit(slices.Values([]*moduleInfo{moduleA, moduleB, moduleC}), bottomUpVisitorImpl{}, 1, 828*1fa6dee9SAndroid Build Coastguard Worker func(module *moduleInfo, pause chan<- pauseSpec) bool { 829*1fa6dee9SAndroid Build Coastguard Worker order += module.group.name 830*1fa6dee9SAndroid Build Coastguard Worker // Cancel in module B 831*1fa6dee9SAndroid Build Coastguard Worker return module == moduleB 832*1fa6dee9SAndroid Build Coastguard Worker }) 833*1fa6dee9SAndroid Build Coastguard Worker if errs != nil { 834*1fa6dee9SAndroid Build Coastguard Worker t.Errorf("expected no errors, got %q", errs) 835*1fa6dee9SAndroid Build Coastguard Worker } 836*1fa6dee9SAndroid Build Coastguard Worker if g, w := order, "CB"; g != w { 837*1fa6dee9SAndroid Build Coastguard Worker t.Errorf("expected order %q, got %q", w, g) 838*1fa6dee9SAndroid Build Coastguard Worker } 839*1fa6dee9SAndroid Build Coastguard Worker }) 840*1fa6dee9SAndroid Build Coastguard Worker t.Run("pause and cancel", func(t *testing.T) { 841*1fa6dee9SAndroid Build Coastguard Worker order := "" 842*1fa6dee9SAndroid Build Coastguard Worker errs := parallelVisit(slices.Values([]*moduleInfo{moduleA, moduleB, moduleC, moduleD}), bottomUpVisitorImpl{}, 1, 843*1fa6dee9SAndroid Build Coastguard Worker func(module *moduleInfo, pause chan<- pauseSpec) bool { 844*1fa6dee9SAndroid Build Coastguard Worker if module == moduleC { 845*1fa6dee9SAndroid Build Coastguard Worker // Pause module C on module D 846*1fa6dee9SAndroid Build Coastguard Worker unpause := make(chan struct{}) 847*1fa6dee9SAndroid Build Coastguard Worker pause <- pauseSpec{moduleC, moduleD, unpause} 848*1fa6dee9SAndroid Build Coastguard Worker <-unpause 849*1fa6dee9SAndroid Build Coastguard Worker } 850*1fa6dee9SAndroid Build Coastguard Worker order += module.group.name 851*1fa6dee9SAndroid Build Coastguard Worker // Cancel in module D 852*1fa6dee9SAndroid Build Coastguard Worker return module == moduleD 853*1fa6dee9SAndroid Build Coastguard Worker }) 854*1fa6dee9SAndroid Build Coastguard Worker if errs != nil { 855*1fa6dee9SAndroid Build Coastguard Worker t.Errorf("expected no errors, got %q", errs) 856*1fa6dee9SAndroid Build Coastguard Worker } 857*1fa6dee9SAndroid Build Coastguard Worker if g, w := order, "D"; g != w { 858*1fa6dee9SAndroid Build Coastguard Worker t.Errorf("expected order %q, got %q", w, g) 859*1fa6dee9SAndroid Build Coastguard Worker } 860*1fa6dee9SAndroid Build Coastguard Worker }) 861*1fa6dee9SAndroid Build Coastguard Worker t.Run("parallel", func(t *testing.T) { 862*1fa6dee9SAndroid Build Coastguard Worker order := "" 863*1fa6dee9SAndroid Build Coastguard Worker errs := parallelVisit(slices.Values([]*moduleInfo{moduleA, moduleB, moduleC}), bottomUpVisitorImpl{}, 3, 864*1fa6dee9SAndroid Build Coastguard Worker func(module *moduleInfo, pause chan<- pauseSpec) bool { 865*1fa6dee9SAndroid Build Coastguard Worker order += module.group.name 866*1fa6dee9SAndroid Build Coastguard Worker return false 867*1fa6dee9SAndroid Build Coastguard Worker }) 868*1fa6dee9SAndroid Build Coastguard Worker if errs != nil { 869*1fa6dee9SAndroid Build Coastguard Worker t.Errorf("expected no errors, got %q", errs) 870*1fa6dee9SAndroid Build Coastguard Worker } 871*1fa6dee9SAndroid Build Coastguard Worker if g, w := order, "CBA"; g != w { 872*1fa6dee9SAndroid Build Coastguard Worker t.Errorf("expected order %q, got %q", w, g) 873*1fa6dee9SAndroid Build Coastguard Worker } 874*1fa6dee9SAndroid Build Coastguard Worker }) 875*1fa6dee9SAndroid Build Coastguard Worker t.Run("pause existing", func(t *testing.T) { 876*1fa6dee9SAndroid Build Coastguard Worker order := "" 877*1fa6dee9SAndroid Build Coastguard Worker errs := parallelVisit(slices.Values([]*moduleInfo{moduleA, moduleB, moduleC}), bottomUpVisitorImpl{}, 3, 878*1fa6dee9SAndroid Build Coastguard Worker func(module *moduleInfo, pause chan<- pauseSpec) bool { 879*1fa6dee9SAndroid Build Coastguard Worker if module == moduleA { 880*1fa6dee9SAndroid Build Coastguard Worker // Pause module A on module B (an existing dependency) 881*1fa6dee9SAndroid Build Coastguard Worker unpause := make(chan struct{}) 882*1fa6dee9SAndroid Build Coastguard Worker pause <- pauseSpec{moduleA, moduleB, unpause} 883*1fa6dee9SAndroid Build Coastguard Worker <-unpause 884*1fa6dee9SAndroid Build Coastguard Worker } 885*1fa6dee9SAndroid Build Coastguard Worker order += module.group.name 886*1fa6dee9SAndroid Build Coastguard Worker return false 887*1fa6dee9SAndroid Build Coastguard Worker }) 888*1fa6dee9SAndroid Build Coastguard Worker if errs != nil { 889*1fa6dee9SAndroid Build Coastguard Worker t.Errorf("expected no errors, got %q", errs) 890*1fa6dee9SAndroid Build Coastguard Worker } 891*1fa6dee9SAndroid Build Coastguard Worker if g, w := order, "CBA"; g != w { 892*1fa6dee9SAndroid Build Coastguard Worker t.Errorf("expected order %q, got %q", w, g) 893*1fa6dee9SAndroid Build Coastguard Worker } 894*1fa6dee9SAndroid Build Coastguard Worker }) 895*1fa6dee9SAndroid Build Coastguard Worker t.Run("cycle", func(t *testing.T) { 896*1fa6dee9SAndroid Build Coastguard Worker errs := parallelVisit(slices.Values([]*moduleInfo{moduleA, moduleB, moduleC}), bottomUpVisitorImpl{}, 3, 897*1fa6dee9SAndroid Build Coastguard Worker func(module *moduleInfo, pause chan<- pauseSpec) bool { 898*1fa6dee9SAndroid Build Coastguard Worker if module == moduleC { 899*1fa6dee9SAndroid Build Coastguard Worker // Pause module C on module A (a dependency cycle) 900*1fa6dee9SAndroid Build Coastguard Worker unpause := make(chan struct{}) 901*1fa6dee9SAndroid Build Coastguard Worker pause <- pauseSpec{moduleC, moduleA, unpause} 902*1fa6dee9SAndroid Build Coastguard Worker <-unpause 903*1fa6dee9SAndroid Build Coastguard Worker } 904*1fa6dee9SAndroid Build Coastguard Worker return false 905*1fa6dee9SAndroid Build Coastguard Worker }) 906*1fa6dee9SAndroid Build Coastguard Worker want := []string{ 907*1fa6dee9SAndroid Build Coastguard Worker `encountered dependency cycle`, 908*1fa6dee9SAndroid Build Coastguard Worker `module "C" depends on module "A"`, 909*1fa6dee9SAndroid Build Coastguard Worker `module "A" depends on module "B"`, 910*1fa6dee9SAndroid Build Coastguard Worker `module "B" depends on module "C"`, 911*1fa6dee9SAndroid Build Coastguard Worker } 912*1fa6dee9SAndroid Build Coastguard Worker for i := range want { 913*1fa6dee9SAndroid Build Coastguard Worker if len(errs) <= i { 914*1fa6dee9SAndroid Build Coastguard Worker t.Errorf("missing error %s", want[i]) 915*1fa6dee9SAndroid Build Coastguard Worker } else if !strings.Contains(errs[i].Error(), want[i]) { 916*1fa6dee9SAndroid Build Coastguard Worker t.Errorf("expected error %s, got %s", want[i], errs[i]) 917*1fa6dee9SAndroid Build Coastguard Worker } 918*1fa6dee9SAndroid Build Coastguard Worker } 919*1fa6dee9SAndroid Build Coastguard Worker if len(errs) > len(want) { 920*1fa6dee9SAndroid Build Coastguard Worker for _, err := range errs[len(want):] { 921*1fa6dee9SAndroid Build Coastguard Worker t.Errorf("unexpected error %s", err.Error()) 922*1fa6dee9SAndroid Build Coastguard Worker } 923*1fa6dee9SAndroid Build Coastguard Worker } 924*1fa6dee9SAndroid Build Coastguard Worker }) 925*1fa6dee9SAndroid Build Coastguard Worker t.Run("pause cycle", func(t *testing.T) { 926*1fa6dee9SAndroid Build Coastguard Worker errs := parallelVisit(slices.Values([]*moduleInfo{moduleA, moduleB, moduleC, moduleD}), bottomUpVisitorImpl{}, 3, 927*1fa6dee9SAndroid Build Coastguard Worker func(module *moduleInfo, pause chan<- pauseSpec) bool { 928*1fa6dee9SAndroid Build Coastguard Worker if module == moduleC { 929*1fa6dee9SAndroid Build Coastguard Worker // Pause module C on module D 930*1fa6dee9SAndroid Build Coastguard Worker unpause := make(chan struct{}) 931*1fa6dee9SAndroid Build Coastguard Worker pause <- pauseSpec{moduleC, moduleD, unpause} 932*1fa6dee9SAndroid Build Coastguard Worker <-unpause 933*1fa6dee9SAndroid Build Coastguard Worker } 934*1fa6dee9SAndroid Build Coastguard Worker if module == moduleD { 935*1fa6dee9SAndroid Build Coastguard Worker // Pause module D on module C (a pause cycle) 936*1fa6dee9SAndroid Build Coastguard Worker unpause := make(chan struct{}) 937*1fa6dee9SAndroid Build Coastguard Worker pause <- pauseSpec{moduleD, moduleC, unpause} 938*1fa6dee9SAndroid Build Coastguard Worker <-unpause 939*1fa6dee9SAndroid Build Coastguard Worker } 940*1fa6dee9SAndroid Build Coastguard Worker return false 941*1fa6dee9SAndroid Build Coastguard Worker }) 942*1fa6dee9SAndroid Build Coastguard Worker want := []string{ 943*1fa6dee9SAndroid Build Coastguard Worker `encountered dependency cycle`, 944*1fa6dee9SAndroid Build Coastguard Worker `module "D" depends on module "C"`, 945*1fa6dee9SAndroid Build Coastguard Worker `module "C" depends on module "D"`, 946*1fa6dee9SAndroid Build Coastguard Worker } 947*1fa6dee9SAndroid Build Coastguard Worker for i := range want { 948*1fa6dee9SAndroid Build Coastguard Worker if len(errs) <= i { 949*1fa6dee9SAndroid Build Coastguard Worker t.Errorf("missing error %s", want[i]) 950*1fa6dee9SAndroid Build Coastguard Worker } else if !strings.Contains(errs[i].Error(), want[i]) { 951*1fa6dee9SAndroid Build Coastguard Worker t.Errorf("expected error %s, got %s", want[i], errs[i]) 952*1fa6dee9SAndroid Build Coastguard Worker } 953*1fa6dee9SAndroid Build Coastguard Worker } 954*1fa6dee9SAndroid Build Coastguard Worker if len(errs) > len(want) { 955*1fa6dee9SAndroid Build Coastguard Worker for _, err := range errs[len(want):] { 956*1fa6dee9SAndroid Build Coastguard Worker t.Errorf("unexpected error %s", err.Error()) 957*1fa6dee9SAndroid Build Coastguard Worker } 958*1fa6dee9SAndroid Build Coastguard Worker } 959*1fa6dee9SAndroid Build Coastguard Worker }) 960*1fa6dee9SAndroid Build Coastguard Worker t.Run("pause cycle with deps", func(t *testing.T) { 961*1fa6dee9SAndroid Build Coastguard Worker pauseDeps := map[*moduleInfo]*moduleInfo{ 962*1fa6dee9SAndroid Build Coastguard Worker // F and G form a pause cycle 963*1fa6dee9SAndroid Build Coastguard Worker moduleF: moduleG, 964*1fa6dee9SAndroid Build Coastguard Worker moduleG: moduleF, 965*1fa6dee9SAndroid Build Coastguard Worker // D depends on E which depends on the pause cycle, making E the first alphabetical 966*1fa6dee9SAndroid Build Coastguard Worker // entry in pauseMap, which is not part of the cycle. 967*1fa6dee9SAndroid Build Coastguard Worker moduleD: moduleE, 968*1fa6dee9SAndroid Build Coastguard Worker moduleE: moduleF, 969*1fa6dee9SAndroid Build Coastguard Worker } 970*1fa6dee9SAndroid Build Coastguard Worker errs := parallelVisit(slices.Values([]*moduleInfo{moduleD, moduleE, moduleF, moduleG}), bottomUpVisitorImpl{}, 4, 971*1fa6dee9SAndroid Build Coastguard Worker func(module *moduleInfo, pause chan<- pauseSpec) bool { 972*1fa6dee9SAndroid Build Coastguard Worker if dep, ok := pauseDeps[module]; ok { 973*1fa6dee9SAndroid Build Coastguard Worker unpause := make(chan struct{}) 974*1fa6dee9SAndroid Build Coastguard Worker pause <- pauseSpec{module, dep, unpause} 975*1fa6dee9SAndroid Build Coastguard Worker <-unpause 976*1fa6dee9SAndroid Build Coastguard Worker } 977*1fa6dee9SAndroid Build Coastguard Worker return false 978*1fa6dee9SAndroid Build Coastguard Worker }) 979*1fa6dee9SAndroid Build Coastguard Worker want := []string{ 980*1fa6dee9SAndroid Build Coastguard Worker `encountered dependency cycle`, 981*1fa6dee9SAndroid Build Coastguard Worker `module "G" depends on module "F"`, 982*1fa6dee9SAndroid Build Coastguard Worker `module "F" depends on module "G"`, 983*1fa6dee9SAndroid Build Coastguard Worker } 984*1fa6dee9SAndroid Build Coastguard Worker for i := range want { 985*1fa6dee9SAndroid Build Coastguard Worker if len(errs) <= i { 986*1fa6dee9SAndroid Build Coastguard Worker t.Errorf("missing error %s", want[i]) 987*1fa6dee9SAndroid Build Coastguard Worker } else if !strings.Contains(errs[i].Error(), want[i]) { 988*1fa6dee9SAndroid Build Coastguard Worker t.Errorf("expected error %s, got %s", want[i], errs[i]) 989*1fa6dee9SAndroid Build Coastguard Worker } 990*1fa6dee9SAndroid Build Coastguard Worker } 991*1fa6dee9SAndroid Build Coastguard Worker if len(errs) > len(want) { 992*1fa6dee9SAndroid Build Coastguard Worker for _, err := range errs[len(want):] { 993*1fa6dee9SAndroid Build Coastguard Worker t.Errorf("unexpected error %s", err.Error()) 994*1fa6dee9SAndroid Build Coastguard Worker } 995*1fa6dee9SAndroid Build Coastguard Worker } 996*1fa6dee9SAndroid Build Coastguard Worker }) 997*1fa6dee9SAndroid Build Coastguard Worker} 998*1fa6dee9SAndroid Build Coastguard Worker 999*1fa6dee9SAndroid Build Coastguard Workerfunc TestDeduplicateOrderOnlyDeps(t *testing.T) { 1000*1fa6dee9SAndroid Build Coastguard Worker b := func(output string, inputs []string, orderOnlyDeps []string) *buildDef { 1001*1fa6dee9SAndroid Build Coastguard Worker return &buildDef{ 1002*1fa6dee9SAndroid Build Coastguard Worker OutputStrings: []string{output}, 1003*1fa6dee9SAndroid Build Coastguard Worker InputStrings: inputs, 1004*1fa6dee9SAndroid Build Coastguard Worker OrderOnlyStrings: orderOnlyDeps, 1005*1fa6dee9SAndroid Build Coastguard Worker } 1006*1fa6dee9SAndroid Build Coastguard Worker } 1007*1fa6dee9SAndroid Build Coastguard Worker m := func(bs ...*buildDef) *moduleInfo { 1008*1fa6dee9SAndroid Build Coastguard Worker return &moduleInfo{actionDefs: localBuildActions{buildDefs: bs}} 1009*1fa6dee9SAndroid Build Coastguard Worker } 1010*1fa6dee9SAndroid Build Coastguard Worker type testcase struct { 1011*1fa6dee9SAndroid Build Coastguard Worker modules []*moduleInfo 1012*1fa6dee9SAndroid Build Coastguard Worker expectedPhonys []*buildDef 1013*1fa6dee9SAndroid Build Coastguard Worker conversions map[string][]string 1014*1fa6dee9SAndroid Build Coastguard Worker } 1015*1fa6dee9SAndroid Build Coastguard Worker fnvHash := func(s string) string { 1016*1fa6dee9SAndroid Build Coastguard Worker hash := fnv.New64a() 1017*1fa6dee9SAndroid Build Coastguard Worker hash.Write([]byte(s)) 1018*1fa6dee9SAndroid Build Coastguard Worker return strconv.FormatUint(hash.Sum64(), 16) 1019*1fa6dee9SAndroid Build Coastguard Worker } 1020*1fa6dee9SAndroid Build Coastguard Worker testCases := []testcase{{ 1021*1fa6dee9SAndroid Build Coastguard Worker modules: []*moduleInfo{ 1022*1fa6dee9SAndroid Build Coastguard Worker m(b("A", nil, []string{"d"})), 1023*1fa6dee9SAndroid Build Coastguard Worker m(b("B", nil, []string{"d"})), 1024*1fa6dee9SAndroid Build Coastguard Worker }, 1025*1fa6dee9SAndroid Build Coastguard Worker expectedPhonys: []*buildDef{ 1026*1fa6dee9SAndroid Build Coastguard Worker b("dedup-"+fnvHash("d"), []string{"d"}, nil), 1027*1fa6dee9SAndroid Build Coastguard Worker }, 1028*1fa6dee9SAndroid Build Coastguard Worker conversions: map[string][]string{ 1029*1fa6dee9SAndroid Build Coastguard Worker "A": []string{"dedup-" + fnvHash("d")}, 1030*1fa6dee9SAndroid Build Coastguard Worker "B": []string{"dedup-" + fnvHash("d")}, 1031*1fa6dee9SAndroid Build Coastguard Worker }, 1032*1fa6dee9SAndroid Build Coastguard Worker }, { 1033*1fa6dee9SAndroid Build Coastguard Worker modules: []*moduleInfo{ 1034*1fa6dee9SAndroid Build Coastguard Worker m(b("A", nil, []string{"a"})), 1035*1fa6dee9SAndroid Build Coastguard Worker m(b("B", nil, []string{"b"})), 1036*1fa6dee9SAndroid Build Coastguard Worker }, 1037*1fa6dee9SAndroid Build Coastguard Worker }, { 1038*1fa6dee9SAndroid Build Coastguard Worker modules: []*moduleInfo{ 1039*1fa6dee9SAndroid Build Coastguard Worker m(b("A", nil, []string{"a"})), 1040*1fa6dee9SAndroid Build Coastguard Worker m(b("B", nil, []string{"b"})), 1041*1fa6dee9SAndroid Build Coastguard Worker m(b("C", nil, []string{"a"})), 1042*1fa6dee9SAndroid Build Coastguard Worker }, 1043*1fa6dee9SAndroid Build Coastguard Worker expectedPhonys: []*buildDef{b("dedup-"+fnvHash("a"), []string{"a"}, nil)}, 1044*1fa6dee9SAndroid Build Coastguard Worker conversions: map[string][]string{ 1045*1fa6dee9SAndroid Build Coastguard Worker "A": []string{"dedup-" + fnvHash("a")}, 1046*1fa6dee9SAndroid Build Coastguard Worker "B": []string{"b"}, 1047*1fa6dee9SAndroid Build Coastguard Worker "C": []string{"dedup-" + fnvHash("a")}, 1048*1fa6dee9SAndroid Build Coastguard Worker }, 1049*1fa6dee9SAndroid Build Coastguard Worker }, { 1050*1fa6dee9SAndroid Build Coastguard Worker modules: []*moduleInfo{ 1051*1fa6dee9SAndroid Build Coastguard Worker m(b("A", nil, []string{"a", "b"}), 1052*1fa6dee9SAndroid Build Coastguard Worker b("B", nil, []string{"a", "b"})), 1053*1fa6dee9SAndroid Build Coastguard Worker m(b("C", nil, []string{"a", "c"}), 1054*1fa6dee9SAndroid Build Coastguard Worker b("D", nil, []string{"a", "c"})), 1055*1fa6dee9SAndroid Build Coastguard Worker }, 1056*1fa6dee9SAndroid Build Coastguard Worker expectedPhonys: []*buildDef{ 1057*1fa6dee9SAndroid Build Coastguard Worker b("dedup-"+fnvHash("ab"), []string{"a", "b"}, nil), 1058*1fa6dee9SAndroid Build Coastguard Worker b("dedup-"+fnvHash("ac"), []string{"a", "c"}, nil)}, 1059*1fa6dee9SAndroid Build Coastguard Worker conversions: map[string][]string{ 1060*1fa6dee9SAndroid Build Coastguard Worker "A": []string{"dedup-" + fnvHash("ab")}, 1061*1fa6dee9SAndroid Build Coastguard Worker "B": []string{"dedup-" + fnvHash("ab")}, 1062*1fa6dee9SAndroid Build Coastguard Worker "C": []string{"dedup-" + fnvHash("ac")}, 1063*1fa6dee9SAndroid Build Coastguard Worker "D": []string{"dedup-" + fnvHash("ac")}, 1064*1fa6dee9SAndroid Build Coastguard Worker }, 1065*1fa6dee9SAndroid Build Coastguard Worker }} 1066*1fa6dee9SAndroid Build Coastguard Worker for index, tc := range testCases { 1067*1fa6dee9SAndroid Build Coastguard Worker t.Run(fmt.Sprintf("TestCase-%d", index), func(t *testing.T) { 1068*1fa6dee9SAndroid Build Coastguard Worker ctx := NewContext() 1069*1fa6dee9SAndroid Build Coastguard Worker actualPhonys := ctx.deduplicateOrderOnlyDeps(tc.modules) 1070*1fa6dee9SAndroid Build Coastguard Worker if len(actualPhonys.variables) != 0 { 1071*1fa6dee9SAndroid Build Coastguard Worker t.Errorf("No variables expected but found %v", actualPhonys.variables) 1072*1fa6dee9SAndroid Build Coastguard Worker } 1073*1fa6dee9SAndroid Build Coastguard Worker if len(actualPhonys.rules) != 0 { 1074*1fa6dee9SAndroid Build Coastguard Worker t.Errorf("No rules expected but found %v", actualPhonys.rules) 1075*1fa6dee9SAndroid Build Coastguard Worker } 1076*1fa6dee9SAndroid Build Coastguard Worker if e, a := len(tc.expectedPhonys), len(actualPhonys.buildDefs); e != a { 1077*1fa6dee9SAndroid Build Coastguard Worker t.Errorf("Expected %d build statements but got %d", e, a) 1078*1fa6dee9SAndroid Build Coastguard Worker } 1079*1fa6dee9SAndroid Build Coastguard Worker for i := 0; i < len(tc.expectedPhonys); i++ { 1080*1fa6dee9SAndroid Build Coastguard Worker a := actualPhonys.buildDefs[i] 1081*1fa6dee9SAndroid Build Coastguard Worker e := tc.expectedPhonys[i] 1082*1fa6dee9SAndroid Build Coastguard Worker if !reflect.DeepEqual(e.Outputs, a.Outputs) { 1083*1fa6dee9SAndroid Build Coastguard Worker t.Errorf("phonys expected %v but actualPhonys %v", e.Outputs, a.Outputs) 1084*1fa6dee9SAndroid Build Coastguard Worker } 1085*1fa6dee9SAndroid Build Coastguard Worker if !reflect.DeepEqual(e.Inputs, a.Inputs) { 1086*1fa6dee9SAndroid Build Coastguard Worker t.Errorf("phonys expected %v but actualPhonys %v", e.Inputs, a.Inputs) 1087*1fa6dee9SAndroid Build Coastguard Worker } 1088*1fa6dee9SAndroid Build Coastguard Worker } 1089*1fa6dee9SAndroid Build Coastguard Worker find := func(k string) *buildDef { 1090*1fa6dee9SAndroid Build Coastguard Worker for _, m := range tc.modules { 1091*1fa6dee9SAndroid Build Coastguard Worker for _, b := range m.actionDefs.buildDefs { 1092*1fa6dee9SAndroid Build Coastguard Worker if reflect.DeepEqual(b.OutputStrings, []string{k}) { 1093*1fa6dee9SAndroid Build Coastguard Worker return b 1094*1fa6dee9SAndroid Build Coastguard Worker } 1095*1fa6dee9SAndroid Build Coastguard Worker } 1096*1fa6dee9SAndroid Build Coastguard Worker } 1097*1fa6dee9SAndroid Build Coastguard Worker return nil 1098*1fa6dee9SAndroid Build Coastguard Worker } 1099*1fa6dee9SAndroid Build Coastguard Worker for k, conversion := range tc.conversions { 1100*1fa6dee9SAndroid Build Coastguard Worker actual := find(k) 1101*1fa6dee9SAndroid Build Coastguard Worker if actual == nil { 1102*1fa6dee9SAndroid Build Coastguard Worker t.Errorf("Couldn't find %s", k) 1103*1fa6dee9SAndroid Build Coastguard Worker } 1104*1fa6dee9SAndroid Build Coastguard Worker if !reflect.DeepEqual(actual.OrderOnlyStrings, conversion) { 1105*1fa6dee9SAndroid Build Coastguard Worker t.Errorf("expected %s.OrderOnly = %v but got %v", k, conversion, actual.OrderOnly) 1106*1fa6dee9SAndroid Build Coastguard Worker } 1107*1fa6dee9SAndroid Build Coastguard Worker } 1108*1fa6dee9SAndroid Build Coastguard Worker }) 1109*1fa6dee9SAndroid Build Coastguard Worker } 1110*1fa6dee9SAndroid Build Coastguard Worker} 1111*1fa6dee9SAndroid Build Coastguard Worker 1112*1fa6dee9SAndroid Build Coastguard Workerfunc TestSourceRootDirAllowed(t *testing.T) { 1113*1fa6dee9SAndroid Build Coastguard Worker type pathCase struct { 1114*1fa6dee9SAndroid Build Coastguard Worker path string 1115*1fa6dee9SAndroid Build Coastguard Worker decidingPrefix string 1116*1fa6dee9SAndroid Build Coastguard Worker allowed bool 1117*1fa6dee9SAndroid Build Coastguard Worker } 1118*1fa6dee9SAndroid Build Coastguard Worker testcases := []struct { 1119*1fa6dee9SAndroid Build Coastguard Worker desc string 1120*1fa6dee9SAndroid Build Coastguard Worker rootDirs []string 1121*1fa6dee9SAndroid Build Coastguard Worker pathCases []pathCase 1122*1fa6dee9SAndroid Build Coastguard Worker }{ 1123*1fa6dee9SAndroid Build Coastguard Worker { 1124*1fa6dee9SAndroid Build Coastguard Worker desc: "simple case", 1125*1fa6dee9SAndroid Build Coastguard Worker rootDirs: []string{ 1126*1fa6dee9SAndroid Build Coastguard Worker "a", 1127*1fa6dee9SAndroid Build Coastguard Worker "b/c/d", 1128*1fa6dee9SAndroid Build Coastguard Worker "-c", 1129*1fa6dee9SAndroid Build Coastguard Worker "-d/c/a", 1130*1fa6dee9SAndroid Build Coastguard Worker "c/some_single_file", 1131*1fa6dee9SAndroid Build Coastguard Worker }, 1132*1fa6dee9SAndroid Build Coastguard Worker pathCases: []pathCase{ 1133*1fa6dee9SAndroid Build Coastguard Worker { 1134*1fa6dee9SAndroid Build Coastguard Worker path: "a", 1135*1fa6dee9SAndroid Build Coastguard Worker decidingPrefix: "a", 1136*1fa6dee9SAndroid Build Coastguard Worker allowed: true, 1137*1fa6dee9SAndroid Build Coastguard Worker }, 1138*1fa6dee9SAndroid Build Coastguard Worker { 1139*1fa6dee9SAndroid Build Coastguard Worker path: "a/b/c", 1140*1fa6dee9SAndroid Build Coastguard Worker decidingPrefix: "a", 1141*1fa6dee9SAndroid Build Coastguard Worker allowed: true, 1142*1fa6dee9SAndroid Build Coastguard Worker }, 1143*1fa6dee9SAndroid Build Coastguard Worker { 1144*1fa6dee9SAndroid Build Coastguard Worker path: "b", 1145*1fa6dee9SAndroid Build Coastguard Worker decidingPrefix: "", 1146*1fa6dee9SAndroid Build Coastguard Worker allowed: true, 1147*1fa6dee9SAndroid Build Coastguard Worker }, 1148*1fa6dee9SAndroid Build Coastguard Worker { 1149*1fa6dee9SAndroid Build Coastguard Worker path: "b/c/d/a", 1150*1fa6dee9SAndroid Build Coastguard Worker decidingPrefix: "b/c/d", 1151*1fa6dee9SAndroid Build Coastguard Worker allowed: true, 1152*1fa6dee9SAndroid Build Coastguard Worker }, 1153*1fa6dee9SAndroid Build Coastguard Worker { 1154*1fa6dee9SAndroid Build Coastguard Worker path: "c", 1155*1fa6dee9SAndroid Build Coastguard Worker decidingPrefix: "c", 1156*1fa6dee9SAndroid Build Coastguard Worker allowed: false, 1157*1fa6dee9SAndroid Build Coastguard Worker }, 1158*1fa6dee9SAndroid Build Coastguard Worker { 1159*1fa6dee9SAndroid Build Coastguard Worker path: "c/a/b", 1160*1fa6dee9SAndroid Build Coastguard Worker decidingPrefix: "c", 1161*1fa6dee9SAndroid Build Coastguard Worker allowed: false, 1162*1fa6dee9SAndroid Build Coastguard Worker }, 1163*1fa6dee9SAndroid Build Coastguard Worker { 1164*1fa6dee9SAndroid Build Coastguard Worker path: "c/some_single_file", 1165*1fa6dee9SAndroid Build Coastguard Worker decidingPrefix: "c/some_single_file", 1166*1fa6dee9SAndroid Build Coastguard Worker allowed: true, 1167*1fa6dee9SAndroid Build Coastguard Worker }, 1168*1fa6dee9SAndroid Build Coastguard Worker { 1169*1fa6dee9SAndroid Build Coastguard Worker path: "d/c/a/abc", 1170*1fa6dee9SAndroid Build Coastguard Worker decidingPrefix: "d/c/a", 1171*1fa6dee9SAndroid Build Coastguard Worker allowed: false, 1172*1fa6dee9SAndroid Build Coastguard Worker }, 1173*1fa6dee9SAndroid Build Coastguard Worker }, 1174*1fa6dee9SAndroid Build Coastguard Worker }, 1175*1fa6dee9SAndroid Build Coastguard Worker { 1176*1fa6dee9SAndroid Build Coastguard Worker desc: "root directory order matters", 1177*1fa6dee9SAndroid Build Coastguard Worker rootDirs: []string{ 1178*1fa6dee9SAndroid Build Coastguard Worker "-a", 1179*1fa6dee9SAndroid Build Coastguard Worker "a/c/some_allowed_file", 1180*1fa6dee9SAndroid Build Coastguard Worker "a/b/d/some_allowed_file", 1181*1fa6dee9SAndroid Build Coastguard Worker "a/b", 1182*1fa6dee9SAndroid Build Coastguard Worker "a/c", 1183*1fa6dee9SAndroid Build Coastguard Worker "-a/b/d", 1184*1fa6dee9SAndroid Build Coastguard Worker }, 1185*1fa6dee9SAndroid Build Coastguard Worker pathCases: []pathCase{ 1186*1fa6dee9SAndroid Build Coastguard Worker { 1187*1fa6dee9SAndroid Build Coastguard Worker path: "a", 1188*1fa6dee9SAndroid Build Coastguard Worker decidingPrefix: "a", 1189*1fa6dee9SAndroid Build Coastguard Worker allowed: false, 1190*1fa6dee9SAndroid Build Coastguard Worker }, 1191*1fa6dee9SAndroid Build Coastguard Worker { 1192*1fa6dee9SAndroid Build Coastguard Worker path: "a/some_disallowed_file", 1193*1fa6dee9SAndroid Build Coastguard Worker decidingPrefix: "a", 1194*1fa6dee9SAndroid Build Coastguard Worker allowed: false, 1195*1fa6dee9SAndroid Build Coastguard Worker }, 1196*1fa6dee9SAndroid Build Coastguard Worker { 1197*1fa6dee9SAndroid Build Coastguard Worker path: "a/c/some_allowed_file", 1198*1fa6dee9SAndroid Build Coastguard Worker decidingPrefix: "a/c/some_allowed_file", 1199*1fa6dee9SAndroid Build Coastguard Worker allowed: true, 1200*1fa6dee9SAndroid Build Coastguard Worker }, 1201*1fa6dee9SAndroid Build Coastguard Worker { 1202*1fa6dee9SAndroid Build Coastguard Worker path: "a/b/d/some_allowed_file", 1203*1fa6dee9SAndroid Build Coastguard Worker decidingPrefix: "a/b/d/some_allowed_file", 1204*1fa6dee9SAndroid Build Coastguard Worker allowed: true, 1205*1fa6dee9SAndroid Build Coastguard Worker }, 1206*1fa6dee9SAndroid Build Coastguard Worker { 1207*1fa6dee9SAndroid Build Coastguard Worker path: "a/b/c", 1208*1fa6dee9SAndroid Build Coastguard Worker decidingPrefix: "a/b", 1209*1fa6dee9SAndroid Build Coastguard Worker allowed: true, 1210*1fa6dee9SAndroid Build Coastguard Worker }, 1211*1fa6dee9SAndroid Build Coastguard Worker { 1212*1fa6dee9SAndroid Build Coastguard Worker path: "a/b/c/some_allowed_file", 1213*1fa6dee9SAndroid Build Coastguard Worker decidingPrefix: "a/b", 1214*1fa6dee9SAndroid Build Coastguard Worker allowed: true, 1215*1fa6dee9SAndroid Build Coastguard Worker }, 1216*1fa6dee9SAndroid Build Coastguard Worker { 1217*1fa6dee9SAndroid Build Coastguard Worker path: "a/b/d", 1218*1fa6dee9SAndroid Build Coastguard Worker decidingPrefix: "a/b/d", 1219*1fa6dee9SAndroid Build Coastguard Worker allowed: false, 1220*1fa6dee9SAndroid Build Coastguard Worker }, 1221*1fa6dee9SAndroid Build Coastguard Worker }, 1222*1fa6dee9SAndroid Build Coastguard Worker }, 1223*1fa6dee9SAndroid Build Coastguard Worker } 1224*1fa6dee9SAndroid Build Coastguard Worker for _, tc := range testcases { 1225*1fa6dee9SAndroid Build Coastguard Worker dirs := SourceRootDirs{} 1226*1fa6dee9SAndroid Build Coastguard Worker dirs.Add(tc.rootDirs...) 1227*1fa6dee9SAndroid Build Coastguard Worker for _, pc := range tc.pathCases { 1228*1fa6dee9SAndroid Build Coastguard Worker t.Run(fmt.Sprintf("%s: %s", tc.desc, pc.path), func(t *testing.T) { 1229*1fa6dee9SAndroid Build Coastguard Worker allowed, decidingPrefix := dirs.SourceRootDirAllowed(pc.path) 1230*1fa6dee9SAndroid Build Coastguard Worker if allowed != pc.allowed { 1231*1fa6dee9SAndroid Build Coastguard Worker if pc.allowed { 1232*1fa6dee9SAndroid Build Coastguard Worker t.Errorf("expected path %q to be allowed, but was not; root allowlist: %q", pc.path, tc.rootDirs) 1233*1fa6dee9SAndroid Build Coastguard Worker } else { 1234*1fa6dee9SAndroid Build Coastguard Worker t.Errorf("path %q was allowed unexpectedly; root allowlist: %q", pc.path, tc.rootDirs) 1235*1fa6dee9SAndroid Build Coastguard Worker } 1236*1fa6dee9SAndroid Build Coastguard Worker } 1237*1fa6dee9SAndroid Build Coastguard Worker if decidingPrefix != pc.decidingPrefix { 1238*1fa6dee9SAndroid Build Coastguard Worker t.Errorf("expected decidingPrefix to be %q, but got %q", pc.decidingPrefix, decidingPrefix) 1239*1fa6dee9SAndroid Build Coastguard Worker } 1240*1fa6dee9SAndroid Build Coastguard Worker }) 1241*1fa6dee9SAndroid Build Coastguard Worker } 1242*1fa6dee9SAndroid Build Coastguard Worker } 1243*1fa6dee9SAndroid Build Coastguard Worker} 1244*1fa6dee9SAndroid Build Coastguard Worker 1245*1fa6dee9SAndroid Build Coastguard Workerfunc TestSourceRootDirs(t *testing.T) { 1246*1fa6dee9SAndroid Build Coastguard Worker root_foo_bp := ` 1247*1fa6dee9SAndroid Build Coastguard Worker foo_module { 1248*1fa6dee9SAndroid Build Coastguard Worker name: "foo", 1249*1fa6dee9SAndroid Build Coastguard Worker deps: ["foo_dir1", "foo_dir_ignored_special_case"], 1250*1fa6dee9SAndroid Build Coastguard Worker } 1251*1fa6dee9SAndroid Build Coastguard Worker ` 1252*1fa6dee9SAndroid Build Coastguard Worker dir1_foo_bp := ` 1253*1fa6dee9SAndroid Build Coastguard Worker foo_module { 1254*1fa6dee9SAndroid Build Coastguard Worker name: "foo_dir1", 1255*1fa6dee9SAndroid Build Coastguard Worker deps: ["foo_dir_ignored"], 1256*1fa6dee9SAndroid Build Coastguard Worker } 1257*1fa6dee9SAndroid Build Coastguard Worker ` 1258*1fa6dee9SAndroid Build Coastguard Worker dir_ignored_foo_bp := ` 1259*1fa6dee9SAndroid Build Coastguard Worker foo_module { 1260*1fa6dee9SAndroid Build Coastguard Worker name: "foo_dir_ignored", 1261*1fa6dee9SAndroid Build Coastguard Worker } 1262*1fa6dee9SAndroid Build Coastguard Worker ` 1263*1fa6dee9SAndroid Build Coastguard Worker dir_ignored_special_case_foo_bp := ` 1264*1fa6dee9SAndroid Build Coastguard Worker foo_module { 1265*1fa6dee9SAndroid Build Coastguard Worker name: "foo_dir_ignored_special_case", 1266*1fa6dee9SAndroid Build Coastguard Worker } 1267*1fa6dee9SAndroid Build Coastguard Worker ` 1268*1fa6dee9SAndroid Build Coastguard Worker mockFs := map[string][]byte{ 1269*1fa6dee9SAndroid Build Coastguard Worker "Android.bp": []byte(root_foo_bp), 1270*1fa6dee9SAndroid Build Coastguard Worker "dir1/Android.bp": []byte(dir1_foo_bp), 1271*1fa6dee9SAndroid Build Coastguard Worker "dir_ignored/Android.bp": []byte(dir_ignored_foo_bp), 1272*1fa6dee9SAndroid Build Coastguard Worker "dir_ignored/special_case/Android.bp": []byte(dir_ignored_special_case_foo_bp), 1273*1fa6dee9SAndroid Build Coastguard Worker } 1274*1fa6dee9SAndroid Build Coastguard Worker fileList := []string{} 1275*1fa6dee9SAndroid Build Coastguard Worker for f := range mockFs { 1276*1fa6dee9SAndroid Build Coastguard Worker fileList = append(fileList, f) 1277*1fa6dee9SAndroid Build Coastguard Worker } 1278*1fa6dee9SAndroid Build Coastguard Worker testCases := []struct { 1279*1fa6dee9SAndroid Build Coastguard Worker sourceRootDirs []string 1280*1fa6dee9SAndroid Build Coastguard Worker expectedModuleDefs []string 1281*1fa6dee9SAndroid Build Coastguard Worker unexpectedModuleDefs []string 1282*1fa6dee9SAndroid Build Coastguard Worker expectedErrs []string 1283*1fa6dee9SAndroid Build Coastguard Worker }{ 1284*1fa6dee9SAndroid Build Coastguard Worker { 1285*1fa6dee9SAndroid Build Coastguard Worker sourceRootDirs: []string{}, 1286*1fa6dee9SAndroid Build Coastguard Worker expectedModuleDefs: []string{ 1287*1fa6dee9SAndroid Build Coastguard Worker "foo", 1288*1fa6dee9SAndroid Build Coastguard Worker "foo_dir1", 1289*1fa6dee9SAndroid Build Coastguard Worker "foo_dir_ignored", 1290*1fa6dee9SAndroid Build Coastguard Worker "foo_dir_ignored_special_case", 1291*1fa6dee9SAndroid Build Coastguard Worker }, 1292*1fa6dee9SAndroid Build Coastguard Worker }, 1293*1fa6dee9SAndroid Build Coastguard Worker { 1294*1fa6dee9SAndroid Build Coastguard Worker sourceRootDirs: []string{"-", ""}, 1295*1fa6dee9SAndroid Build Coastguard Worker unexpectedModuleDefs: []string{ 1296*1fa6dee9SAndroid Build Coastguard Worker "foo", 1297*1fa6dee9SAndroid Build Coastguard Worker "foo_dir1", 1298*1fa6dee9SAndroid Build Coastguard Worker "foo_dir_ignored", 1299*1fa6dee9SAndroid Build Coastguard Worker "foo_dir_ignored_special_case", 1300*1fa6dee9SAndroid Build Coastguard Worker }, 1301*1fa6dee9SAndroid Build Coastguard Worker }, 1302*1fa6dee9SAndroid Build Coastguard Worker { 1303*1fa6dee9SAndroid Build Coastguard Worker sourceRootDirs: []string{"-"}, 1304*1fa6dee9SAndroid Build Coastguard Worker unexpectedModuleDefs: []string{ 1305*1fa6dee9SAndroid Build Coastguard Worker "foo", 1306*1fa6dee9SAndroid Build Coastguard Worker "foo_dir1", 1307*1fa6dee9SAndroid Build Coastguard Worker "foo_dir_ignored", 1308*1fa6dee9SAndroid Build Coastguard Worker "foo_dir_ignored_special_case", 1309*1fa6dee9SAndroid Build Coastguard Worker }, 1310*1fa6dee9SAndroid Build Coastguard Worker }, 1311*1fa6dee9SAndroid Build Coastguard Worker { 1312*1fa6dee9SAndroid Build Coastguard Worker sourceRootDirs: []string{"dir1"}, 1313*1fa6dee9SAndroid Build Coastguard Worker expectedModuleDefs: []string{ 1314*1fa6dee9SAndroid Build Coastguard Worker "foo", 1315*1fa6dee9SAndroid Build Coastguard Worker "foo_dir1", 1316*1fa6dee9SAndroid Build Coastguard Worker "foo_dir_ignored", 1317*1fa6dee9SAndroid Build Coastguard Worker "foo_dir_ignored_special_case", 1318*1fa6dee9SAndroid Build Coastguard Worker }, 1319*1fa6dee9SAndroid Build Coastguard Worker }, 1320*1fa6dee9SAndroid Build Coastguard Worker { 1321*1fa6dee9SAndroid Build Coastguard Worker sourceRootDirs: []string{"-dir1"}, 1322*1fa6dee9SAndroid Build Coastguard Worker expectedModuleDefs: []string{ 1323*1fa6dee9SAndroid Build Coastguard Worker "foo", 1324*1fa6dee9SAndroid Build Coastguard Worker "foo_dir_ignored", 1325*1fa6dee9SAndroid Build Coastguard Worker "foo_dir_ignored_special_case", 1326*1fa6dee9SAndroid Build Coastguard Worker }, 1327*1fa6dee9SAndroid Build Coastguard Worker unexpectedModuleDefs: []string{ 1328*1fa6dee9SAndroid Build Coastguard Worker "foo_dir1", 1329*1fa6dee9SAndroid Build Coastguard Worker }, 1330*1fa6dee9SAndroid Build Coastguard Worker expectedErrs: []string{ 1331*1fa6dee9SAndroid Build Coastguard Worker `Android.bp:2:2: module "foo" depends on skipped module "foo_dir1"; "foo_dir1" was defined in files(s) [dir1/Android.bp], but was skipped for reason(s) ["dir1/Android.bp" is a descendant of "dir1", and that path prefix was not included in PRODUCT_SOURCE_ROOT_DIRS]`, 1332*1fa6dee9SAndroid Build Coastguard Worker }, 1333*1fa6dee9SAndroid Build Coastguard Worker }, 1334*1fa6dee9SAndroid Build Coastguard Worker { 1335*1fa6dee9SAndroid Build Coastguard Worker sourceRootDirs: []string{"-", "dir1"}, 1336*1fa6dee9SAndroid Build Coastguard Worker expectedModuleDefs: []string{ 1337*1fa6dee9SAndroid Build Coastguard Worker "foo_dir1", 1338*1fa6dee9SAndroid Build Coastguard Worker }, 1339*1fa6dee9SAndroid Build Coastguard Worker unexpectedModuleDefs: []string{ 1340*1fa6dee9SAndroid Build Coastguard Worker "foo", 1341*1fa6dee9SAndroid Build Coastguard Worker "foo_dir_ignored", 1342*1fa6dee9SAndroid Build Coastguard Worker "foo_dir_ignored_special_case", 1343*1fa6dee9SAndroid Build Coastguard Worker }, 1344*1fa6dee9SAndroid Build Coastguard Worker expectedErrs: []string{ 1345*1fa6dee9SAndroid Build Coastguard Worker `dir1/Android.bp:2:2: module "foo_dir1" depends on skipped module "foo_dir_ignored"; "foo_dir_ignored" was defined in files(s) [dir_ignored/Android.bp], but was skipped for reason(s) ["dir_ignored/Android.bp" is a descendant of "", and that path prefix was not included in PRODUCT_SOURCE_ROOT_DIRS]`, 1346*1fa6dee9SAndroid Build Coastguard Worker }, 1347*1fa6dee9SAndroid Build Coastguard Worker }, 1348*1fa6dee9SAndroid Build Coastguard Worker { 1349*1fa6dee9SAndroid Build Coastguard Worker sourceRootDirs: []string{"-", "dir1", "dir_ignored/special_case/Android.bp"}, 1350*1fa6dee9SAndroid Build Coastguard Worker expectedModuleDefs: []string{ 1351*1fa6dee9SAndroid Build Coastguard Worker "foo_dir1", 1352*1fa6dee9SAndroid Build Coastguard Worker "foo_dir_ignored_special_case", 1353*1fa6dee9SAndroid Build Coastguard Worker }, 1354*1fa6dee9SAndroid Build Coastguard Worker unexpectedModuleDefs: []string{ 1355*1fa6dee9SAndroid Build Coastguard Worker "foo", 1356*1fa6dee9SAndroid Build Coastguard Worker "foo_dir_ignored", 1357*1fa6dee9SAndroid Build Coastguard Worker }, 1358*1fa6dee9SAndroid Build Coastguard Worker expectedErrs: []string{ 1359*1fa6dee9SAndroid Build Coastguard Worker "dir1/Android.bp:2:2: module \"foo_dir1\" depends on skipped module \"foo_dir_ignored\"; \"foo_dir_ignored\" was defined in files(s) [dir_ignored/Android.bp], but was skipped for reason(s) [\"dir_ignored/Android.bp\" is a descendant of \"\", and that path prefix was not included in PRODUCT_SOURCE_ROOT_DIRS]", 1360*1fa6dee9SAndroid Build Coastguard Worker }, 1361*1fa6dee9SAndroid Build Coastguard Worker }, 1362*1fa6dee9SAndroid Build Coastguard Worker } 1363*1fa6dee9SAndroid Build Coastguard Worker for _, tc := range testCases { 1364*1fa6dee9SAndroid Build Coastguard Worker t.Run(fmt.Sprintf(`source root dirs are %q`, tc.sourceRootDirs), func(t *testing.T) { 1365*1fa6dee9SAndroid Build Coastguard Worker ctx := NewContext() 1366*1fa6dee9SAndroid Build Coastguard Worker ctx.MockFileSystem(mockFs) 1367*1fa6dee9SAndroid Build Coastguard Worker ctx.RegisterModuleType("foo_module", newFooModule) 1368*1fa6dee9SAndroid Build Coastguard Worker ctx.RegisterBottomUpMutator("deps", depsMutator) 1369*1fa6dee9SAndroid Build Coastguard Worker ctx.AddSourceRootDirs(tc.sourceRootDirs...) 1370*1fa6dee9SAndroid Build Coastguard Worker ctx.ParseFileList(".", fileList, nil) 1371*1fa6dee9SAndroid Build Coastguard Worker _, actualErrs := ctx.ResolveDependencies(nil) 1372*1fa6dee9SAndroid Build Coastguard Worker 1373*1fa6dee9SAndroid Build Coastguard Worker stringErrs := []string(nil) 1374*1fa6dee9SAndroid Build Coastguard Worker for _, err := range actualErrs { 1375*1fa6dee9SAndroid Build Coastguard Worker stringErrs = append(stringErrs, err.Error()) 1376*1fa6dee9SAndroid Build Coastguard Worker } 1377*1fa6dee9SAndroid Build Coastguard Worker if !reflect.DeepEqual(tc.expectedErrs, stringErrs) { 1378*1fa6dee9SAndroid Build Coastguard Worker t.Errorf("expected to find errors %v; got %v", tc.expectedErrs, stringErrs) 1379*1fa6dee9SAndroid Build Coastguard Worker } 1380*1fa6dee9SAndroid Build Coastguard Worker for _, modName := range tc.expectedModuleDefs { 1381*1fa6dee9SAndroid Build Coastguard Worker allMods := ctx.moduleGroupFromName(modName, nil) 1382*1fa6dee9SAndroid Build Coastguard Worker if allMods == nil || len(allMods.modules) != 1 { 1383*1fa6dee9SAndroid Build Coastguard Worker mods := moduleList{} 1384*1fa6dee9SAndroid Build Coastguard Worker if allMods != nil { 1385*1fa6dee9SAndroid Build Coastguard Worker mods = allMods.modules 1386*1fa6dee9SAndroid Build Coastguard Worker } 1387*1fa6dee9SAndroid Build Coastguard Worker t.Errorf("expected to find one definition for module %q, but got %v", modName, mods) 1388*1fa6dee9SAndroid Build Coastguard Worker } 1389*1fa6dee9SAndroid Build Coastguard Worker } 1390*1fa6dee9SAndroid Build Coastguard Worker 1391*1fa6dee9SAndroid Build Coastguard Worker for _, modName := range tc.unexpectedModuleDefs { 1392*1fa6dee9SAndroid Build Coastguard Worker allMods := ctx.moduleGroupFromName(modName, nil) 1393*1fa6dee9SAndroid Build Coastguard Worker if allMods != nil { 1394*1fa6dee9SAndroid Build Coastguard Worker t.Errorf("expected to find no definitions for module %q, but got %v", modName, allMods.modules) 1395*1fa6dee9SAndroid Build Coastguard Worker } 1396*1fa6dee9SAndroid Build Coastguard Worker } 1397*1fa6dee9SAndroid Build Coastguard Worker }) 1398*1fa6dee9SAndroid Build Coastguard Worker } 1399*1fa6dee9SAndroid Build Coastguard Worker} 1400*1fa6dee9SAndroid Build Coastguard Worker 1401*1fa6dee9SAndroid Build Coastguard Workerfunc incrementalSetup(t *testing.T) *Context { 1402*1fa6dee9SAndroid Build Coastguard Worker ctx := NewContext() 1403*1fa6dee9SAndroid Build Coastguard Worker fileSystem := map[string][]byte{ 1404*1fa6dee9SAndroid Build Coastguard Worker "Android.bp": []byte(` 1405*1fa6dee9SAndroid Build Coastguard Worker incremental_module { 1406*1fa6dee9SAndroid Build Coastguard Worker name: "MyIncrementalModule", 1407*1fa6dee9SAndroid Build Coastguard Worker deps: ["MyBarModule"], 1408*1fa6dee9SAndroid Build Coastguard Worker } 1409*1fa6dee9SAndroid Build Coastguard Worker 1410*1fa6dee9SAndroid Build Coastguard Worker bar_module { 1411*1fa6dee9SAndroid Build Coastguard Worker name: "MyBarModule", 1412*1fa6dee9SAndroid Build Coastguard Worker } 1413*1fa6dee9SAndroid Build Coastguard Worker `), 1414*1fa6dee9SAndroid Build Coastguard Worker } 1415*1fa6dee9SAndroid Build Coastguard Worker ctx.MockFileSystem(fileSystem) 1416*1fa6dee9SAndroid Build Coastguard Worker ctx.RegisterBottomUpMutator("deps", depsMutator) 1417*1fa6dee9SAndroid Build Coastguard Worker ctx.RegisterModuleType("incremental_module", newIncrementalModule) 1418*1fa6dee9SAndroid Build Coastguard Worker ctx.RegisterModuleType("bar_module", newBarModule) 1419*1fa6dee9SAndroid Build Coastguard Worker 1420*1fa6dee9SAndroid Build Coastguard Worker _, errs := ctx.ParseBlueprintsFiles("Android.bp", nil) 1421*1fa6dee9SAndroid Build Coastguard Worker if len(errs) > 0 { 1422*1fa6dee9SAndroid Build Coastguard Worker t.Errorf("unexpected parse errors:") 1423*1fa6dee9SAndroid Build Coastguard Worker for _, err := range errs { 1424*1fa6dee9SAndroid Build Coastguard Worker t.Errorf(" %s", err) 1425*1fa6dee9SAndroid Build Coastguard Worker } 1426*1fa6dee9SAndroid Build Coastguard Worker t.FailNow() 1427*1fa6dee9SAndroid Build Coastguard Worker } 1428*1fa6dee9SAndroid Build Coastguard Worker 1429*1fa6dee9SAndroid Build Coastguard Worker _, errs = ctx.ResolveDependencies(nil) 1430*1fa6dee9SAndroid Build Coastguard Worker if len(errs) > 0 { 1431*1fa6dee9SAndroid Build Coastguard Worker t.Errorf("unexpected dep errors:") 1432*1fa6dee9SAndroid Build Coastguard Worker for _, err := range errs { 1433*1fa6dee9SAndroid Build Coastguard Worker t.Errorf(" %s", err) 1434*1fa6dee9SAndroid Build Coastguard Worker } 1435*1fa6dee9SAndroid Build Coastguard Worker t.FailNow() 1436*1fa6dee9SAndroid Build Coastguard Worker } 1437*1fa6dee9SAndroid Build Coastguard Worker 1438*1fa6dee9SAndroid Build Coastguard Worker return ctx 1439*1fa6dee9SAndroid Build Coastguard Worker} 1440*1fa6dee9SAndroid Build Coastguard Worker 1441*1fa6dee9SAndroid Build Coastguard Workerfunc incrementalSetupForRestore(t *testing.T, orderOnlyStrings []string) (*Context, any) { 1442*1fa6dee9SAndroid Build Coastguard Worker ctx := incrementalSetup(t) 1443*1fa6dee9SAndroid Build Coastguard Worker incInfo := ctx.moduleGroupFromName("MyIncrementalModule", nil).modules.firstModule() 1444*1fa6dee9SAndroid Build Coastguard Worker barInfo := ctx.moduleGroupFromName("MyBarModule", nil).modules.firstModule() 1445*1fa6dee9SAndroid Build Coastguard Worker 1446*1fa6dee9SAndroid Build Coastguard Worker providerHashes := make([]uint64, len(providerRegistry)) 1447*1fa6dee9SAndroid Build Coastguard Worker // Use fixed value since SetProvider hasn't been called yet, so we can't go 1448*1fa6dee9SAndroid Build Coastguard Worker // through the providers of the module. 1449*1fa6dee9SAndroid Build Coastguard Worker for k, v := range map[providerKey]any{ 1450*1fa6dee9SAndroid Build Coastguard Worker IncrementalTestProviderKey.providerKey: IncrementalTestProvider{ 1451*1fa6dee9SAndroid Build Coastguard Worker Value: barInfo.Name(), 1452*1fa6dee9SAndroid Build Coastguard Worker }, 1453*1fa6dee9SAndroid Build Coastguard Worker } { 1454*1fa6dee9SAndroid Build Coastguard Worker hash, err := proptools.CalculateHash(v) 1455*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 1456*1fa6dee9SAndroid Build Coastguard Worker panic(fmt.Sprintf("Can't hash value of providers")) 1457*1fa6dee9SAndroid Build Coastguard Worker } 1458*1fa6dee9SAndroid Build Coastguard Worker providerHashes[k.id] = hash 1459*1fa6dee9SAndroid Build Coastguard Worker } 1460*1fa6dee9SAndroid Build Coastguard Worker cacheKey := calculateHashKey(incInfo, [][]uint64{providerHashes}) 1461*1fa6dee9SAndroid Build Coastguard Worker var providerValue any = IncrementalTestProvider{Value: "MyIncrementalModule"} 1462*1fa6dee9SAndroid Build Coastguard Worker toCache := BuildActionCache{ 1463*1fa6dee9SAndroid Build Coastguard Worker cacheKey: &BuildActionCachedData{ 1464*1fa6dee9SAndroid Build Coastguard Worker Pos: &scanner.Position{ 1465*1fa6dee9SAndroid Build Coastguard Worker Filename: "Android.bp", 1466*1fa6dee9SAndroid Build Coastguard Worker Line: 2, 1467*1fa6dee9SAndroid Build Coastguard Worker Column: 4, 1468*1fa6dee9SAndroid Build Coastguard Worker Offset: 4, 1469*1fa6dee9SAndroid Build Coastguard Worker }, 1470*1fa6dee9SAndroid Build Coastguard Worker Providers: []CachedProvider{{ 1471*1fa6dee9SAndroid Build Coastguard Worker Id: &IncrementalTestProviderKey.providerKey, 1472*1fa6dee9SAndroid Build Coastguard Worker Value: &providerValue, 1473*1fa6dee9SAndroid Build Coastguard Worker }}, 1474*1fa6dee9SAndroid Build Coastguard Worker OrderOnlyStrings: orderOnlyStrings, 1475*1fa6dee9SAndroid Build Coastguard Worker }, 1476*1fa6dee9SAndroid Build Coastguard Worker } 1477*1fa6dee9SAndroid Build Coastguard Worker ctx.SetIncrementalEnabled(true) 1478*1fa6dee9SAndroid Build Coastguard Worker ctx.SetIncrementalAnalysis(true) 1479*1fa6dee9SAndroid Build Coastguard Worker ctx.buildActionsFromCache = toCache 1480*1fa6dee9SAndroid Build Coastguard Worker 1481*1fa6dee9SAndroid Build Coastguard Worker return ctx, providerValue 1482*1fa6dee9SAndroid Build Coastguard Worker} 1483*1fa6dee9SAndroid Build Coastguard Worker 1484*1fa6dee9SAndroid Build Coastguard Workerfunc calculateHashKey(m *moduleInfo, providerHashes [][]uint64) BuildActionCacheKey { 1485*1fa6dee9SAndroid Build Coastguard Worker hash, err := proptools.CalculateHash(m.properties) 1486*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 1487*1fa6dee9SAndroid Build Coastguard Worker panic(newPanicErrorf(err, "failed to calculate properties hash")) 1488*1fa6dee9SAndroid Build Coastguard Worker } 1489*1fa6dee9SAndroid Build Coastguard Worker cacheInput := new(BuildActionCacheInput) 1490*1fa6dee9SAndroid Build Coastguard Worker cacheInput.PropertiesHash = hash 1491*1fa6dee9SAndroid Build Coastguard Worker cacheInput.ProvidersHash = providerHashes 1492*1fa6dee9SAndroid Build Coastguard Worker hash, err = proptools.CalculateHash(&cacheInput) 1493*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 1494*1fa6dee9SAndroid Build Coastguard Worker panic(newPanicErrorf(err, "failed to calculate cache input hash")) 1495*1fa6dee9SAndroid Build Coastguard Worker } 1496*1fa6dee9SAndroid Build Coastguard Worker return BuildActionCacheKey{ 1497*1fa6dee9SAndroid Build Coastguard Worker Id: m.ModuleCacheKey(), 1498*1fa6dee9SAndroid Build Coastguard Worker InputHash: hash, 1499*1fa6dee9SAndroid Build Coastguard Worker } 1500*1fa6dee9SAndroid Build Coastguard Worker} 1501*1fa6dee9SAndroid Build Coastguard Worker 1502*1fa6dee9SAndroid Build Coastguard Workerfunc TestCacheBuildActions(t *testing.T) { 1503*1fa6dee9SAndroid Build Coastguard Worker ctx := incrementalSetup(t) 1504*1fa6dee9SAndroid Build Coastguard Worker ctx.SetIncrementalEnabled(true) 1505*1fa6dee9SAndroid Build Coastguard Worker 1506*1fa6dee9SAndroid Build Coastguard Worker _, errs := ctx.PrepareBuildActions(nil) 1507*1fa6dee9SAndroid Build Coastguard Worker if len(errs) > 0 { 1508*1fa6dee9SAndroid Build Coastguard Worker t.Errorf("unexpected errors calling generateModuleBuildActions:") 1509*1fa6dee9SAndroid Build Coastguard Worker for _, err := range errs { 1510*1fa6dee9SAndroid Build Coastguard Worker t.Errorf(" %s", err) 1511*1fa6dee9SAndroid Build Coastguard Worker } 1512*1fa6dee9SAndroid Build Coastguard Worker t.FailNow() 1513*1fa6dee9SAndroid Build Coastguard Worker } 1514*1fa6dee9SAndroid Build Coastguard Worker 1515*1fa6dee9SAndroid Build Coastguard Worker incInfo := ctx.moduleGroupFromName("MyIncrementalModule", nil).modules.firstModule() 1516*1fa6dee9SAndroid Build Coastguard Worker barInfo := ctx.moduleGroupFromName("MyBarModule", nil).modules.firstModule() 1517*1fa6dee9SAndroid Build Coastguard Worker if len(ctx.buildActionsToCache) != 1 { 1518*1fa6dee9SAndroid Build Coastguard Worker t.Errorf("build actions are not cached for the incremental module") 1519*1fa6dee9SAndroid Build Coastguard Worker } 1520*1fa6dee9SAndroid Build Coastguard Worker cacheKey := calculateHashKey(incInfo, [][]uint64{barInfo.providerInitialValueHashes}) 1521*1fa6dee9SAndroid Build Coastguard Worker cache := ctx.buildActionsToCache[cacheKey] 1522*1fa6dee9SAndroid Build Coastguard Worker if cache == nil { 1523*1fa6dee9SAndroid Build Coastguard Worker t.Errorf("failed to find cached build actions for the incremental module") 1524*1fa6dee9SAndroid Build Coastguard Worker } 1525*1fa6dee9SAndroid Build Coastguard Worker var providerValue any = IncrementalTestProvider{Value: "MyIncrementalModule"} 1526*1fa6dee9SAndroid Build Coastguard Worker expectedCache := BuildActionCachedData{ 1527*1fa6dee9SAndroid Build Coastguard Worker Pos: &scanner.Position{ 1528*1fa6dee9SAndroid Build Coastguard Worker Filename: "Android.bp", 1529*1fa6dee9SAndroid Build Coastguard Worker Line: 2, 1530*1fa6dee9SAndroid Build Coastguard Worker Column: 4, 1531*1fa6dee9SAndroid Build Coastguard Worker Offset: 4, 1532*1fa6dee9SAndroid Build Coastguard Worker }, 1533*1fa6dee9SAndroid Build Coastguard Worker Providers: []CachedProvider{{ 1534*1fa6dee9SAndroid Build Coastguard Worker Id: &IncrementalTestProviderKey.providerKey, 1535*1fa6dee9SAndroid Build Coastguard Worker Value: &providerValue, 1536*1fa6dee9SAndroid Build Coastguard Worker }}, 1537*1fa6dee9SAndroid Build Coastguard Worker } 1538*1fa6dee9SAndroid Build Coastguard Worker if !reflect.DeepEqual(expectedCache, *cache) { 1539*1fa6dee9SAndroid Build Coastguard Worker t.Errorf("expected: %v actual %v", expectedCache, *cache) 1540*1fa6dee9SAndroid Build Coastguard Worker } 1541*1fa6dee9SAndroid Build Coastguard Worker} 1542*1fa6dee9SAndroid Build Coastguard Worker 1543*1fa6dee9SAndroid Build Coastguard Workerfunc TestRestoreBuildActions(t *testing.T) { 1544*1fa6dee9SAndroid Build Coastguard Worker ctx, providerValue := incrementalSetupForRestore(t, nil) 1545*1fa6dee9SAndroid Build Coastguard Worker incInfo := ctx.moduleGroupFromName("MyIncrementalModule", nil).modules.firstModule() 1546*1fa6dee9SAndroid Build Coastguard Worker barInfo := ctx.moduleGroupFromName("MyBarModule", nil).modules.firstModule() 1547*1fa6dee9SAndroid Build Coastguard Worker _, errs := ctx.PrepareBuildActions(nil) 1548*1fa6dee9SAndroid Build Coastguard Worker if len(errs) > 0 { 1549*1fa6dee9SAndroid Build Coastguard Worker t.Errorf("unexpected errors calling generateModuleBuildActions:") 1550*1fa6dee9SAndroid Build Coastguard Worker for _, err := range errs { 1551*1fa6dee9SAndroid Build Coastguard Worker t.Errorf(" %s", err) 1552*1fa6dee9SAndroid Build Coastguard Worker } 1553*1fa6dee9SAndroid Build Coastguard Worker t.FailNow() 1554*1fa6dee9SAndroid Build Coastguard Worker } 1555*1fa6dee9SAndroid Build Coastguard Worker 1556*1fa6dee9SAndroid Build Coastguard Worker // Verify that the GenerateBuildActions was skipped for the incremental module 1557*1fa6dee9SAndroid Build Coastguard Worker incRerun := incInfo.logicModule.(*incrementalModule).GenerateBuildActionsCalled 1558*1fa6dee9SAndroid Build Coastguard Worker barRerun := barInfo.logicModule.(*barModule).GenerateBuildActionsCalled 1559*1fa6dee9SAndroid Build Coastguard Worker if incRerun || !barRerun { 1560*1fa6dee9SAndroid Build Coastguard Worker t.Errorf("failed to skip/rerun GenerateBuildActions: %t %t", incRerun, barRerun) 1561*1fa6dee9SAndroid Build Coastguard Worker } 1562*1fa6dee9SAndroid Build Coastguard Worker // Verify that the provider is set correctly for the incremental module 1563*1fa6dee9SAndroid Build Coastguard Worker if !reflect.DeepEqual(incInfo.providers[IncrementalTestProviderKey.id], providerValue) { 1564*1fa6dee9SAndroid Build Coastguard Worker t.Errorf("provider is not set correctly when restoring from cache") 1565*1fa6dee9SAndroid Build Coastguard Worker } 1566*1fa6dee9SAndroid Build Coastguard Worker} 1567*1fa6dee9SAndroid Build Coastguard Worker 1568*1fa6dee9SAndroid Build Coastguard Workerfunc TestSkipNinjaForCacheHit(t *testing.T) { 1569*1fa6dee9SAndroid Build Coastguard Worker ctx, _ := incrementalSetupForRestore(t, nil) 1570*1fa6dee9SAndroid Build Coastguard Worker _, errs := ctx.PrepareBuildActions(nil) 1571*1fa6dee9SAndroid Build Coastguard Worker if len(errs) > 0 { 1572*1fa6dee9SAndroid Build Coastguard Worker t.Errorf("unexpected errors calling generateModuleBuildActions:") 1573*1fa6dee9SAndroid Build Coastguard Worker for _, err := range errs { 1574*1fa6dee9SAndroid Build Coastguard Worker t.Errorf(" %s", err) 1575*1fa6dee9SAndroid Build Coastguard Worker } 1576*1fa6dee9SAndroid Build Coastguard Worker t.FailNow() 1577*1fa6dee9SAndroid Build Coastguard Worker } 1578*1fa6dee9SAndroid Build Coastguard Worker 1579*1fa6dee9SAndroid Build Coastguard Worker buf := bytes.NewBuffer(nil) 1580*1fa6dee9SAndroid Build Coastguard Worker w := newNinjaWriter(buf) 1581*1fa6dee9SAndroid Build Coastguard Worker ctx.writeAllModuleActions(w, true, "test.ninja") 1582*1fa6dee9SAndroid Build Coastguard Worker // Verify that soong updated the ninja file for the bar module and skipped the 1583*1fa6dee9SAndroid Build Coastguard Worker // ninja file writing of the incremental module 1584*1fa6dee9SAndroid Build Coastguard Worker file, err := ctx.fs.Open("test.0.ninja") 1585*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 1586*1fa6dee9SAndroid Build Coastguard Worker t.Errorf("no ninja file for MyBarModule") 1587*1fa6dee9SAndroid Build Coastguard Worker } 1588*1fa6dee9SAndroid Build Coastguard Worker content := make([]byte, 1024) 1589*1fa6dee9SAndroid Build Coastguard Worker file.Read(content) 1590*1fa6dee9SAndroid Build Coastguard Worker if !strings.Contains(string(content), "build MyBarModule_phony_output: phony") { 1591*1fa6dee9SAndroid Build Coastguard Worker t.Errorf("ninja file doesn't have build statements for MyBarModule: %s", string(content)) 1592*1fa6dee9SAndroid Build Coastguard Worker } 1593*1fa6dee9SAndroid Build Coastguard Worker 1594*1fa6dee9SAndroid Build Coastguard Worker file, err = ctx.fs.Open("test_incremental_ninja/.-MyIncrementalModule-none-incremental_module.ninja") 1595*1fa6dee9SAndroid Build Coastguard Worker if !os.IsNotExist(err) { 1596*1fa6dee9SAndroid Build Coastguard Worker t.Errorf("shouldn't generate ninja file for MyIncrementalModule: %s", err.Error()) 1597*1fa6dee9SAndroid Build Coastguard Worker } 1598*1fa6dee9SAndroid Build Coastguard Worker} 1599*1fa6dee9SAndroid Build Coastguard Worker 1600*1fa6dee9SAndroid Build Coastguard Workerfunc TestNotSkipNinjaForCacheMiss(t *testing.T) { 1601*1fa6dee9SAndroid Build Coastguard Worker ctx := incrementalSetup(t) 1602*1fa6dee9SAndroid Build Coastguard Worker ctx.SetIncrementalEnabled(true) 1603*1fa6dee9SAndroid Build Coastguard Worker ctx.SetIncrementalAnalysis(true) 1604*1fa6dee9SAndroid Build Coastguard Worker _, errs := ctx.PrepareBuildActions(nil) 1605*1fa6dee9SAndroid Build Coastguard Worker if len(errs) > 0 { 1606*1fa6dee9SAndroid Build Coastguard Worker t.Errorf("unexpected errors calling generateModuleBuildActions:") 1607*1fa6dee9SAndroid Build Coastguard Worker for _, err := range errs { 1608*1fa6dee9SAndroid Build Coastguard Worker t.Errorf(" %s", err) 1609*1fa6dee9SAndroid Build Coastguard Worker } 1610*1fa6dee9SAndroid Build Coastguard Worker t.FailNow() 1611*1fa6dee9SAndroid Build Coastguard Worker } 1612*1fa6dee9SAndroid Build Coastguard Worker 1613*1fa6dee9SAndroid Build Coastguard Worker buf := bytes.NewBuffer(nil) 1614*1fa6dee9SAndroid Build Coastguard Worker w := newNinjaWriter(buf) 1615*1fa6dee9SAndroid Build Coastguard Worker ctx.writeAllModuleActions(w, true, "test.ninja") 1616*1fa6dee9SAndroid Build Coastguard Worker // Verify that soong updated the ninja files for both the bar module and the 1617*1fa6dee9SAndroid Build Coastguard Worker // incremental module 1618*1fa6dee9SAndroid Build Coastguard Worker file, err := ctx.fs.Open("test.0.ninja") 1619*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 1620*1fa6dee9SAndroid Build Coastguard Worker t.Errorf("no ninja file for MyBarModule") 1621*1fa6dee9SAndroid Build Coastguard Worker } 1622*1fa6dee9SAndroid Build Coastguard Worker content := make([]byte, 1024) 1623*1fa6dee9SAndroid Build Coastguard Worker file.Read(content) 1624*1fa6dee9SAndroid Build Coastguard Worker if !strings.Contains(string(content), "build MyBarModule_phony_output: phony") { 1625*1fa6dee9SAndroid Build Coastguard Worker t.Errorf("ninja file doesn't have build statements for MyBarModule: %s", string(content)) 1626*1fa6dee9SAndroid Build Coastguard Worker } 1627*1fa6dee9SAndroid Build Coastguard Worker 1628*1fa6dee9SAndroid Build Coastguard Worker file, err = ctx.fs.Open("test_incremental_ninja/.-MyIncrementalModule-none-incremental_module.ninja") 1629*1fa6dee9SAndroid Build Coastguard Worker if err != nil { 1630*1fa6dee9SAndroid Build Coastguard Worker t.Errorf("no ninja file for MyIncrementalModule") 1631*1fa6dee9SAndroid Build Coastguard Worker } 1632*1fa6dee9SAndroid Build Coastguard Worker file.Read(content) 1633*1fa6dee9SAndroid Build Coastguard Worker if !strings.Contains(string(content), "build MyIncrementalModule_phony_output: phony") { 1634*1fa6dee9SAndroid Build Coastguard Worker t.Errorf("ninja file doesn't have build statements for MyIncrementalModule: %s", string(content)) 1635*1fa6dee9SAndroid Build Coastguard Worker } 1636*1fa6dee9SAndroid Build Coastguard Worker} 1637*1fa6dee9SAndroid Build Coastguard Worker 1638*1fa6dee9SAndroid Build Coastguard Workerfunc TestOrderOnlyStringsCaching(t *testing.T) { 1639*1fa6dee9SAndroid Build Coastguard Worker ctx := incrementalSetup(t) 1640*1fa6dee9SAndroid Build Coastguard Worker ctx.SetIncrementalEnabled(true) 1641*1fa6dee9SAndroid Build Coastguard Worker _, errs := ctx.PrepareBuildActions(nil) 1642*1fa6dee9SAndroid Build Coastguard Worker if len(errs) > 0 { 1643*1fa6dee9SAndroid Build Coastguard Worker t.Errorf("unexpected errors calling generateModuleBuildActions:") 1644*1fa6dee9SAndroid Build Coastguard Worker for _, err := range errs { 1645*1fa6dee9SAndroid Build Coastguard Worker t.Errorf(" %s", err) 1646*1fa6dee9SAndroid Build Coastguard Worker } 1647*1fa6dee9SAndroid Build Coastguard Worker t.FailNow() 1648*1fa6dee9SAndroid Build Coastguard Worker } 1649*1fa6dee9SAndroid Build Coastguard Worker incInfo := ctx.moduleGroupFromName("MyIncrementalModule", nil).modules.firstModule() 1650*1fa6dee9SAndroid Build Coastguard Worker barInfo := ctx.moduleGroupFromName("MyBarModule", nil).modules.firstModule() 1651*1fa6dee9SAndroid Build Coastguard Worker bDef := buildDef{ 1652*1fa6dee9SAndroid Build Coastguard Worker Rule: Phony, 1653*1fa6dee9SAndroid Build Coastguard Worker OrderOnlyStrings: []string{"test.lib"}, 1654*1fa6dee9SAndroid Build Coastguard Worker } 1655*1fa6dee9SAndroid Build Coastguard Worker incInfo.actionDefs.buildDefs = append(incInfo.actionDefs.buildDefs, &bDef) 1656*1fa6dee9SAndroid Build Coastguard Worker barInfo.actionDefs.buildDefs = append(barInfo.actionDefs.buildDefs, &bDef) 1657*1fa6dee9SAndroid Build Coastguard Worker 1658*1fa6dee9SAndroid Build Coastguard Worker buf := bytes.NewBuffer(nil) 1659*1fa6dee9SAndroid Build Coastguard Worker w := newNinjaWriter(buf) 1660*1fa6dee9SAndroid Build Coastguard Worker ctx.writeAllModuleActions(w, true, "test.ninja") 1661*1fa6dee9SAndroid Build Coastguard Worker 1662*1fa6dee9SAndroid Build Coastguard Worker verifyOrderOnlyStringsCache(t, ctx, incInfo, barInfo) 1663*1fa6dee9SAndroid Build Coastguard Worker} 1664*1fa6dee9SAndroid Build Coastguard Worker 1665*1fa6dee9SAndroid Build Coastguard Workerfunc TestOrderOnlyStringsRestoring(t *testing.T) { 1666*1fa6dee9SAndroid Build Coastguard Worker phony := "dedup-d479e9a8133ff998" 1667*1fa6dee9SAndroid Build Coastguard Worker orderOnlyStrings := []string{phony} 1668*1fa6dee9SAndroid Build Coastguard Worker ctx, _ := incrementalSetupForRestore(t, orderOnlyStrings) 1669*1fa6dee9SAndroid Build Coastguard Worker ctx.orderOnlyStringsFromCache = make(OrderOnlyStringsCache) 1670*1fa6dee9SAndroid Build Coastguard Worker ctx.orderOnlyStringsFromCache[phony] = []string{"test.lib"} 1671*1fa6dee9SAndroid Build Coastguard Worker _, errs := ctx.PrepareBuildActions(nil) 1672*1fa6dee9SAndroid Build Coastguard Worker if len(errs) > 0 { 1673*1fa6dee9SAndroid Build Coastguard Worker t.Errorf("unexpected errors calling generateModuleBuildActions:") 1674*1fa6dee9SAndroid Build Coastguard Worker for _, err := range errs { 1675*1fa6dee9SAndroid Build Coastguard Worker t.Errorf(" %s", err) 1676*1fa6dee9SAndroid Build Coastguard Worker } 1677*1fa6dee9SAndroid Build Coastguard Worker t.FailNow() 1678*1fa6dee9SAndroid Build Coastguard Worker } 1679*1fa6dee9SAndroid Build Coastguard Worker 1680*1fa6dee9SAndroid Build Coastguard Worker buf := bytes.NewBuffer(nil) 1681*1fa6dee9SAndroid Build Coastguard Worker w := newNinjaWriter(buf) 1682*1fa6dee9SAndroid Build Coastguard Worker ctx.writeAllModuleActions(w, true, "test.ninja") 1683*1fa6dee9SAndroid Build Coastguard Worker 1684*1fa6dee9SAndroid Build Coastguard Worker incInfo := ctx.moduleGroupFromName("MyIncrementalModule", nil).modules.firstModule() 1685*1fa6dee9SAndroid Build Coastguard Worker barInfo := ctx.moduleGroupFromName("MyBarModule", nil).modules.firstModule() 1686*1fa6dee9SAndroid Build Coastguard Worker verifyOrderOnlyStringsCache(t, ctx, incInfo, barInfo) 1687*1fa6dee9SAndroid Build Coastguard Worker 1688*1fa6dee9SAndroid Build Coastguard Worker // Verify dedup-d479e9a8133ff998 is still written to the common ninja file even 1689*1fa6dee9SAndroid Build Coastguard Worker // though MyBarModule no longer uses it. 1690*1fa6dee9SAndroid Build Coastguard Worker expected := strings.Join([]string{"build", phony + ":", "phony", "test.lib"}, " ") 1691*1fa6dee9SAndroid Build Coastguard Worker if !strings.Contains(buf.String(), expected) { 1692*1fa6dee9SAndroid Build Coastguard Worker t.Errorf("phony target not found: %s", buf.String()) 1693*1fa6dee9SAndroid Build Coastguard Worker } 1694*1fa6dee9SAndroid Build Coastguard Worker} 1695*1fa6dee9SAndroid Build Coastguard Worker 1696*1fa6dee9SAndroid Build Coastguard Workerfunc verifyOrderOnlyStringsCache(t *testing.T, ctx *Context, incInfo, barInfo *moduleInfo) { 1697*1fa6dee9SAndroid Build Coastguard Worker // Verify that soong cache all the order only strings that are used by the 1698*1fa6dee9SAndroid Build Coastguard Worker // incremental modules 1699*1fa6dee9SAndroid Build Coastguard Worker ok, key := mapContainsValue(ctx.orderOnlyStringsToCache, "test.lib") 1700*1fa6dee9SAndroid Build Coastguard Worker if !ok { 1701*1fa6dee9SAndroid Build Coastguard Worker t.Errorf("no order only strings used by incremetnal modules cached: %v", ctx.orderOnlyStringsToCache) 1702*1fa6dee9SAndroid Build Coastguard Worker } 1703*1fa6dee9SAndroid Build Coastguard Worker 1704*1fa6dee9SAndroid Build Coastguard Worker // Verify that the dedup-* order only strings used by MyIncrementalModule is 1705*1fa6dee9SAndroid Build Coastguard Worker // cached along with its other cached values 1706*1fa6dee9SAndroid Build Coastguard Worker cacheKey := calculateHashKey(incInfo, [][]uint64{barInfo.providerInitialValueHashes}) 1707*1fa6dee9SAndroid Build Coastguard Worker cache := ctx.buildActionsToCache[cacheKey] 1708*1fa6dee9SAndroid Build Coastguard Worker if cache == nil { 1709*1fa6dee9SAndroid Build Coastguard Worker t.Errorf("failed to find cached build actions for the incremental module") 1710*1fa6dee9SAndroid Build Coastguard Worker } 1711*1fa6dee9SAndroid Build Coastguard Worker if !listContainsValue(cache.OrderOnlyStrings, key) { 1712*1fa6dee9SAndroid Build Coastguard Worker t.Errorf("no order only strings cached for MyIncrementalModule: %v", cache.OrderOnlyStrings) 1713*1fa6dee9SAndroid Build Coastguard Worker } 1714*1fa6dee9SAndroid Build Coastguard Worker} 1715*1fa6dee9SAndroid Build Coastguard Worker 1716*1fa6dee9SAndroid Build Coastguard Workerfunc listContainsValue[K comparable](l []K, target K) bool { 1717*1fa6dee9SAndroid Build Coastguard Worker for _, value := range l { 1718*1fa6dee9SAndroid Build Coastguard Worker if value == target { 1719*1fa6dee9SAndroid Build Coastguard Worker return true 1720*1fa6dee9SAndroid Build Coastguard Worker } 1721*1fa6dee9SAndroid Build Coastguard Worker } 1722*1fa6dee9SAndroid Build Coastguard Worker return false 1723*1fa6dee9SAndroid Build Coastguard Worker} 1724*1fa6dee9SAndroid Build Coastguard Worker 1725*1fa6dee9SAndroid Build Coastguard Workerfunc mapContainsValue[K comparable, V comparable](m map[K][]V, target V) (bool, K) { 1726*1fa6dee9SAndroid Build Coastguard Worker for k, v := range m { 1727*1fa6dee9SAndroid Build Coastguard Worker if listContainsValue(v, target) { 1728*1fa6dee9SAndroid Build Coastguard Worker return true, k 1729*1fa6dee9SAndroid Build Coastguard Worker } 1730*1fa6dee9SAndroid Build Coastguard Worker } 1731*1fa6dee9SAndroid Build Coastguard Worker var key K 1732*1fa6dee9SAndroid Build Coastguard Worker return false, key 1733*1fa6dee9SAndroid Build Coastguard Worker} 1734*1fa6dee9SAndroid Build Coastguard Worker 1735*1fa6dee9SAndroid Build Coastguard Workerfunc TestDisallowedMutatorMethods(t *testing.T) { 1736*1fa6dee9SAndroid Build Coastguard Worker testCases := []struct { 1737*1fa6dee9SAndroid Build Coastguard Worker name string 1738*1fa6dee9SAndroid Build Coastguard Worker mutatorHandleFunc func(MutatorHandle) 1739*1fa6dee9SAndroid Build Coastguard Worker mutatorFunc func(BottomUpMutatorContext) 1740*1fa6dee9SAndroid Build Coastguard Worker expectedPanic string 1741*1fa6dee9SAndroid Build Coastguard Worker }{ 1742*1fa6dee9SAndroid Build Coastguard Worker { 1743*1fa6dee9SAndroid Build Coastguard Worker name: "rename", 1744*1fa6dee9SAndroid Build Coastguard Worker mutatorHandleFunc: func(handle MutatorHandle) { handle.UsesRename() }, 1745*1fa6dee9SAndroid Build Coastguard Worker mutatorFunc: func(ctx BottomUpMutatorContext) { ctx.Rename("qux") }, 1746*1fa6dee9SAndroid Build Coastguard Worker expectedPanic: "method Rename called from mutator that was not marked UsesRename", 1747*1fa6dee9SAndroid Build Coastguard Worker }, 1748*1fa6dee9SAndroid Build Coastguard Worker { 1749*1fa6dee9SAndroid Build Coastguard Worker name: "replace_dependencies", 1750*1fa6dee9SAndroid Build Coastguard Worker mutatorHandleFunc: func(handle MutatorHandle) { handle.UsesReplaceDependencies() }, 1751*1fa6dee9SAndroid Build Coastguard Worker mutatorFunc: func(ctx BottomUpMutatorContext) { ctx.ReplaceDependencies("bar") }, 1752*1fa6dee9SAndroid Build Coastguard Worker expectedPanic: "method ReplaceDependenciesIf called from mutator that was not marked UsesReplaceDependencies", 1753*1fa6dee9SAndroid Build Coastguard Worker }, 1754*1fa6dee9SAndroid Build Coastguard Worker { 1755*1fa6dee9SAndroid Build Coastguard Worker name: "replace_dependencies_if", 1756*1fa6dee9SAndroid Build Coastguard Worker mutatorHandleFunc: func(handle MutatorHandle) { handle.UsesReplaceDependencies() }, 1757*1fa6dee9SAndroid Build Coastguard Worker mutatorFunc: func(ctx BottomUpMutatorContext) { 1758*1fa6dee9SAndroid Build Coastguard Worker ctx.ReplaceDependenciesIf("bar", func(from Module, tag DependencyTag, to Module) bool { return false }) 1759*1fa6dee9SAndroid Build Coastguard Worker }, 1760*1fa6dee9SAndroid Build Coastguard Worker expectedPanic: "method ReplaceDependenciesIf called from mutator that was not marked UsesReplaceDependencies", 1761*1fa6dee9SAndroid Build Coastguard Worker }, 1762*1fa6dee9SAndroid Build Coastguard Worker { 1763*1fa6dee9SAndroid Build Coastguard Worker name: "reverse_dependencies", 1764*1fa6dee9SAndroid Build Coastguard Worker mutatorHandleFunc: func(handle MutatorHandle) { handle.UsesReverseDependencies() }, 1765*1fa6dee9SAndroid Build Coastguard Worker mutatorFunc: func(ctx BottomUpMutatorContext) { ctx.AddReverseDependency(ctx.Module(), nil, "baz") }, 1766*1fa6dee9SAndroid Build Coastguard Worker expectedPanic: "method AddReverseDependency called from mutator that was not marked UsesReverseDependencies", 1767*1fa6dee9SAndroid Build Coastguard Worker }, 1768*1fa6dee9SAndroid Build Coastguard Worker { 1769*1fa6dee9SAndroid Build Coastguard Worker name: "create_module", 1770*1fa6dee9SAndroid Build Coastguard Worker mutatorHandleFunc: func(handle MutatorHandle) { handle.UsesCreateModule() }, 1771*1fa6dee9SAndroid Build Coastguard Worker mutatorFunc: func(ctx BottomUpMutatorContext) { 1772*1fa6dee9SAndroid Build Coastguard Worker ctx.CreateModule(newFooModule, "create_module", 1773*1fa6dee9SAndroid Build Coastguard Worker &struct{ Name string }{Name: "quz"}) 1774*1fa6dee9SAndroid Build Coastguard Worker }, 1775*1fa6dee9SAndroid Build Coastguard Worker expectedPanic: "method CreateModule called from mutator that was not marked UsesCreateModule", 1776*1fa6dee9SAndroid Build Coastguard Worker }, 1777*1fa6dee9SAndroid Build Coastguard Worker } 1778*1fa6dee9SAndroid Build Coastguard Worker 1779*1fa6dee9SAndroid Build Coastguard Worker runTest := func(mutatorHandleFunc func(MutatorHandle), mutatorFunc func(ctx BottomUpMutatorContext), expectedPanic string) { 1780*1fa6dee9SAndroid Build Coastguard Worker ctx := NewContext() 1781*1fa6dee9SAndroid Build Coastguard Worker 1782*1fa6dee9SAndroid Build Coastguard Worker ctx.MockFileSystem(map[string][]byte{ 1783*1fa6dee9SAndroid Build Coastguard Worker "Android.bp": []byte(` 1784*1fa6dee9SAndroid Build Coastguard Worker foo_module { 1785*1fa6dee9SAndroid Build Coastguard Worker name: "foo", 1786*1fa6dee9SAndroid Build Coastguard Worker } 1787*1fa6dee9SAndroid Build Coastguard Worker 1788*1fa6dee9SAndroid Build Coastguard Worker foo_module { 1789*1fa6dee9SAndroid Build Coastguard Worker name: "bar", 1790*1fa6dee9SAndroid Build Coastguard Worker deps: ["foo"], 1791*1fa6dee9SAndroid Build Coastguard Worker } 1792*1fa6dee9SAndroid Build Coastguard Worker 1793*1fa6dee9SAndroid Build Coastguard Worker foo_module { 1794*1fa6dee9SAndroid Build Coastguard Worker name: "baz", 1795*1fa6dee9SAndroid Build Coastguard Worker } 1796*1fa6dee9SAndroid Build Coastguard Worker `)}) 1797*1fa6dee9SAndroid Build Coastguard Worker 1798*1fa6dee9SAndroid Build Coastguard Worker ctx.RegisterModuleType("foo_module", newFooModule) 1799*1fa6dee9SAndroid Build Coastguard Worker ctx.RegisterBottomUpMutator("deps", depsMutator) 1800*1fa6dee9SAndroid Build Coastguard Worker handle := ctx.RegisterBottomUpMutator("mutator", func(ctx BottomUpMutatorContext) { 1801*1fa6dee9SAndroid Build Coastguard Worker if ctx.ModuleName() == "foo" { 1802*1fa6dee9SAndroid Build Coastguard Worker mutatorFunc(ctx) 1803*1fa6dee9SAndroid Build Coastguard Worker } 1804*1fa6dee9SAndroid Build Coastguard Worker }) 1805*1fa6dee9SAndroid Build Coastguard Worker mutatorHandleFunc(handle) 1806*1fa6dee9SAndroid Build Coastguard Worker 1807*1fa6dee9SAndroid Build Coastguard Worker _, errs := ctx.ParseBlueprintsFiles("Android.bp", nil) 1808*1fa6dee9SAndroid Build Coastguard Worker if len(errs) > 0 { 1809*1fa6dee9SAndroid Build Coastguard Worker t.Errorf("unexpected parse errors:") 1810*1fa6dee9SAndroid Build Coastguard Worker for _, err := range errs { 1811*1fa6dee9SAndroid Build Coastguard Worker t.Errorf(" %s", err) 1812*1fa6dee9SAndroid Build Coastguard Worker } 1813*1fa6dee9SAndroid Build Coastguard Worker t.FailNow() 1814*1fa6dee9SAndroid Build Coastguard Worker } 1815*1fa6dee9SAndroid Build Coastguard Worker 1816*1fa6dee9SAndroid Build Coastguard Worker _, errs = ctx.ResolveDependencies(nil) 1817*1fa6dee9SAndroid Build Coastguard Worker if expectedPanic != "" { 1818*1fa6dee9SAndroid Build Coastguard Worker if len(errs) == 0 { 1819*1fa6dee9SAndroid Build Coastguard Worker t.Errorf("missing expected error %q", expectedPanic) 1820*1fa6dee9SAndroid Build Coastguard Worker } else if !strings.Contains(errs[0].Error(), expectedPanic) { 1821*1fa6dee9SAndroid Build Coastguard Worker t.Errorf("missing expected error %q in %q", expectedPanic, errs[0].Error()) 1822*1fa6dee9SAndroid Build Coastguard Worker } 1823*1fa6dee9SAndroid Build Coastguard Worker } else if len(errs) > 0 { 1824*1fa6dee9SAndroid Build Coastguard Worker t.Errorf("unexpected dep errors:") 1825*1fa6dee9SAndroid Build Coastguard Worker for _, err := range errs { 1826*1fa6dee9SAndroid Build Coastguard Worker t.Errorf(" %s", err) 1827*1fa6dee9SAndroid Build Coastguard Worker } 1828*1fa6dee9SAndroid Build Coastguard Worker t.FailNow() 1829*1fa6dee9SAndroid Build Coastguard Worker } 1830*1fa6dee9SAndroid Build Coastguard Worker } 1831*1fa6dee9SAndroid Build Coastguard Worker 1832*1fa6dee9SAndroid Build Coastguard Worker noopMutatorHandleFunc := func(MutatorHandle) {} 1833*1fa6dee9SAndroid Build Coastguard Worker 1834*1fa6dee9SAndroid Build Coastguard Worker for _, testCase := range testCases { 1835*1fa6dee9SAndroid Build Coastguard Worker t.Run(testCase.name, func(t *testing.T) { 1836*1fa6dee9SAndroid Build Coastguard Worker t.Run("allowed", func(t *testing.T) { 1837*1fa6dee9SAndroid Build Coastguard Worker // Test that the method doesn't panic when the handle function is called. 1838*1fa6dee9SAndroid Build Coastguard Worker runTest(testCase.mutatorHandleFunc, testCase.mutatorFunc, "") 1839*1fa6dee9SAndroid Build Coastguard Worker }) 1840*1fa6dee9SAndroid Build Coastguard Worker t.Run("disallowed", func(t *testing.T) { 1841*1fa6dee9SAndroid Build Coastguard Worker // Test that the method does panic with the expected error when the 1842*1fa6dee9SAndroid Build Coastguard Worker // handle function is not called. 1843*1fa6dee9SAndroid Build Coastguard Worker runTest(noopMutatorHandleFunc, testCase.mutatorFunc, testCase.expectedPanic) 1844*1fa6dee9SAndroid Build Coastguard Worker }) 1845*1fa6dee9SAndroid Build Coastguard Worker }) 1846*1fa6dee9SAndroid Build Coastguard Worker } 1847*1fa6dee9SAndroid Build Coastguard Worker 1848*1fa6dee9SAndroid Build Coastguard Worker} 1849