test: Add 22 unit tests across dnsmasq, haproxy, services
dnsmasq (6 new, 30.8% → 32%): - Empty instances, multiple instances, nil config, configured IP - No leaked empty entries (address=//, local=//) - Empty fields don't produce broken entries Also fixed a bug: empty Domain/InternalDomain fields in commented-out entries (no LB IP case) now guarded against producing # local=// and # address=// directives. haproxy (7 new): - No HTTPS frontend with no routes - HTTP-only and L4-only route scenarios - CertsDir customization and default - Custom TCP route ports - Health check directive in L7 backends services (8 new, 72.7% → 75.8%): - Not-found errors for Get, Deregister, Update - DeregisterBySource partial match (source AND backend) - Overwrite preserves file count - Empty dir and non-YAML file handling Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
package services
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
)
|
||||
|
||||
@@ -324,3 +326,174 @@ func TestDomainToFilename(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestGet_NotFound(t *testing.T) {
|
||||
mgr := NewManager(t.TempDir())
|
||||
|
||||
_, err := mgr.Get("nonexistent.example.com")
|
||||
if err == nil {
|
||||
t.Error("expected error for non-existent domain, got nil")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeregister_NotFound(t *testing.T) {
|
||||
mgr := NewManager(t.TempDir())
|
||||
|
||||
err := mgr.Deregister("nonexistent.example.com")
|
||||
if err == nil {
|
||||
t.Error("expected error when deregistering non-existent domain, got nil")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeregisterBySource_NoMatch(t *testing.T) {
|
||||
mgr := NewManager(t.TempDir())
|
||||
|
||||
// Register some services
|
||||
mgr.Register(Service{
|
||||
Domain: "a.example.com",
|
||||
Source: "wild-cloud",
|
||||
Backend: Backend{Address: "10.0.0.1:443", Type: BackendTCPPassthrough},
|
||||
Reach: ReachPublic,
|
||||
})
|
||||
mgr.Register(Service{
|
||||
Domain: "b.example.com",
|
||||
Source: "wild-works",
|
||||
Backend: Backend{Address: "10.0.0.2:8080", Type: BackendHTTP},
|
||||
Reach: ReachInternal,
|
||||
})
|
||||
|
||||
// Deregister with a source that doesn't match anything
|
||||
err := mgr.DeregisterBySource("unknown-source", "10.0.0.99:443")
|
||||
if err != nil {
|
||||
t.Fatalf("DeregisterBySource with no matches should not error: %v", err)
|
||||
}
|
||||
|
||||
// All services should still be present
|
||||
svcs, _ := mgr.List()
|
||||
if len(svcs) != 2 {
|
||||
t.Errorf("expected 2 services after no-match deregister, got %d", len(svcs))
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeregisterBySource_PartialMatch(t *testing.T) {
|
||||
mgr := NewManager(t.TempDir())
|
||||
|
||||
// Same source, different backends
|
||||
mgr.Register(Service{
|
||||
Domain: "a.example.com",
|
||||
Source: "wild-cloud",
|
||||
Backend: Backend{Address: "10.0.0.1:443", Type: BackendTCPPassthrough},
|
||||
Reach: ReachPublic,
|
||||
})
|
||||
mgr.Register(Service{
|
||||
Domain: "b.example.com",
|
||||
Source: "wild-cloud",
|
||||
Backend: Backend{Address: "10.0.0.2:443", Type: BackendTCPPassthrough},
|
||||
Reach: ReachPublic,
|
||||
})
|
||||
|
||||
// Deregister only the ones matching source AND backend
|
||||
err := mgr.DeregisterBySource("wild-cloud", "10.0.0.1:443")
|
||||
if err != nil {
|
||||
t.Fatalf("DeregisterBySource failed: %v", err)
|
||||
}
|
||||
|
||||
svcs, _ := mgr.List()
|
||||
if len(svcs) != 1 {
|
||||
t.Errorf("expected 1 remaining service, got %d", len(svcs))
|
||||
}
|
||||
if svcs[0].Domain != "b.example.com" {
|
||||
t.Errorf("expected b.example.com to remain, got %s", svcs[0].Domain)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpdate_NotFound(t *testing.T) {
|
||||
mgr := NewManager(t.TempDir())
|
||||
|
||||
err := mgr.Update("nonexistent.example.com", map[string]any{
|
||||
"reach": "public",
|
||||
})
|
||||
if err == nil {
|
||||
t.Error("expected error when updating non-existent domain, got nil")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRegister_OverwritePreservesFile(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
mgr := NewManager(dir)
|
||||
|
||||
svc := Service{
|
||||
Domain: "overwrite.example.com",
|
||||
Source: "test",
|
||||
Backend: Backend{Address: "127.0.0.1:8080", Type: BackendHTTP},
|
||||
Reach: ReachInternal,
|
||||
}
|
||||
|
||||
// Register first time
|
||||
if err := mgr.Register(svc); err != nil {
|
||||
t.Fatalf("first Register failed: %v", err)
|
||||
}
|
||||
|
||||
// Register again with different backend
|
||||
svc.Backend.Address = "127.0.0.1:9090"
|
||||
if err := mgr.Register(svc); err != nil {
|
||||
t.Fatalf("second Register failed: %v", err)
|
||||
}
|
||||
|
||||
// File count should be exactly 1
|
||||
entries, err := os.ReadDir(filepath.Join(dir, "services"))
|
||||
if err != nil {
|
||||
t.Fatalf("ReadDir failed: %v", err)
|
||||
}
|
||||
if len(entries) != 1 {
|
||||
t.Errorf("expected 1 file after overwrite, got %d", len(entries))
|
||||
}
|
||||
|
||||
// Value should be updated
|
||||
got, _ := mgr.Get("overwrite.example.com")
|
||||
if got.Backend.Address != "127.0.0.1:9090" {
|
||||
t.Errorf("expected updated backend 127.0.0.1:9090, got %s", got.Backend.Address)
|
||||
}
|
||||
}
|
||||
|
||||
func TestList_EmptyDir(t *testing.T) {
|
||||
mgr := NewManager(t.TempDir())
|
||||
|
||||
svcs, err := mgr.List()
|
||||
if err != nil {
|
||||
t.Fatalf("List on empty dir should not error: %v", err)
|
||||
}
|
||||
if len(svcs) != 0 {
|
||||
t.Errorf("expected 0 services from empty dir, got %d", len(svcs))
|
||||
}
|
||||
}
|
||||
|
||||
func TestList_IgnoresNonYAML(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
mgr := NewManager(dir)
|
||||
|
||||
// Register one real service
|
||||
mgr.Register(Service{
|
||||
Domain: "real.example.com",
|
||||
Source: "test",
|
||||
Backend: Backend{Address: "127.0.0.1:8080", Type: BackendHTTP},
|
||||
Reach: ReachInternal,
|
||||
})
|
||||
|
||||
// Create non-YAML files in the services directory
|
||||
servicesDir := filepath.Join(dir, "services")
|
||||
os.WriteFile(filepath.Join(servicesDir, "README.md"), []byte("# ignore me"), 0644)
|
||||
os.WriteFile(filepath.Join(servicesDir, "notes.txt"), []byte("some notes"), 0644)
|
||||
os.WriteFile(filepath.Join(servicesDir, ".gitkeep"), []byte(""), 0644)
|
||||
|
||||
svcs, err := mgr.List()
|
||||
if err != nil {
|
||||
t.Fatalf("List failed: %v", err)
|
||||
}
|
||||
if len(svcs) != 1 {
|
||||
t.Errorf("expected 1 service (ignoring non-YAML files), got %d", len(svcs))
|
||||
}
|
||||
if svcs[0].Domain != "real.example.com" {
|
||||
t.Errorf("expected real.example.com, got %s", svcs[0].Domain)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user