• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright 2014 Google Inc. All rights reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package blueprint
16
17import (
18	"bytes"
19	"errors"
20	"fmt"
21	"path/filepath"
22	"reflect"
23	"strings"
24	"sync"
25	"testing"
26	"time"
27
28	"github.com/google/blueprint/parser"
29)
30
31type Walker interface {
32	Walk() bool
33}
34
35func walkDependencyGraph(ctx *Context, topModule *moduleInfo, allowDuplicates bool) (string, string) {
36	var outputDown string
37	var outputUp string
38	ctx.walkDeps(topModule, allowDuplicates,
39		func(dep depInfo, parent *moduleInfo) bool {
40			outputDown += ctx.ModuleName(dep.module.logicModule)
41			if tag, ok := dep.tag.(walkerDepsTag); ok {
42				if !tag.follow {
43					return false
44				}
45			}
46			if dep.module.logicModule.(Walker).Walk() {
47				return true
48			}
49
50			return false
51		},
52		func(dep depInfo, parent *moduleInfo) {
53			outputUp += ctx.ModuleName(dep.module.logicModule)
54		})
55	return outputDown, outputUp
56}
57
58type depsProvider interface {
59	Deps() []string
60	IgnoreDeps() []string
61}
62
63type fooModule struct {
64	SimpleName
65	properties struct {
66		Deps         []string
67		Ignored_deps []string
68		Foo          string
69	}
70}
71
72func newFooModule() (Module, []interface{}) {
73	m := &fooModule{}
74	return m, []interface{}{&m.properties, &m.SimpleName.Properties}
75}
76
77func (f *fooModule) GenerateBuildActions(ModuleContext) {
78}
79
80func (f *fooModule) Deps() []string {
81	return f.properties.Deps
82}
83
84func (f *fooModule) IgnoreDeps() []string {
85	return f.properties.Ignored_deps
86}
87
88func (f *fooModule) Foo() string {
89	return f.properties.Foo
90}
91
92func (f *fooModule) Walk() bool {
93	return true
94}
95
96type barModule struct {
97	SimpleName
98	properties struct {
99		Deps         []string
100		Ignored_deps []string
101		Bar          bool
102	}
103}
104
105func newBarModule() (Module, []interface{}) {
106	m := &barModule{}
107	return m, []interface{}{&m.properties, &m.SimpleName.Properties}
108}
109
110func (b *barModule) Deps() []string {
111	return b.properties.Deps
112}
113
114func (b *barModule) IgnoreDeps() []string {
115	return b.properties.Ignored_deps
116}
117
118func (b *barModule) GenerateBuildActions(ModuleContext) {
119}
120
121func (b *barModule) Bar() bool {
122	return b.properties.Bar
123}
124
125func (b *barModule) Walk() bool {
126	return false
127}
128
129type walkerDepsTag struct {
130	BaseDependencyTag
131	// True if the dependency should be followed, false otherwise.
132	follow bool
133}
134
135func depsMutator(mctx BottomUpMutatorContext) {
136	if m, ok := mctx.Module().(depsProvider); ok {
137		mctx.AddDependency(mctx.Module(), walkerDepsTag{follow: false}, m.IgnoreDeps()...)
138		mctx.AddDependency(mctx.Module(), walkerDepsTag{follow: true}, m.Deps()...)
139	}
140}
141
142func TestContextParse(t *testing.T) {
143	ctx := NewContext()
144	ctx.RegisterModuleType("foo_module", newFooModule)
145	ctx.RegisterModuleType("bar_module", newBarModule)
146
147	r := bytes.NewBufferString(`
148		foo_module {
149	        name: "MyFooModule",
150			deps: ["MyBarModule"],
151		}
152
153		bar_module {
154	        name: "MyBarModule",
155		}
156	`)
157
158	_, _, errs := ctx.parseOne(".", "Blueprint", r, parser.NewScope(nil), nil)
159	if len(errs) > 0 {
160		t.Errorf("unexpected parse errors:")
161		for _, err := range errs {
162			t.Errorf("  %s", err)
163		}
164		t.FailNow()
165	}
166
167	_, errs = ctx.ResolveDependencies(nil)
168	if len(errs) > 0 {
169		t.Errorf("unexpected dep errors:")
170		for _, err := range errs {
171			t.Errorf("  %s", err)
172		}
173		t.FailNow()
174	}
175}
176
177// |===B---D       - represents a non-walkable edge
178// A               = represents a walkable edge
179// |===C===E---G
180//     |       |   A should not be visited because it's the root node.
181//     |===F===|   B, D and E should not be walked.
182func TestWalkDeps(t *testing.T) {
183	ctx := NewContext()
184	ctx.MockFileSystem(map[string][]byte{
185		"Android.bp": []byte(`
186			foo_module {
187			    name: "A",
188			    deps: ["B", "C"],
189			}
190
191			bar_module {
192			    name: "B",
193			    deps: ["D"],
194			}
195
196			foo_module {
197			    name: "C",
198			    deps: ["E", "F"],
199			}
200
201			foo_module {
202			    name: "D",
203			}
204
205			bar_module {
206			    name: "E",
207			    deps: ["G"],
208			}
209
210			foo_module {
211			    name: "F",
212			    deps: ["G"],
213			}
214
215			foo_module {
216			    name: "G",
217			}
218		`),
219	})
220
221	ctx.RegisterModuleType("foo_module", newFooModule)
222	ctx.RegisterModuleType("bar_module", newBarModule)
223	ctx.RegisterBottomUpMutator("deps", depsMutator)
224	_, errs := ctx.ParseBlueprintsFiles("Android.bp", nil)
225	if len(errs) > 0 {
226		t.Errorf("unexpected parse errors:")
227		for _, err := range errs {
228			t.Errorf("  %s", err)
229		}
230		t.FailNow()
231	}
232
233	_, errs = ctx.ResolveDependencies(nil)
234	if len(errs) > 0 {
235		t.Errorf("unexpected dep errors:")
236		for _, err := range errs {
237			t.Errorf("  %s", err)
238		}
239		t.FailNow()
240	}
241
242	topModule := ctx.moduleGroupFromName("A", nil).modules.firstModule()
243	outputDown, outputUp := walkDependencyGraph(ctx, topModule, false)
244	if outputDown != "BCEFG" {
245		t.Errorf("unexpected walkDeps behaviour: %s\ndown should be: BCEFG", outputDown)
246	}
247	if outputUp != "BEGFC" {
248		t.Errorf("unexpected walkDeps behaviour: %s\nup should be: BEGFC", outputUp)
249	}
250}
251
252// |===B---D           - represents a non-walkable edge
253// A                   = represents a walkable edge
254// |===C===E===\       A should not be visited because it's the root node.
255//     |       |       B, D should not be walked.
256//     |===F===G===H   G should be visited multiple times
257//         \===/       H should only be visited once
258func TestWalkDepsDuplicates(t *testing.T) {
259	ctx := NewContext()
260	ctx.MockFileSystem(map[string][]byte{
261		"Android.bp": []byte(`
262			foo_module {
263			    name: "A",
264			    deps: ["B", "C"],
265			}
266
267			bar_module {
268			    name: "B",
269			    deps: ["D"],
270			}
271
272			foo_module {
273			    name: "C",
274			    deps: ["E", "F"],
275			}
276
277			foo_module {
278			    name: "D",
279			}
280
281			foo_module {
282			    name: "E",
283			    deps: ["G"],
284			}
285
286			foo_module {
287			    name: "F",
288			    deps: ["G", "G"],
289			}
290
291			foo_module {
292			    name: "G",
293				deps: ["H"],
294			}
295
296			foo_module {
297			    name: "H",
298			}
299		`),
300	})
301
302	ctx.RegisterModuleType("foo_module", newFooModule)
303	ctx.RegisterModuleType("bar_module", newBarModule)
304	ctx.RegisterBottomUpMutator("deps", depsMutator)
305	_, errs := ctx.ParseBlueprintsFiles("Android.bp", nil)
306	if len(errs) > 0 {
307		t.Errorf("unexpected parse errors:")
308		for _, err := range errs {
309			t.Errorf("  %s", err)
310		}
311		t.FailNow()
312	}
313
314	_, errs = ctx.ResolveDependencies(nil)
315	if len(errs) > 0 {
316		t.Errorf("unexpected dep errors:")
317		for _, err := range errs {
318			t.Errorf("  %s", err)
319		}
320		t.FailNow()
321	}
322
323	topModule := ctx.moduleGroupFromName("A", nil).modules.firstModule()
324	outputDown, outputUp := walkDependencyGraph(ctx, topModule, true)
325	if outputDown != "BCEGHFGG" {
326		t.Errorf("unexpected walkDeps behaviour: %s\ndown should be: BCEGHFGG", outputDown)
327	}
328	if outputUp != "BHGEGGFC" {
329		t.Errorf("unexpected walkDeps behaviour: %s\nup should be: BHGEGGFC", outputUp)
330	}
331}
332
333//                     - represents a non-walkable edge
334// A                   = represents a walkable edge
335// |===B-------\       A should not be visited because it's the root node.
336//     |       |       B -> D should not be walked.
337//     |===C===D===E   B -> C -> D -> E should be walked
338func TestWalkDepsDuplicates_IgnoreFirstPath(t *testing.T) {
339	ctx := NewContext()
340	ctx.MockFileSystem(map[string][]byte{
341		"Android.bp": []byte(`
342			foo_module {
343			    name: "A",
344			    deps: ["B"],
345			}
346
347			foo_module {
348			    name: "B",
349			    deps: ["C"],
350			    ignored_deps: ["D"],
351			}
352
353			foo_module {
354			    name: "C",
355			    deps: ["D"],
356			}
357
358			foo_module {
359			    name: "D",
360			    deps: ["E"],
361			}
362
363			foo_module {
364			    name: "E",
365			}
366		`),
367	})
368
369	ctx.RegisterModuleType("foo_module", newFooModule)
370	ctx.RegisterModuleType("bar_module", newBarModule)
371	ctx.RegisterBottomUpMutator("deps", depsMutator)
372	_, errs := ctx.ParseBlueprintsFiles("Android.bp", nil)
373	if len(errs) > 0 {
374		t.Errorf("unexpected parse errors:")
375		for _, err := range errs {
376			t.Errorf("  %s", err)
377		}
378		t.FailNow()
379	}
380
381	_, errs = ctx.ResolveDependencies(nil)
382	if len(errs) > 0 {
383		t.Errorf("unexpected dep errors:")
384		for _, err := range errs {
385			t.Errorf("  %s", err)
386		}
387		t.FailNow()
388	}
389
390	topModule := ctx.moduleGroupFromName("A", nil).modules.firstModule()
391	outputDown, outputUp := walkDependencyGraph(ctx, topModule, true)
392	expectedDown := "BDCDE"
393	if outputDown != expectedDown {
394		t.Errorf("unexpected walkDeps behaviour: %s\ndown should be: %s", outputDown, expectedDown)
395	}
396	expectedUp := "DEDCB"
397	if outputUp != expectedUp {
398		t.Errorf("unexpected walkDeps behaviour: %s\nup should be: %s", outputUp, expectedUp)
399	}
400}
401
402func TestCreateModule(t *testing.T) {
403	ctx := newContext()
404	ctx.MockFileSystem(map[string][]byte{
405		"Android.bp": []byte(`
406			foo_module {
407			    name: "A",
408			    deps: ["B", "C"],
409			}
410		`),
411	})
412
413	ctx.RegisterTopDownMutator("create", createTestMutator)
414	ctx.RegisterBottomUpMutator("deps", depsMutator)
415
416	ctx.RegisterModuleType("foo_module", newFooModule)
417	ctx.RegisterModuleType("bar_module", newBarModule)
418	_, errs := ctx.ParseBlueprintsFiles("Android.bp", nil)
419	if len(errs) > 0 {
420		t.Errorf("unexpected parse errors:")
421		for _, err := range errs {
422			t.Errorf("  %s", err)
423		}
424		t.FailNow()
425	}
426
427	_, errs = ctx.ResolveDependencies(nil)
428	if len(errs) > 0 {
429		t.Errorf("unexpected dep errors:")
430		for _, err := range errs {
431			t.Errorf("  %s", err)
432		}
433		t.FailNow()
434	}
435
436	a := ctx.moduleGroupFromName("A", nil).modules.firstModule().logicModule.(*fooModule)
437	b := ctx.moduleGroupFromName("B", nil).modules.firstModule().logicModule.(*barModule)
438	c := ctx.moduleGroupFromName("C", nil).modules.firstModule().logicModule.(*barModule)
439	d := ctx.moduleGroupFromName("D", nil).modules.firstModule().logicModule.(*fooModule)
440
441	checkDeps := func(m Module, expected string) {
442		var deps []string
443		ctx.VisitDirectDeps(m, func(m Module) {
444			deps = append(deps, ctx.ModuleName(m))
445		})
446		got := strings.Join(deps, ",")
447		if got != expected {
448			t.Errorf("unexpected %q dependencies, got %q expected %q",
449				ctx.ModuleName(m), got, expected)
450		}
451	}
452
453	checkDeps(a, "B,C")
454	checkDeps(b, "D")
455	checkDeps(c, "D")
456	checkDeps(d, "")
457}
458
459func createTestMutator(ctx TopDownMutatorContext) {
460	type props struct {
461		Name string
462		Deps []string
463	}
464
465	ctx.CreateModule(newBarModule, &props{
466		Name: "B",
467		Deps: []string{"D"},
468	})
469
470	ctx.CreateModule(newBarModule, &props{
471		Name: "C",
472		Deps: []string{"D"},
473	})
474
475	ctx.CreateModule(newFooModule, &props{
476		Name: "D",
477	})
478}
479
480func TestWalkFileOrder(t *testing.T) {
481	// Run the test once to see how long it normally takes
482	start := time.Now()
483	doTestWalkFileOrder(t, time.Duration(0))
484	duration := time.Since(start)
485
486	// Run the test again, but put enough of a sleep into each visitor to detect ordering
487	// problems if they exist
488	doTestWalkFileOrder(t, duration)
489}
490
491// test that WalkBlueprintsFiles calls asyncVisitor in the right order
492func doTestWalkFileOrder(t *testing.T, sleepDuration time.Duration) {
493	// setup mock context
494	ctx := newContext()
495	mockFiles := map[string][]byte{
496		"Android.bp": []byte(`
497			sample_module {
498			    name: "a",
499			}
500		`),
501		"dir1/Android.bp": []byte(`
502			sample_module {
503			    name: "b",
504			}
505		`),
506		"dir1/dir2/Android.bp": []byte(`
507			sample_module {
508			    name: "c",
509			}
510		`),
511	}
512	ctx.MockFileSystem(mockFiles)
513
514	// prepare to monitor the visit order
515	visitOrder := []string{}
516	visitLock := sync.Mutex{}
517	correctVisitOrder := []string{"Android.bp", "dir1/Android.bp", "dir1/dir2/Android.bp"}
518
519	// sleep longer when processing the earlier files
520	chooseSleepDuration := func(fileName string) (duration time.Duration) {
521		duration = time.Duration(0)
522		for i := len(correctVisitOrder) - 1; i >= 0; i-- {
523			if fileName == correctVisitOrder[i] {
524				return duration
525			}
526			duration = duration + sleepDuration
527		}
528		panic("unrecognized file name " + fileName)
529	}
530
531	visitor := func(file *parser.File) {
532		time.Sleep(chooseSleepDuration(file.Name))
533		visitLock.Lock()
534		defer visitLock.Unlock()
535		visitOrder = append(visitOrder, file.Name)
536	}
537	keys := []string{"Android.bp", "dir1/Android.bp", "dir1/dir2/Android.bp"}
538
539	// visit the blueprints files
540	ctx.WalkBlueprintsFiles(".", keys, visitor)
541
542	// check the order
543	if !reflect.DeepEqual(visitOrder, correctVisitOrder) {
544		t.Errorf("Incorrect visit order; expected %v, got %v", correctVisitOrder, visitOrder)
545	}
546}
547
548// test that WalkBlueprintsFiles reports syntax errors
549func TestWalkingWithSyntaxError(t *testing.T) {
550	// setup mock context
551	ctx := newContext()
552	mockFiles := map[string][]byte{
553		"Android.bp": []byte(`
554			sample_module {
555			    name: "a" "b",
556			}
557		`),
558		"dir1/Android.bp": []byte(`
559			sample_module {
560			    name: "b",
561		`),
562		"dir1/dir2/Android.bp": []byte(`
563			sample_module {
564			    name: "c",
565			}
566		`),
567	}
568	ctx.MockFileSystem(mockFiles)
569
570	keys := []string{"Android.bp", "dir1/Android.bp", "dir1/dir2/Android.bp"}
571
572	// visit the blueprints files
573	_, errs := ctx.WalkBlueprintsFiles(".", keys, func(file *parser.File) {})
574
575	expectedErrs := []error{
576		errors.New(`Android.bp:3:18: expected "}", found String`),
577		errors.New(`dir1/Android.bp:4:3: expected "}", found EOF`),
578	}
579	if fmt.Sprintf("%s", expectedErrs) != fmt.Sprintf("%s", errs) {
580		t.Errorf("Incorrect errors; expected:\n%s\ngot:\n%s", expectedErrs, errs)
581	}
582
583}
584
585func TestParseFailsForModuleWithoutName(t *testing.T) {
586	ctx := NewContext()
587	ctx.MockFileSystem(map[string][]byte{
588		"Android.bp": []byte(`
589			foo_module {
590			    name: "A",
591			}
592
593			bar_module {
594			    deps: ["A"],
595			}
596		`),
597	})
598	ctx.RegisterModuleType("foo_module", newFooModule)
599	ctx.RegisterModuleType("bar_module", newBarModule)
600
601	_, errs := ctx.ParseBlueprintsFiles("Android.bp", nil)
602
603	expectedErrs := []error{
604		errors.New(`Android.bp:6:4: property 'name' is missing from a module`),
605	}
606	if fmt.Sprintf("%s", expectedErrs) != fmt.Sprintf("%s", errs) {
607		t.Errorf("Incorrect errors; expected:\n%s\ngot:\n%s", expectedErrs, errs)
608	}
609}
610
611func Test_findVariant(t *testing.T) {
612	module := &moduleInfo{
613		variant: variant{
614			name: "normal_local",
615			variations: variationMap{
616				"normal": "normal",
617				"local":  "local",
618			},
619			dependencyVariations: variationMap{
620				"normal": "normal",
621			},
622		},
623	}
624
625	type alias struct {
626		variant variant
627		target  int
628	}
629
630	makeDependencyGroup := func(in ...interface{}) *moduleGroup {
631		group := &moduleGroup{
632			name: "dep",
633		}
634		for _, x := range in {
635			switch m := x.(type) {
636			case *moduleInfo:
637				m.group = group
638				group.modules = append(group.modules, m)
639			case alias:
640				// aliases may need to target modules that haven't been processed
641				// yet, put an empty alias in for now.
642				group.modules = append(group.modules, nil)
643			default:
644				t.Fatalf("unexpected type %T", x)
645			}
646		}
647
648		for i, x := range in {
649			switch m := x.(type) {
650			case *moduleInfo:
651				// already added in the first pass
652			case alias:
653				group.modules[i] = &moduleAlias{
654					variant: m.variant,
655					target:  group.modules[m.target].moduleOrAliasTarget(),
656				}
657			default:
658				t.Fatalf("unexpected type %T", x)
659			}
660		}
661
662		return group
663	}
664
665	tests := []struct {
666		name         string
667		possibleDeps *moduleGroup
668		variations   []Variation
669		far          bool
670		reverse      bool
671		want         string
672	}{
673		{
674			name: "AddVariationDependencies(nil)",
675			// A dependency that matches the non-local variations of the module
676			possibleDeps: makeDependencyGroup(
677				&moduleInfo{
678					variant: variant{
679						name: "normal",
680						variations: variationMap{
681							"normal": "normal",
682						},
683					},
684				},
685			),
686			variations: nil,
687			far:        false,
688			reverse:    false,
689			want:       "normal",
690		},
691		{
692			name: "AddVariationDependencies(nil) to alias",
693			// A dependency with an alias that matches the non-local variations of the module
694			possibleDeps: makeDependencyGroup(
695				alias{
696					variant: variant{
697						name: "normal",
698						variations: variationMap{
699							"normal": "normal",
700						},
701					},
702					target: 1,
703				},
704				&moduleInfo{
705					variant: variant{
706						name: "normal_a",
707						variations: variationMap{
708							"normal": "normal",
709							"a":      "a",
710						},
711					},
712				},
713			),
714			variations: nil,
715			far:        false,
716			reverse:    false,
717			want:       "normal_a",
718		},
719		{
720			name: "AddVariationDependencies(a)",
721			// A dependency with local variations
722			possibleDeps: makeDependencyGroup(
723				&moduleInfo{
724					variant: variant{
725						name: "normal_a",
726						variations: variationMap{
727							"normal": "normal",
728							"a":      "a",
729						},
730					},
731				},
732			),
733			variations: []Variation{{"a", "a"}},
734			far:        false,
735			reverse:    false,
736			want:       "normal_a",
737		},
738		{
739			name: "AddFarVariationDependencies(far)",
740			// A dependency with far variations
741			possibleDeps: makeDependencyGroup(
742				&moduleInfo{
743					variant: variant{
744						name:       "",
745						variations: nil,
746					},
747				},
748				&moduleInfo{
749					variant: variant{
750						name: "far",
751						variations: variationMap{
752							"far": "far",
753						},
754					},
755				},
756			),
757			variations: []Variation{{"far", "far"}},
758			far:        true,
759			reverse:    false,
760			want:       "far",
761		},
762		{
763			name: "AddFarVariationDependencies(far) to alias",
764			// A dependency with far variations and aliases
765			possibleDeps: makeDependencyGroup(
766				alias{
767					variant: variant{
768						name: "far",
769						variations: variationMap{
770							"far": "far",
771						},
772					},
773					target: 2,
774				},
775				&moduleInfo{
776					variant: variant{
777						name: "far_a",
778						variations: variationMap{
779							"far": "far",
780							"a":   "a",
781						},
782					},
783				},
784				&moduleInfo{
785					variant: variant{
786						name: "far_b",
787						variations: variationMap{
788							"far": "far",
789							"b":   "b",
790						},
791					},
792				},
793			),
794			variations: []Variation{{"far", "far"}},
795			far:        true,
796			reverse:    false,
797			want:       "far_b",
798		},
799		{
800			name: "AddFarVariationDependencies(far, b) to missing",
801			// A dependency with far variations and aliases
802			possibleDeps: makeDependencyGroup(
803				alias{
804					variant: variant{
805						name: "far",
806						variations: variationMap{
807							"far": "far",
808						},
809					},
810					target: 1,
811				},
812				&moduleInfo{
813					variant: variant{
814						name: "far_a",
815						variations: variationMap{
816							"far": "far",
817							"a":   "a",
818						},
819					},
820				},
821			),
822			variations: []Variation{{"far", "far"}, {"a", "b"}},
823			far:        true,
824			reverse:    false,
825			want:       "nil",
826		},
827	}
828	for _, tt := range tests {
829		t.Run(tt.name, func(t *testing.T) {
830			got, _ := findVariant(module, tt.possibleDeps, tt.variations, tt.far, tt.reverse)
831			if g, w := got == nil, tt.want == "nil"; g != w {
832				t.Fatalf("findVariant() got = %v, want %v", got, tt.want)
833			}
834			if got != nil {
835				if g, w := got.String(), fmt.Sprintf("module %q variant %q", "dep", tt.want); g != w {
836					t.Errorf("findVariant() got = %v, want %v", g, w)
837				}
838			}
839		})
840	}
841}
842
843func Test_parallelVisit(t *testing.T) {
844	addDep := func(from, to *moduleInfo) {
845		from.directDeps = append(from.directDeps, depInfo{to, nil})
846		from.forwardDeps = append(from.forwardDeps, to)
847		to.reverseDeps = append(to.reverseDeps, from)
848	}
849
850	create := func(name string) *moduleInfo {
851		m := &moduleInfo{
852			group: &moduleGroup{
853				name: name,
854			},
855		}
856		m.group.modules = modulesOrAliases{m}
857		return m
858	}
859	moduleA := create("A")
860	moduleB := create("B")
861	moduleC := create("C")
862	moduleD := create("D")
863	moduleE := create("E")
864	moduleF := create("F")
865	moduleG := create("G")
866
867	// A depends on B, B depends on C.  Nothing depends on D through G, and they don't depend on
868	// anything.
869	addDep(moduleA, moduleB)
870	addDep(moduleB, moduleC)
871
872	t.Run("no modules", func(t *testing.T) {
873		errs := parallelVisit(nil, bottomUpVisitorImpl{}, 1,
874			func(module *moduleInfo, pause chan<- pauseSpec) bool {
875				panic("unexpected call to visitor")
876			})
877		if errs != nil {
878			t.Errorf("expected no errors, got %q", errs)
879		}
880	})
881	t.Run("bottom up", func(t *testing.T) {
882		order := ""
883		errs := parallelVisit([]*moduleInfo{moduleA, moduleB, moduleC}, bottomUpVisitorImpl{}, 1,
884			func(module *moduleInfo, pause chan<- pauseSpec) bool {
885				order += module.group.name
886				return false
887			})
888		if errs != nil {
889			t.Errorf("expected no errors, got %q", errs)
890		}
891		if g, w := order, "CBA"; g != w {
892			t.Errorf("expected order %q, got %q", w, g)
893		}
894	})
895	t.Run("pause", func(t *testing.T) {
896		order := ""
897		errs := parallelVisit([]*moduleInfo{moduleA, moduleB, moduleC, moduleD}, bottomUpVisitorImpl{}, 1,
898			func(module *moduleInfo, pause chan<- pauseSpec) bool {
899				if module == moduleC {
900					// Pause module C on module D
901					unpause := make(chan struct{})
902					pause <- pauseSpec{moduleC, moduleD, unpause}
903					<-unpause
904				}
905				order += module.group.name
906				return false
907			})
908		if errs != nil {
909			t.Errorf("expected no errors, got %q", errs)
910		}
911		if g, w := order, "DCBA"; g != w {
912			t.Errorf("expected order %q, got %q", w, g)
913		}
914	})
915	t.Run("cancel", func(t *testing.T) {
916		order := ""
917		errs := parallelVisit([]*moduleInfo{moduleA, moduleB, moduleC}, bottomUpVisitorImpl{}, 1,
918			func(module *moduleInfo, pause chan<- pauseSpec) bool {
919				order += module.group.name
920				// Cancel in module B
921				return module == moduleB
922			})
923		if errs != nil {
924			t.Errorf("expected no errors, got %q", errs)
925		}
926		if g, w := order, "CB"; g != w {
927			t.Errorf("expected order %q, got %q", w, g)
928		}
929	})
930	t.Run("pause and cancel", func(t *testing.T) {
931		order := ""
932		errs := parallelVisit([]*moduleInfo{moduleA, moduleB, moduleC, moduleD}, bottomUpVisitorImpl{}, 1,
933			func(module *moduleInfo, pause chan<- pauseSpec) bool {
934				if module == moduleC {
935					// Pause module C on module D
936					unpause := make(chan struct{})
937					pause <- pauseSpec{moduleC, moduleD, unpause}
938					<-unpause
939				}
940				order += module.group.name
941				// Cancel in module D
942				return module == moduleD
943			})
944		if errs != nil {
945			t.Errorf("expected no errors, got %q", errs)
946		}
947		if g, w := order, "D"; g != w {
948			t.Errorf("expected order %q, got %q", w, g)
949		}
950	})
951	t.Run("parallel", func(t *testing.T) {
952		order := ""
953		errs := parallelVisit([]*moduleInfo{moduleA, moduleB, moduleC}, bottomUpVisitorImpl{}, 3,
954			func(module *moduleInfo, pause chan<- pauseSpec) bool {
955				order += module.group.name
956				return false
957			})
958		if errs != nil {
959			t.Errorf("expected no errors, got %q", errs)
960		}
961		if g, w := order, "CBA"; g != w {
962			t.Errorf("expected order %q, got %q", w, g)
963		}
964	})
965	t.Run("pause existing", func(t *testing.T) {
966		order := ""
967		errs := parallelVisit([]*moduleInfo{moduleA, moduleB, moduleC}, bottomUpVisitorImpl{}, 3,
968			func(module *moduleInfo, pause chan<- pauseSpec) bool {
969				if module == moduleA {
970					// Pause module A on module B (an existing dependency)
971					unpause := make(chan struct{})
972					pause <- pauseSpec{moduleA, moduleB, unpause}
973					<-unpause
974				}
975				order += module.group.name
976				return false
977			})
978		if errs != nil {
979			t.Errorf("expected no errors, got %q", errs)
980		}
981		if g, w := order, "CBA"; g != w {
982			t.Errorf("expected order %q, got %q", w, g)
983		}
984	})
985	t.Run("cycle", func(t *testing.T) {
986		errs := parallelVisit([]*moduleInfo{moduleA, moduleB, moduleC}, bottomUpVisitorImpl{}, 3,
987			func(module *moduleInfo, pause chan<- pauseSpec) bool {
988				if module == moduleC {
989					// Pause module C on module A (a dependency cycle)
990					unpause := make(chan struct{})
991					pause <- pauseSpec{moduleC, moduleA, unpause}
992					<-unpause
993				}
994				return false
995			})
996		want := []string{
997			`encountered dependency cycle`,
998			`module "C" depends on module "A"`,
999			`module "A" depends on module "B"`,
1000			`module "B" depends on module "C"`,
1001		}
1002		for i := range want {
1003			if len(errs) <= i {
1004				t.Errorf("missing error %s", want[i])
1005			} else if !strings.Contains(errs[i].Error(), want[i]) {
1006				t.Errorf("expected error %s, got %s", want[i], errs[i])
1007			}
1008		}
1009		if len(errs) > len(want) {
1010			for _, err := range errs[len(want):] {
1011				t.Errorf("unexpected error %s", err.Error())
1012			}
1013		}
1014	})
1015	t.Run("pause cycle", func(t *testing.T) {
1016		errs := parallelVisit([]*moduleInfo{moduleA, moduleB, moduleC, moduleD}, bottomUpVisitorImpl{}, 3,
1017			func(module *moduleInfo, pause chan<- pauseSpec) bool {
1018				if module == moduleC {
1019					// Pause module C on module D
1020					unpause := make(chan struct{})
1021					pause <- pauseSpec{moduleC, moduleD, unpause}
1022					<-unpause
1023				}
1024				if module == moduleD {
1025					// Pause module D on module C (a pause cycle)
1026					unpause := make(chan struct{})
1027					pause <- pauseSpec{moduleD, moduleC, unpause}
1028					<-unpause
1029				}
1030				return false
1031			})
1032		want := []string{
1033			`encountered dependency cycle`,
1034			`module "D" depends on module "C"`,
1035			`module "C" depends on module "D"`,
1036		}
1037		for i := range want {
1038			if len(errs) <= i {
1039				t.Errorf("missing error %s", want[i])
1040			} else if !strings.Contains(errs[i].Error(), want[i]) {
1041				t.Errorf("expected error %s, got %s", want[i], errs[i])
1042			}
1043		}
1044		if len(errs) > len(want) {
1045			for _, err := range errs[len(want):] {
1046				t.Errorf("unexpected error %s", err.Error())
1047			}
1048		}
1049	})
1050	t.Run("pause cycle with deps", func(t *testing.T) {
1051		pauseDeps := map[*moduleInfo]*moduleInfo{
1052			// F and G form a pause cycle
1053			moduleF: moduleG,
1054			moduleG: moduleF,
1055			// D depends on E which depends on the pause cycle, making E the first alphabetical
1056			// entry in pauseMap, which is not part of the cycle.
1057			moduleD: moduleE,
1058			moduleE: moduleF,
1059		}
1060		errs := parallelVisit([]*moduleInfo{moduleD, moduleE, moduleF, moduleG}, bottomUpVisitorImpl{}, 4,
1061			func(module *moduleInfo, pause chan<- pauseSpec) bool {
1062				if dep, ok := pauseDeps[module]; ok {
1063					unpause := make(chan struct{})
1064					pause <- pauseSpec{module, dep, unpause}
1065					<-unpause
1066				}
1067				return false
1068			})
1069		want := []string{
1070			`encountered dependency cycle`,
1071			`module "G" depends on module "F"`,
1072			`module "F" depends on module "G"`,
1073		}
1074		for i := range want {
1075			if len(errs) <= i {
1076				t.Errorf("missing error %s", want[i])
1077			} else if !strings.Contains(errs[i].Error(), want[i]) {
1078				t.Errorf("expected error %s, got %s", want[i], errs[i])
1079			}
1080		}
1081		if len(errs) > len(want) {
1082			for _, err := range errs[len(want):] {
1083				t.Errorf("unexpected error %s", err.Error())
1084			}
1085		}
1086	})
1087}
1088
1089func TestPackageIncludes(t *testing.T) {
1090	dir1_foo_bp := `
1091	blueprint_package_includes {
1092		match_all: ["use_dir1"],
1093	}
1094	foo_module {
1095		name: "foo",
1096	}
1097	`
1098	dir2_foo_bp := `
1099	blueprint_package_includes {
1100		match_all: ["use_dir2"],
1101	}
1102	foo_module {
1103		name: "foo",
1104	}
1105	`
1106	mockFs := map[string][]byte{
1107		"dir1/Android.bp": []byte(dir1_foo_bp),
1108		"dir2/Android.bp": []byte(dir2_foo_bp),
1109	}
1110	testCases := []struct{
1111		desc string
1112		includeTags []string
1113		expectedDir string
1114		expectedErr string
1115	}{
1116		{
1117			desc: "use_dir1 is set, use dir1 foo",
1118			includeTags: []string{"use_dir1"},
1119			expectedDir: "dir1",
1120		},
1121		{
1122			desc: "use_dir2 is set, use dir2 foo",
1123			includeTags: []string{"use_dir2"},
1124			expectedDir: "dir2",
1125		},
1126		{
1127			desc: "duplicate module error if both use_dir1 and use_dir2 are set",
1128			includeTags: []string{"use_dir1", "use_dir2"},
1129			expectedDir: "",
1130			expectedErr: `module "foo" already defined`,
1131		},
1132	}
1133	for _, tc := range testCases {
1134		ctx := NewContext()
1135		// Register mock FS
1136		ctx.MockFileSystem(mockFs)
1137		// Register module types
1138		ctx.RegisterModuleType("foo_module", newFooModule)
1139		RegisterPackageIncludesModuleType(ctx)
1140		// Add include tags for test case
1141		ctx.AddIncludeTags(tc.includeTags...)
1142		// Run test
1143		_, actualErrs := ctx.ParseFileList(".", []string{"dir1/Android.bp", "dir2/Android.bp"}, nil)
1144		// Evaluate
1145		if !strings.Contains(fmt.Sprintf("%s", actualErrs), fmt.Sprintf("%s", tc.expectedErr)) {
1146			t.Errorf("Expected errors: %s, got errors: %s\n", tc.expectedErr, actualErrs)
1147		}
1148		if tc.expectedErr != "" {
1149			continue // expectedDir check not necessary
1150		}
1151		actualBpFile := ctx.moduleGroupFromName("foo", nil).modules.firstModule().relBlueprintsFile
1152		if tc.expectedDir != filepath.Dir(actualBpFile) {
1153			t.Errorf("Expected foo from %s, got %s\n", tc.expectedDir, filepath.Dir(actualBpFile))
1154		}
1155	}
1156
1157}
1158