package vmdns import ( "net" "testing" "github.com/miekg/dns" ) func TestRecordName(t *testing.T) { if got := RecordName("DevBox"); got != "devbox.vm" { t.Fatalf("RecordName = %q, want devbox.vm", got) } if got := RecordName("already.vm"); got != "already.vm" { t.Fatalf("RecordName = %q, want already.vm", got) } } func TestServerAnswersVMQueries(t *testing.T) { server := startTestServer(t) if err := server.Set("devbox.vm", "172.16.0.8"); err != nil { t.Fatalf("Set: %v", err) } t.Run("A record", func(t *testing.T) { resp := exchangeQuery(t, server.Addr(), "devbox.vm.", dns.TypeA) if resp.Rcode != dns.RcodeSuccess { t.Fatalf("rcode = %d, want success", resp.Rcode) } if len(resp.Answer) != 1 { t.Fatalf("answer count = %d, want 1", len(resp.Answer)) } a, ok := resp.Answer[0].(*dns.A) if !ok { t.Fatalf("answer type = %T, want *dns.A", resp.Answer[0]) } if got := a.A.String(); got != "172.16.0.8" { t.Fatalf("A = %q, want 172.16.0.8", got) } }) t.Run("known AAAA returns NODATA", func(t *testing.T) { resp := exchangeQuery(t, server.Addr(), "devbox.vm.", dns.TypeAAAA) if resp.Rcode != dns.RcodeSuccess { t.Fatalf("rcode = %d, want success", resp.Rcode) } if len(resp.Answer) != 0 { t.Fatalf("answer count = %d, want 0", len(resp.Answer)) } }) t.Run("unknown name returns NXDOMAIN", func(t *testing.T) { resp := exchangeQuery(t, server.Addr(), "missing.vm.", dns.TypeA) if resp.Rcode != dns.RcodeNameError { t.Fatalf("rcode = %d, want NXDOMAIN", resp.Rcode) } }) t.Run("outside zone returns REFUSED", func(t *testing.T) { resp := exchangeQuery(t, server.Addr(), "example.com.", dns.TypeA) if resp.Rcode != dns.RcodeRefused { t.Fatalf("rcode = %d, want REFUSED", resp.Rcode) } }) } func TestServerReplaceSwapsRecordSet(t *testing.T) { server := startTestServer(t) if err := server.Replace(map[string]string{ "alpha.vm": "172.16.0.2", "beta.vm": "172.16.0.3", }); err != nil { t.Fatalf("Replace: %v", err) } if _, ok := server.Lookup("alpha.vm"); !ok { t.Fatal("alpha.vm missing after replace") } if err := server.Replace(map[string]string{"beta.vm": "172.16.0.4"}); err != nil { t.Fatalf("Replace second set: %v", err) } if _, ok := server.Lookup("alpha.vm"); ok { t.Fatal("alpha.vm should have been removed by replace") } addr, ok := server.Lookup("beta.vm") if !ok || addr.String() != "172.16.0.4" { t.Fatalf("beta.vm = %v, %v, want 172.16.0.4", addr, ok) } } func TestServerFailsWhenAddressAlreadyInUse(t *testing.T) { packetConn, err := net.ListenPacket("udp", "127.0.0.1:0") if err != nil { t.Fatalf("ListenPacket: %v", err) } defer packetConn.Close() if _, err := New(packetConn.LocalAddr().String(), nil); err == nil { t.Fatal("New() succeeded on occupied UDP address, want failure") } } func startTestServer(t *testing.T) *Server { t.Helper() server, err := New("127.0.0.1:0", nil) if err != nil { t.Fatalf("New: %v", err) } t.Cleanup(func() { if err := server.Close(); err != nil { t.Fatalf("Close: %v", err) } }) return server } func exchangeQuery(t *testing.T, addr, name string, qtype uint16) *dns.Msg { t.Helper() client := &dns.Client{Net: "udp"} req := new(dns.Msg) req.SetQuestion(name, qtype) resp, _, err := client.Exchange(req, addr) if err != nil { t.Fatalf("Exchange(%s, %d): %v", name, qtype, err) } return resp }