package engine import ( "reflect" "testing" ) func TestImportSchedulingKeepsUnselectedSlotsAndScopeBoundaries(t *testing.T) { dependent := importNodeKey{resourcePath: "a-dependent"} external := importNodeKey{resourcePath: "external"} prerequisite := importNodeKey{resourcePath: "z-prerequisite"} graph := newImportInclusionGraph() for _, key := range []importNodeKey{dependent, external, prerequisite} { graph.addNode(importGraphNode{key: key}) } graph.addEdge(dependent, prerequisite, Location{}) graph.addEdge(dependent, external, Location{}) graph.addEdge(external, prerequisite, Location{}) contributions := []acquiredContribution{ {identity: dependent}, {identity: external}, {identity: prerequisite}, } scheduled := scheduleContributionSlots(contributions, []int{0, 2}, indexImportDependencies(graph)) if scheduled[0].identity != prerequisite || scheduled[1].identity != external || scheduled[2].identity != dependent { t.Fatalf("scope schedule = %#v", scheduled) } if contributions[0].identity != dependent || contributions[2].identity != prerequisite { t.Fatal("scheduling changed the input slots") } } func TestImportAndInheritanceIntegrationsUseEquivalentReadySchedules(t *testing.T) { names := []string{"a-base", "b-independent", "z-dependent"} keys := make(map[string]importNodeKey, len(names)) contributions := make([]acquiredContribution, len(names)) for index, name := range names { key := importNodeKey{ namespaceKind: "host", namespaceAnchor: "/shared", resourceKind: "file", resourcePath: "/" + name, } keys[name] = key contributions[index] = acquiredContribution{ identity: key, source: SourceInfo{ID: "source-" + name, Path: name}, } } var want []string for _, reverse := range []bool{false, true} { graph := newImportInclusionGraph() orderedNames := append([]string(nil), names...) if reverse { orderedNames[0], orderedNames[2] = orderedNames[2], orderedNames[0] } for _, name := range orderedNames { graph.addNode(importGraphNode{key: keys[name], sourceID: "source-" + name, role: importRoleMapping}) } graph.addEdge(keys["z-dependent"], keys["a-base"], Location{}) scheduled := scheduleContributionSlots(contributions, []int{0, 1, 2}, indexImportDependencies(graph)) got := make([]string, len(scheduled)) for index, contribution := range scheduled { got[index] = contribution.identity.resourcePath[1:] } if !reflect.DeepEqual(got, []string{"a-base", "b-independent", "z-dependent"}) { t.Fatalf("import schedule reverse=%t: %v", reverse, got) } if !reflect.DeepEqual( []string{contributions[0].source.ID, contributions[1].source.ID, contributions[2].source.ID}, []string{"source-a-base", "source-b-independent", "source-z-dependent"}, ) { t.Fatal("scheduling mutated acquisition source records") } inheritanceText := "a-base: {value: ready}\nb-independent: {value: independent}\nz-dependent: {extends: a-base}\n" if reverse { inheritanceText = "z-dependent: {extends: a-base}\nb-independent: {value: independent}\na-base: {value: ready}\n" } scope := parseCompositionDocument(t, "inheritance", inheritanceText) inheritance, diagnostics := analyzeInheritanceGraph(scope, Path{}) if len(diagnostics) != 0 { t.Fatalf("analyze inheritance reverse=%t: %#v", reverse, diagnostics) } order, diagnostics := inheritance.schedule() if len(diagnostics) != 0 { t.Fatalf("schedule inheritance reverse=%t: %#v", reverse, diagnostics) } inheritanceNames := make([]string, len(order)) for index, node := range order { inheritanceNames[index] = inheritance.nodes[node].name } if !reflect.DeepEqual(inheritanceNames, got) { t.Fatalf("equivalent graph schedules differ reverse=%t: imports=%v inheritance=%v", reverse, got, inheritanceNames) } if want == nil { want = got } else if !reflect.DeepEqual(got, want) { t.Fatalf("import graph construction changed schedule: got %v, want %v", got, want) } } }