feat: Add comprehensive tests + fix startup reconciliation
Tests added (13 new): - HAProxy ACL ordering: L7 before L4 wildcard, L4 exact before L4 wildcard - HAProxy subdomains: false=exact only, true=wildcard+exact - Reconciliation integration: HAProxy config from services, DNS config from services, Central config domain injection, correct DNS target IPs - dnsmasq: reach:internal has local=/, reach:public does not - Services: idempotent registration, no duplicates in list Bug fix: - Run initial reconciliation on startup so Central's own domain (from config) gets HAProxy + DNS routes even with zero registered services. Previously, Central only got routes after the first service was registered, causing 503 on fresh restart. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -217,6 +217,96 @@ func TestDefaultSource(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestRegisterIdempotent(t *testing.T) {
|
||||
mgr := NewManager(t.TempDir())
|
||||
|
||||
svc := Service{
|
||||
Domain: "idempotent.example.com",
|
||||
Source: "test",
|
||||
Backend: Backend{Address: "127.0.0.1:8080", Type: BackendHTTP},
|
||||
Reach: ReachInternal,
|
||||
}
|
||||
|
||||
// Register twice with same domain
|
||||
if err := mgr.Register(svc); err != nil {
|
||||
t.Fatalf("first Register failed: %v", err)
|
||||
}
|
||||
|
||||
// Update the backend address on second registration
|
||||
svc.Backend.Address = "127.0.0.1:9090"
|
||||
if err := mgr.Register(svc); err != nil {
|
||||
t.Fatalf("second Register failed: %v", err)
|
||||
}
|
||||
|
||||
// Should still have only one service
|
||||
svcs, err := mgr.List()
|
||||
if err != nil {
|
||||
t.Fatalf("List failed: %v", err)
|
||||
}
|
||||
if len(svcs) != 1 {
|
||||
t.Errorf("expected 1 service after idempotent register, got %d", len(svcs))
|
||||
}
|
||||
|
||||
// Should have the updated address
|
||||
got, err := mgr.Get("idempotent.example.com")
|
||||
if err != nil {
|
||||
t.Fatalf("Get failed: %v", err)
|
||||
}
|
||||
if got.Backend.Address != "127.0.0.1:9090" {
|
||||
t.Errorf("expected updated backend address 127.0.0.1:9090, got %s", got.Backend.Address)
|
||||
}
|
||||
}
|
||||
|
||||
func TestListNoDuplicates(t *testing.T) {
|
||||
mgr := NewManager(t.TempDir())
|
||||
|
||||
domains := []string{
|
||||
"alpha.example.com",
|
||||
"beta.example.com",
|
||||
"gamma.example.com",
|
||||
}
|
||||
|
||||
// Register each domain
|
||||
for _, domain := range domains {
|
||||
if err := mgr.Register(Service{
|
||||
Domain: domain,
|
||||
Source: "test",
|
||||
Backend: Backend{Address: "127.0.0.1:8080", Type: BackendHTTP},
|
||||
Reach: ReachInternal,
|
||||
}); err != nil {
|
||||
t.Fatalf("Register %s failed: %v", domain, err)
|
||||
}
|
||||
}
|
||||
|
||||
// Re-register one domain to verify no duplication
|
||||
if err := mgr.Register(Service{
|
||||
Domain: "beta.example.com",
|
||||
Source: "test",
|
||||
Backend: Backend{Address: "127.0.0.1:9090", Type: BackendHTTP},
|
||||
Reach: ReachInternal,
|
||||
}); err != nil {
|
||||
t.Fatalf("Re-register beta failed: %v", err)
|
||||
}
|
||||
|
||||
svcs, err := mgr.List()
|
||||
if err != nil {
|
||||
t.Fatalf("List failed: %v", err)
|
||||
}
|
||||
|
||||
if len(svcs) != 3 {
|
||||
t.Errorf("expected 3 unique services, got %d", len(svcs))
|
||||
}
|
||||
|
||||
// Verify no duplicate domains
|
||||
seen := make(map[string]bool)
|
||||
for _, svc := range svcs {
|
||||
if seen[svc.Domain] {
|
||||
t.Errorf("duplicate domain in List(): %s", svc.Domain)
|
||||
}
|
||||
seen[svc.Domain] = true
|
||||
}
|
||||
}
|
||||
|
||||
func TestDomainToFilename(t *testing.T) {
|
||||
tests := []struct {
|
||||
domain string
|
||||
|
||||
Reference in New Issue
Block a user