Add catalog-zone-gen tool
Generate RFC 9432 DNS catalog zone files from a declarative input file. Parses zone-to-catalog assignments with optional group and coo properties, produces deterministic BIND-format output with automatic SOA serial management and change detection.
This commit is contained in:
141
config_test.go
Normal file
141
config_test.go
Normal file
@@ -0,0 +1,141 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestLoadConfig(t *testing.T) {
|
||||
t.Run("valid config", func(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
writeTestFile(t, dir, "catz.yaml", `catalogs:
|
||||
cat1:
|
||||
zone: catalog1.example.com.
|
||||
soa:
|
||||
mname: ns1.example.com.
|
||||
rname: hostmaster.example.com.
|
||||
`)
|
||||
cfg, err := loadConfig(filepath.Join(dir, "catz.yaml"))
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if cfg.Catalogs["cat1"].Zone != "catalog1.example.com." {
|
||||
t.Errorf("zone = %q, want %q", cfg.Catalogs["cat1"].Zone, "catalog1.example.com.")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("normalizes FQDNs", func(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
writeTestFile(t, dir, "catz.yaml", `catalogs:
|
||||
cat1:
|
||||
zone: Catalog1.Example.COM
|
||||
soa:
|
||||
mname: NS1.Example.COM
|
||||
rname: Hostmaster.Example.COM
|
||||
`)
|
||||
cfg, err := loadConfig(filepath.Join(dir, "catz.yaml"))
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if cfg.Catalogs["cat1"].Zone != "catalog1.example.com." {
|
||||
t.Errorf("zone = %q, want normalized FQDN", cfg.Catalogs["cat1"].Zone)
|
||||
}
|
||||
if cfg.SOA.Mname != "ns1.example.com." {
|
||||
t.Errorf("mname = %q, want normalized FQDN", cfg.SOA.Mname)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("missing file", func(t *testing.T) {
|
||||
_, err := loadConfig("/nonexistent/catz.yaml")
|
||||
if err == nil {
|
||||
t.Fatal("expected error for missing file")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("invalid YAML", func(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
writeTestFile(t, dir, "catz.yaml", "{{invalid yaml")
|
||||
_, err := loadConfig(filepath.Join(dir, "catz.yaml"))
|
||||
if err == nil {
|
||||
t.Fatal("expected error for invalid YAML")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestValidateConfig(t *testing.T) {
|
||||
t.Run("no catalogs", func(t *testing.T) {
|
||||
cfg := &Config{
|
||||
Catalogs: map[string]CatalogConfig{},
|
||||
SOA: SOAConfig{Mname: "ns1.example.com.", Rname: "hostmaster.example.com."},
|
||||
}
|
||||
if err := validateConfig(cfg); err == nil {
|
||||
t.Fatal("expected error for no catalogs")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("nil catalogs", func(t *testing.T) {
|
||||
cfg := &Config{
|
||||
SOA: SOAConfig{Mname: "ns1.example.com.", Rname: "hostmaster.example.com."},
|
||||
}
|
||||
if err := validateConfig(cfg); err == nil {
|
||||
t.Fatal("expected error for nil catalogs")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("empty zone", func(t *testing.T) {
|
||||
cfg := &Config{
|
||||
Catalogs: map[string]CatalogConfig{"cat1": {Zone: ""}},
|
||||
SOA: SOAConfig{Mname: "ns1.example.com.", Rname: "hostmaster.example.com."},
|
||||
}
|
||||
if err := validateConfig(cfg); err == nil {
|
||||
t.Fatal("expected error for empty zone")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("missing mname", func(t *testing.T) {
|
||||
cfg := &Config{
|
||||
Catalogs: map[string]CatalogConfig{"cat1": {Zone: "cat.example.com."}},
|
||||
SOA: SOAConfig{Rname: "hostmaster.example.com."},
|
||||
}
|
||||
if err := validateConfig(cfg); err == nil {
|
||||
t.Fatal("expected error for missing mname")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("missing rname", func(t *testing.T) {
|
||||
cfg := &Config{
|
||||
Catalogs: map[string]CatalogConfig{"cat1": {Zone: "cat.example.com."}},
|
||||
SOA: SOAConfig{Mname: "ns1.example.com."},
|
||||
}
|
||||
if err := validateConfig(cfg); err == nil {
|
||||
t.Fatal("expected error for missing rname")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("valid config", func(t *testing.T) {
|
||||
cfg := &Config{
|
||||
Catalogs: map[string]CatalogConfig{"cat1": {Zone: "cat.example.com."}},
|
||||
SOA: SOAConfig{Mname: "ns1.example.com.", Rname: "hostmaster.example.com."},
|
||||
}
|
||||
if err := validateConfig(cfg); err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestLoadConfigWritePermission(t *testing.T) {
|
||||
// Test that loadConfig returns error for unreadable file
|
||||
dir := t.TempDir()
|
||||
path := filepath.Join(dir, "catz.yaml")
|
||||
writeTestFile(t, dir, "catz.yaml", "catalogs: {}")
|
||||
if err := os.Chmod(path, 0o000); err != nil {
|
||||
t.Skip("cannot change file permissions")
|
||||
}
|
||||
defer os.Chmod(path, 0o644)
|
||||
|
||||
_, err := loadConfig(path)
|
||||
if err == nil {
|
||||
t.Fatal("expected error for unreadable file")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user