Public source validation / validate (push) Failing after 3m8s
88 lines
4.4 KiB
Go
88 lines
4.4 KiB
Go
package service
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestBuildTopologyIsBoundedAndPreservesUnknownNodes(t *testing.T) {
|
|
now := time.Date(2026, 8, 2, 12, 0, 0, 0, time.UTC)
|
|
snapshot := Snapshot{ObservedAt: now, Services: []ServiceStatus{{ID: "service-b", Name: "Backend", State: StateDown}, {ID: "service-a", Name: "Frontend", State: StateUp}}}
|
|
dependencies := []Dependency{{ID: "edge-2", ServiceID: "service-a", DependsOnServiceID: "missing", RelationType: RelationDependsOn, SourceID: "compose", Confidence: .6}, {ID: "edge-1", ServiceID: "service-a", DependsOnServiceID: "service-b", RelationType: RelationDependsOn, SourceID: "manual", Confidence: .9, Confirmed: true}}
|
|
topology, err := BuildTopology(snapshot, dependencies, 3, 2)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if topology.ObservedAt != now || len(topology.Nodes) != 3 || len(topology.Edges) != 2 || topology.TotalEdges != 2 {
|
|
t.Fatalf("unexpected topology: %+v", topology)
|
|
}
|
|
if topology.Nodes[0].ID != "missing" || topology.Nodes[0].Known {
|
|
t.Fatalf("nodes are not deterministic or missing node is known: %+v", topology.Nodes)
|
|
}
|
|
if topology.Edges[0].ID != "edge-2" || topology.Edges[0].Confirmed || !topology.Edges[0].Inferred {
|
|
t.Fatalf("inferred edge was not preserved: %+v", topology.Edges[0])
|
|
}
|
|
if topology.Edges[1].ID != "edge-1" || !topology.Edges[1].Confirmed || topology.Edges[1].Inferred {
|
|
t.Fatalf("confirmed edge was not preserved: %+v", topology.Edges[1])
|
|
}
|
|
}
|
|
|
|
func TestBuildTopologyPreservesSourceState(t *testing.T) {
|
|
now := time.Date(2026, 8, 12, 1, 0, 0, 0, time.UTC)
|
|
topology, err := BuildTopology(Snapshot{ObservedAt: now, CapabilityState: CapabilityAvailable, ConfigurationState: ConfigurationNotConfigured, Reason: "no_services_configured"}, nil, 10, 10)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if topology.CapabilityState != CapabilityAvailable || topology.ConfigurationState != ConfigurationNotConfigured || topology.Reason != "no_services_configured" {
|
|
t.Fatalf("topology source state was lost: %+v", topology)
|
|
}
|
|
}
|
|
|
|
func TestBuildTopologyRejectsUnsafeBoundsAndCycles(t *testing.T) {
|
|
if _, err := BuildTopology(Snapshot{}, nil, 0, 1); err == nil {
|
|
t.Fatal("expected bound error")
|
|
}
|
|
cycle := []Dependency{{ID: "a", ServiceID: "one", DependsOnServiceID: "two", RelationType: RelationDependsOn}, {ID: "b", ServiceID: "two", DependsOnServiceID: "one", RelationType: RelationDependsOn}}
|
|
_, err := BuildTopology(Snapshot{}, cycle, 10, 10)
|
|
if err == nil || !strings.Contains(err.Error(), "cycle") {
|
|
t.Fatalf("expected cycle error, got %v", err)
|
|
}
|
|
}
|
|
|
|
func TestBuildTopologyTruncatesEdgesDeterministically(t *testing.T) {
|
|
snapshot := Snapshot{ObservedAt: time.Now().UTC(), Services: []ServiceStatus{{ID: "a", Name: "A", State: StateUnknown}, {ID: "b", Name: "B", State: StateUnknown}, {ID: "c", Name: "C", State: StateUnknown}}}
|
|
dependencies := []Dependency{{ID: "z", ServiceID: "a", DependsOnServiceID: "c", RelationType: RelationBacks}, {ID: "a", ServiceID: "a", DependsOnServiceID: "b", RelationType: RelationExposes}}
|
|
topology, err := BuildTopology(snapshot, dependencies, 3, 1)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if !topology.Truncated || len(topology.Edges) != 1 || topology.Edges[0].ID != "a" {
|
|
t.Fatalf("unexpected truncation: %+v", topology)
|
|
}
|
|
}
|
|
|
|
func TestBuildTopologyTargetScaleRemainsBounded(t *testing.T) {
|
|
now := time.Date(2026, 8, 2, 12, 0, 0, 0, time.UTC)
|
|
services := make([]ServiceStatus, 0, 300)
|
|
dependencies := make([]Dependency, 0, 600)
|
|
for index := 0; index < 300; index++ {
|
|
id := fmt.Sprintf("service-%03d", index)
|
|
services = append(services, ServiceStatus{ID: id, Name: id, State: StateUnknown})
|
|
if index < 299 {
|
|
dependencies = append(dependencies, Dependency{ID: fmt.Sprintf("edge-%03d", index), ServiceID: id, DependsOnServiceID: fmt.Sprintf("service-%03d", index+1), RelationType: RelationBacks})
|
|
}
|
|
if index < 298 {
|
|
dependencies = append(dependencies, Dependency{ID: fmt.Sprintf("edge-extra-%03d", index), ServiceID: id, DependsOnServiceID: fmt.Sprintf("service-%03d", index+2), RelationType: RelationExposes})
|
|
}
|
|
}
|
|
topology, err := BuildTopology(Snapshot{ObservedAt: now, Services: services}, dependencies, 100, 200)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(topology.Nodes) > 100 || len(topology.Edges) > 200 || !topology.Truncated {
|
|
t.Fatalf("topology exceeded target bounds: nodes=%d edges=%d truncated=%v", len(topology.Nodes), len(topology.Edges), topology.Truncated)
|
|
}
|
|
}
|