sorcery-go/pkg/dag/dag_test.go

86 lines
2.6 KiB
Go
Executable File

package dag
import "testing"
// TestCircularDependency reproduces the original "A -> B -> C -> A" loop and
// ensures DetectCycles rejects the offending edge while keeping the Graph
// in a valid state (edge is rolled back).
func TestCircularDependency(t *testing.T) {
g := NewGraph()
if err := g.AddDependency("gcc", "glibc", BuildDep, nil); err != nil {
t.Fatalf("first edge should succeed: %v", err)
}
if err := g.AddDependency("glibc", "linux-headers", BuildDep, nil); err != nil {
t.Fatalf("second edge should succeed: %v", err)
}
// Closing the loop must fail.
if err := g.AddDependency("linux-headers", "gcc", BuildDep, nil); err == nil {
t.Fatalf("expected cycle error, got nil")
} else {
t.Logf("✓ correctly caught loop: %v", err)
}
// Graph must still be intact (rolled back).
if n := g.Nodes["linux-headers"]; n != nil && len(n.Edges) != 0 {
t.Fatalf("linux-headers should have no edges after rollback, got %d", len(n.Edges))
}
}
func TestTopologicalSort(t *testing.T) {
g := NewGraph()
_ = g.AddDependency("wget", "openssl", RuntimeDep, nil)
_ = g.AddDependency("wget", "glibc", RuntimeDep, nil)
_ = g.AddDependency("openssl", "glibc", RuntimeDep, nil)
order, err := g.TopologicalSort()
if err != nil {
t.Fatalf("topo sort: %v", err)
}
pos := make(map[string]int)
for i, n := range order {
pos[n.Name] = i
}
if pos["glibc"] >= pos["openssl"] {
t.Fatalf("glibc must come before openssl")
}
if pos["glibc"] >= pos["wget"] {
t.Fatalf("glibc must come before wget")
}
if pos["openssl"] >= pos["wget"] {
t.Fatalf("openssl must come before wget")
}
}
func TestPruneSkipsOptional(t *testing.T) {
g := NewGraph()
_ = g.AddDependency("app", "libcore", RuntimeDep, nil)
_ = g.AddDependency("app", "libx11", OptionalDep, nil)
_ = g.AddDependency("libx11", "libxext", RuntimeDep, nil)
g.Prune("app", false)
if !g.Nodes["libcore"].IsRequired {
t.Fatalf("libcore must be required")
}
if g.Nodes["libx11"].IsRequired {
t.Fatalf("libx11 (optional, not enabled) must be pruned")
}
if g.Nodes["libxext"].IsRequired {
t.Fatalf("libxext must be pruned along with libx11")
}
}
func TestSolverTriggersReForge(t *testing.T) {
g := NewGraph()
_ = g.AddDependency("wget", "openssl", RuntimeDep, []string{"ssl3"})
// Pretend the existing openssl Essence does NOT have ssl3 enabled.
s := &Solver{Lookup: func(spell, feature string) (bool, error) {
return false, nil
}}
reforges, err := s.Solve("wget", g)
if err != nil {
t.Fatalf("solve: %v", err)
}
if len(reforges) == 0 {
t.Fatalf("expected a re-forge recommendation for openssl+ssl3")
}
}