Files
mcns/internal/db/records_test.go
Kyle Isom f9635578e0 Implement MCNS v1: custom Go DNS server replacing CoreDNS
Replace the CoreDNS precursor with a purpose-built authoritative DNS
server. Zones and records (A, AAAA, CNAME) are stored in SQLite and
managed via synchronized gRPC + REST APIs authenticated through MCIAS.
Non-authoritative queries are forwarded to upstream resolvers with
in-memory caching.

Key components:
- DNS server (miekg/dns) with authoritative zone handling and forwarding
- gRPC + REST management APIs with MCIAS auth (mcdsl integration)
- SQLite storage with CNAME exclusivity enforcement and auto SOA serials
- 30 tests covering database CRUD, DNS resolution, and caching

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 18:37:14 -07:00

290 lines
7.7 KiB
Go

package db
import (
"errors"
"testing"
)
func createTestZone(t *testing.T, db *DB) *Zone {
t.Helper()
zone, err := db.CreateZone("svc.mcp.metacircular.net", "ns.mcp.metacircular.net.", "admin.metacircular.net.", 3600, 600, 86400, 300)
if err != nil {
t.Fatalf("create zone: %v", err)
}
return zone
}
func TestCreateRecordA(t *testing.T) {
db := openTestDB(t)
createTestZone(t, db)
record, err := db.CreateRecord("svc.mcp.metacircular.net", "metacrypt", "A", "192.168.88.181", 300)
if err != nil {
t.Fatalf("create record: %v", err)
}
if record.Name != "metacrypt" {
t.Fatalf("got name %q, want %q", record.Name, "metacrypt")
}
if record.Type != "A" {
t.Fatalf("got type %q, want %q", record.Type, "A")
}
if record.Value != "192.168.88.181" {
t.Fatalf("got value %q, want %q", record.Value, "192.168.88.181")
}
}
func TestCreateRecordAAAA(t *testing.T) {
db := openTestDB(t)
createTestZone(t, db)
record, err := db.CreateRecord("svc.mcp.metacircular.net", "metacrypt", "AAAA", "2001:db8::1", 300)
if err != nil {
t.Fatalf("create record: %v", err)
}
if record.Type != "AAAA" {
t.Fatalf("got type %q, want %q", record.Type, "AAAA")
}
}
func TestCreateRecordCNAME(t *testing.T) {
db := openTestDB(t)
createTestZone(t, db)
record, err := db.CreateRecord("svc.mcp.metacircular.net", "alias", "CNAME", "rift.mcp.metacircular.net.", 300)
if err != nil {
t.Fatalf("create record: %v", err)
}
if record.Type != "CNAME" {
t.Fatalf("got type %q, want %q", record.Type, "CNAME")
}
}
func TestCreateRecordInvalidIP(t *testing.T) {
db := openTestDB(t)
createTestZone(t, db)
_, err := db.CreateRecord("svc.mcp.metacircular.net", "bad", "A", "not-an-ip", 300)
if err == nil {
t.Fatal("expected error for invalid IPv4")
}
}
func TestCreateRecordCNAMEExclusivity(t *testing.T) {
db := openTestDB(t)
createTestZone(t, db)
// Create an A record first.
_, err := db.CreateRecord("svc.mcp.metacircular.net", "metacrypt", "A", "192.168.88.181", 300)
if err != nil {
t.Fatalf("create A record: %v", err)
}
// Trying to add a CNAME for the same name should fail.
_, err = db.CreateRecord("svc.mcp.metacircular.net", "metacrypt", "CNAME", "rift.mcp.metacircular.net.", 300)
if !errors.Is(err, ErrConflict) {
t.Fatalf("expected ErrConflict, got %v", err)
}
}
func TestCreateRecordCNAMEExclusivityReverse(t *testing.T) {
db := openTestDB(t)
createTestZone(t, db)
// Create a CNAME record first.
_, err := db.CreateRecord("svc.mcp.metacircular.net", "alias", "CNAME", "rift.mcp.metacircular.net.", 300)
if err != nil {
t.Fatalf("create CNAME record: %v", err)
}
// Trying to add an A record for the same name should fail.
_, err = db.CreateRecord("svc.mcp.metacircular.net", "alias", "A", "192.168.88.181", 300)
if !errors.Is(err, ErrConflict) {
t.Fatalf("expected ErrConflict, got %v", err)
}
}
func TestCreateRecordBumpsSerial(t *testing.T) {
db := openTestDB(t)
zone := createTestZone(t, db)
originalSerial := zone.Serial
_, err := db.CreateRecord("svc.mcp.metacircular.net", "metacrypt", "A", "192.168.88.181", 300)
if err != nil {
t.Fatalf("create record: %v", err)
}
updated, err := db.GetZone("svc.mcp.metacircular.net")
if err != nil {
t.Fatalf("get zone: %v", err)
}
if updated.Serial <= originalSerial {
t.Fatalf("serial should have bumped: %d <= %d", updated.Serial, originalSerial)
}
}
func TestListRecords(t *testing.T) {
db := openTestDB(t)
createTestZone(t, db)
_, err := db.CreateRecord("svc.mcp.metacircular.net", "metacrypt", "A", "192.168.88.181", 300)
if err != nil {
t.Fatalf("create record 1: %v", err)
}
_, err = db.CreateRecord("svc.mcp.metacircular.net", "metacrypt", "A", "100.95.252.120", 300)
if err != nil {
t.Fatalf("create record 2: %v", err)
}
_, err = db.CreateRecord("svc.mcp.metacircular.net", "mcr", "A", "192.168.88.181", 300)
if err != nil {
t.Fatalf("create record 3: %v", err)
}
// List all records.
records, err := db.ListRecords("svc.mcp.metacircular.net", "", "")
if err != nil {
t.Fatalf("list records: %v", err)
}
if len(records) != 3 {
t.Fatalf("got %d records, want 3", len(records))
}
// Filter by name.
records, err = db.ListRecords("svc.mcp.metacircular.net", "metacrypt", "")
if err != nil {
t.Fatalf("list records by name: %v", err)
}
if len(records) != 2 {
t.Fatalf("got %d records, want 2", len(records))
}
// Filter by type.
records, err = db.ListRecords("svc.mcp.metacircular.net", "", "A")
if err != nil {
t.Fatalf("list records by type: %v", err)
}
if len(records) != 3 {
t.Fatalf("got %d records, want 3", len(records))
}
}
func TestUpdateRecord(t *testing.T) {
db := openTestDB(t)
createTestZone(t, db)
record, err := db.CreateRecord("svc.mcp.metacircular.net", "metacrypt", "A", "192.168.88.181", 300)
if err != nil {
t.Fatalf("create record: %v", err)
}
updated, err := db.UpdateRecord(record.ID, "metacrypt", "A", "10.0.0.1", 600)
if err != nil {
t.Fatalf("update record: %v", err)
}
if updated.Value != "10.0.0.1" {
t.Fatalf("got value %q, want %q", updated.Value, "10.0.0.1")
}
if updated.TTL != 600 {
t.Fatalf("got ttl %d, want 600", updated.TTL)
}
}
func TestDeleteRecord(t *testing.T) {
db := openTestDB(t)
createTestZone(t, db)
record, err := db.CreateRecord("svc.mcp.metacircular.net", "metacrypt", "A", "192.168.88.181", 300)
if err != nil {
t.Fatalf("create record: %v", err)
}
if err := db.DeleteRecord(record.ID); err != nil {
t.Fatalf("delete record: %v", err)
}
_, err = db.GetRecord(record.ID)
if !errors.Is(err, ErrNotFound) {
t.Fatalf("expected ErrNotFound after delete, got %v", err)
}
}
func TestDeleteRecordBumpsSerial(t *testing.T) {
db := openTestDB(t)
createTestZone(t, db)
record, err := db.CreateRecord("svc.mcp.metacircular.net", "metacrypt", "A", "192.168.88.181", 300)
if err != nil {
t.Fatalf("create record: %v", err)
}
zone, err := db.GetZone("svc.mcp.metacircular.net")
if err != nil {
t.Fatalf("get zone: %v", err)
}
serialBefore := zone.Serial
if err := db.DeleteRecord(record.ID); err != nil {
t.Fatalf("delete record: %v", err)
}
zone, err = db.GetZone("svc.mcp.metacircular.net")
if err != nil {
t.Fatalf("get zone after delete: %v", err)
}
if zone.Serial <= serialBefore {
t.Fatalf("serial should have bumped: %d <= %d", zone.Serial, serialBefore)
}
}
func TestLookupRecords(t *testing.T) {
db := openTestDB(t)
createTestZone(t, db)
_, err := db.CreateRecord("svc.mcp.metacircular.net", "metacrypt", "A", "192.168.88.181", 300)
if err != nil {
t.Fatalf("create record: %v", err)
}
records, err := db.LookupRecords("svc.mcp.metacircular.net", "metacrypt", "A")
if err != nil {
t.Fatalf("lookup records: %v", err)
}
if len(records) != 1 {
t.Fatalf("got %d records, want 1", len(records))
}
if records[0].Value != "192.168.88.181" {
t.Fatalf("got value %q, want %q", records[0].Value, "192.168.88.181")
}
}
func TestCreateRecordCNAMEMissingDot(t *testing.T) {
db := openTestDB(t)
createTestZone(t, db)
_, err := db.CreateRecord("svc.mcp.metacircular.net", "alias", "CNAME", "rift.mcp.metacircular.net", 300)
if err == nil {
t.Fatal("expected error for CNAME without trailing dot")
}
}
func TestMultipleARecords(t *testing.T) {
db := openTestDB(t)
createTestZone(t, db)
_, err := db.CreateRecord("svc.mcp.metacircular.net", "metacrypt", "A", "192.168.88.181", 300)
if err != nil {
t.Fatalf("create first A record: %v", err)
}
_, err = db.CreateRecord("svc.mcp.metacircular.net", "metacrypt", "A", "100.95.252.120", 300)
if err != nil {
t.Fatalf("create second A record: %v", err)
}
records, err := db.LookupRecords("svc.mcp.metacircular.net", "metacrypt", "A")
if err != nil {
t.Fatalf("lookup records: %v", err)
}
if len(records) != 2 {
t.Fatalf("got %d records, want 2", len(records))
}
}