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) } }) t.Run("also-notify references unknown catalog", 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."}, BindConf: BindConfConfig{ AlsoNotify: map[string][]string{ "nonexistent": {"198.51.100.1"}, }, }, } if err := validateConfig(cfg); err == nil { t.Fatal("expected error for also-notify referencing unknown catalog") } }) t.Run("also-notify references valid catalog", 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."}, BindConf: BindConfConfig{ AlsoNotify: map[string][]string{ "cat1": {"198.51.100.1"}, }, }, } 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") } }