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:
2026-07-09 21:07:12 +00:00
parent 112f7c7f55
commit 234a8f8462
5 changed files with 459 additions and 5 deletions

View File

@@ -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)
}
}