Generate a BIND-format domains.conf file alongside catalog zones. New input properties: file= (zone data path) and dnssec (bare flag). When --bind-conf is set, every zone must have file= or it errors. Renames ZoneEntry.File to ZonesFile (input path for error messages) and adds ZoneFile (BIND file path) and DNSSEC (bool) fields.
139 lines
4.0 KiB
Go
139 lines
4.0 KiB
Go
package main
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func TestGenerateBindConf(t *testing.T) {
|
|
entries := []ZoneEntry{
|
|
{Zone: "bitcard.org.", ZoneFile: "data/misc/bitcard.org", DNSSEC: true, ZonesFile: "test", Line: 1},
|
|
{Zone: "askask.com.", ZoneFile: "data/ask/askask.com", ZonesFile: "test", Line: 2},
|
|
}
|
|
|
|
got := generateBindConf(entries)
|
|
|
|
// Header
|
|
assertContains(t, got, "# THIS FILE IS GENERATED BY catalog-zone-gen")
|
|
assertContains(t, got, "#=============================================")
|
|
|
|
// Zones should be sorted alphabetically (askask.com before bitcard.org)
|
|
askIdx := strings.Index(got, "askask.com")
|
|
bitIdx := strings.Index(got, "bitcard.org")
|
|
if askIdx == -1 || bitIdx == -1 {
|
|
t.Fatal("expected both zones in output")
|
|
}
|
|
if askIdx >= bitIdx {
|
|
t.Error("expected askask.com before bitcard.org (alphabetical sort)")
|
|
}
|
|
|
|
// Non-DNSSEC zone
|
|
assertContains(t, got, `zone "askask.com" {`)
|
|
assertContains(t, got, ` type master;`)
|
|
assertContains(t, got, ` file "data/ask/askask.com";`)
|
|
|
|
// DNSSEC zone has directives on file line
|
|
assertContains(t, got, ` file "data/misc/bitcard.org"; dnssec-policy standard; inline-signing yes;`)
|
|
|
|
// No trailing dot in zone name
|
|
if strings.Contains(got, `zone "askask.com."`) {
|
|
t.Error("zone name should not have trailing dot in BIND config")
|
|
}
|
|
}
|
|
|
|
func TestGenerateBindConfEmpty(t *testing.T) {
|
|
got := generateBindConf(nil)
|
|
// Should just have the header
|
|
lines := splitLines(got)
|
|
if len(lines) != 3 {
|
|
t.Errorf("expected 3 header lines for empty input, got %d", len(lines))
|
|
}
|
|
}
|
|
|
|
func TestGenerateBindConfNoDNSSEC(t *testing.T) {
|
|
entries := []ZoneEntry{
|
|
{Zone: "example.com.", ZoneFile: "data/example.com", ZonesFile: "test", Line: 1},
|
|
}
|
|
|
|
got := generateBindConf(entries)
|
|
|
|
if strings.Contains(got, "dnssec-policy") {
|
|
t.Error("non-DNSSEC zone should not have dnssec-policy")
|
|
}
|
|
if strings.Contains(got, "inline-signing") {
|
|
t.Error("non-DNSSEC zone should not have inline-signing")
|
|
}
|
|
}
|
|
|
|
func TestValidateBindConf(t *testing.T) {
|
|
t.Run("all zones have file", func(t *testing.T) {
|
|
entries := []ZoneEntry{
|
|
{Zone: "a.example.com.", ZoneFile: "data/a", ZonesFile: "zones.txt", Line: 1},
|
|
{Zone: "b.example.com.", ZoneFile: "data/b", ZonesFile: "zones.txt", Line: 2},
|
|
}
|
|
if err := validateBindConf(entries); err != nil {
|
|
t.Fatalf("unexpected error: %v", err)
|
|
}
|
|
})
|
|
|
|
t.Run("missing file", func(t *testing.T) {
|
|
entries := []ZoneEntry{
|
|
{Zone: "a.example.com.", ZoneFile: "data/a", ZonesFile: "zones.txt", Line: 1},
|
|
{Zone: "b.example.com.", ZoneFile: "", ZonesFile: "zones.txt", Line: 3},
|
|
}
|
|
err := validateBindConf(entries)
|
|
if err == nil {
|
|
t.Fatal("expected error for missing file")
|
|
}
|
|
assertContains(t, err.Error(), "zones.txt:3:")
|
|
assertContains(t, err.Error(), "b.example.com.")
|
|
assertContains(t, err.Error(), "missing file=")
|
|
})
|
|
}
|
|
|
|
func TestWriteBindConf(t *testing.T) {
|
|
dir := t.TempDir()
|
|
path := filepath.Join(dir, "domains.conf")
|
|
|
|
entries := []ZoneEntry{
|
|
{Zone: "example.com.", ZoneFile: "data/example.com", ZonesFile: "test", Line: 1},
|
|
{Zone: "example.org.", ZoneFile: "data/example.org", DNSSEC: true, ZonesFile: "test", Line: 2},
|
|
}
|
|
|
|
if err := writeBindConf(path, entries); err != nil {
|
|
t.Fatalf("unexpected error: %v", err)
|
|
}
|
|
|
|
data, err := os.ReadFile(path)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
got := string(data)
|
|
|
|
assertContains(t, got, `zone "example.com"`)
|
|
assertContains(t, got, `zone "example.org"`)
|
|
assertContains(t, got, "dnssec-policy standard")
|
|
}
|
|
|
|
func TestWriteBindConfValidationError(t *testing.T) {
|
|
dir := t.TempDir()
|
|
path := filepath.Join(dir, "domains.conf")
|
|
|
|
entries := []ZoneEntry{
|
|
{Zone: "example.com.", ZoneFile: "", ZonesFile: "zones.txt", Line: 5},
|
|
}
|
|
|
|
err := writeBindConf(path, entries)
|
|
if err == nil {
|
|
t.Fatal("expected validation error")
|
|
}
|
|
assertContains(t, err.Error(), "zones.txt:5:")
|
|
|
|
// File should not have been written
|
|
if _, statErr := os.Stat(path); statErr == nil {
|
|
t.Error("file should not be written when validation fails")
|
|
}
|
|
}
|