The Local was redundant (and inaccurate in the case of the mDNS client implementation), and otherwise they are too nondescript.
187 lines
5.1 KiB
Go
187 lines
5.1 KiB
Go
package nameserver
|
|
|
|
import (
|
|
"github.com/miekg/dns"
|
|
wt "github.com/zettio/weave/testing"
|
|
"log"
|
|
"net"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
var (
|
|
successTestName = "test1.weave."
|
|
failTestName = "test2.weave."
|
|
testAddr = net.ParseIP("9.8.7.6")
|
|
testInAddr = "6.7.8.9.in-addr.arpa."
|
|
)
|
|
|
|
func minimalServer(w dns.ResponseWriter, req *dns.Msg) {
|
|
|
|
sendAnswer := func(m *dns.Msg) {
|
|
buf, err := m.Pack()
|
|
checkFatal(err)
|
|
if buf == nil {
|
|
log.Fatal("Nil buffer")
|
|
}
|
|
//log.Println("minimalServer sending:", buf)
|
|
// This is a bit of a kludge - per the RFC we should send responses from 5353, but that doesn't seem to work
|
|
sendconn, err := net.DialUDP("udp", nil, ipv4Addr)
|
|
checkFatal(err)
|
|
|
|
_, err = sendconn.Write(buf)
|
|
sendconn.Close()
|
|
checkFatal(err)
|
|
}
|
|
|
|
//log.Println("minimalServer received:", req)
|
|
if len(req.Answer) > 0 {
|
|
return // Only interested in questions.
|
|
}
|
|
if len(req.Question) != 1 {
|
|
return // We only handle single-question messages
|
|
}
|
|
|
|
if req.Question[0].Qtype == dns.TypeA && req.Question[0].Name == successTestName {
|
|
m := new(dns.Msg)
|
|
m.SetReply(req)
|
|
hdr := dns.RR_Header{Name: m.Question[0].Name, Rrtype: dns.TypeA,
|
|
Class: dns.ClassINET, Ttl: 3600}
|
|
a := &dns.A{hdr, testAddr}
|
|
m.Answer = append(m.Answer, a)
|
|
sendAnswer(m)
|
|
} else if req.Question[0].Qtype == dns.TypePTR && req.Question[0].Name == testInAddr {
|
|
m := new(dns.Msg)
|
|
m.SetReply(req)
|
|
hdr := dns.RR_Header{Name: m.Question[0].Name, Rrtype: dns.TypePTR,
|
|
Class: dns.ClassINET, Ttl: 3600}
|
|
a := &dns.PTR{hdr, successTestName}
|
|
m.Answer = append(m.Answer, a)
|
|
sendAnswer(m)
|
|
}
|
|
}
|
|
|
|
func RunLocalMulticastServer() (*dns.Server, error) {
|
|
multicast, err := net.ListenMulticastUDP("udp", nil, ipv4Addr)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
server := &dns.Server{Listener: nil, PacketConn: multicast, Handler: dns.HandlerFunc(minimalServer)}
|
|
go server.ActivateAndServe()
|
|
return server, nil
|
|
}
|
|
|
|
func setup(t *testing.T) (*MDNSClient, *dns.Server, error) {
|
|
mdnsClient, err := NewMDNSClient()
|
|
wt.AssertNoErr(t, err)
|
|
err = mdnsClient.Start(nil)
|
|
wt.AssertNoErr(t, err)
|
|
|
|
server, err := RunLocalMulticastServer()
|
|
if err != nil {
|
|
t.Fatalf("Unable to run test server: %s", err)
|
|
}
|
|
return mdnsClient, server, err
|
|
}
|
|
|
|
type testContext struct {
|
|
receivedAddr net.IP
|
|
receivedCount int
|
|
channel chan *Response
|
|
}
|
|
|
|
func newTestContext() *testContext {
|
|
return &testContext{channel: make(chan *Response, 4)}
|
|
}
|
|
|
|
func (c *testContext) checkResponse(t *testing.T, channelOk bool, resp *Response) {
|
|
if !channelOk {
|
|
c.channel = nil
|
|
return
|
|
}
|
|
wt.AssertNoErr(t, resp.Err)
|
|
log.Printf("Got address response %s addr %s", resp.Name, resp.Addr)
|
|
c.receivedAddr = resp.Addr
|
|
c.receivedCount++
|
|
}
|
|
|
|
func TestSimpleQuery(t *testing.T) {
|
|
log.Println("TestSimpleQuery starting")
|
|
mdnsClient, server, _ := setup(t)
|
|
defer mdnsClient.Shutdown()
|
|
defer server.Shutdown()
|
|
|
|
context := newTestContext()
|
|
|
|
// First, a test we expect to succeed
|
|
mdnsClient.SendQuery(successTestName, dns.TypeA, context.channel)
|
|
for resp := range context.channel {
|
|
context.checkResponse(t, true, resp)
|
|
}
|
|
|
|
if !context.receivedAddr.Equal(testAddr) || context.receivedCount != 1 {
|
|
t.Fatal("Unexpected result for", successTestName, context.receivedAddr, context.receivedCount)
|
|
}
|
|
|
|
// Now, a test we expect to time out with no responses
|
|
context = newTestContext()
|
|
mdnsClient.SendQuery("test2.weave.", dns.TypeA, context.channel)
|
|
for resp := range context.channel {
|
|
context.checkResponse(t, true, resp)
|
|
}
|
|
|
|
if context.receivedCount > 0 {
|
|
t.Fatal("Unexpected result for test2.weave", context.receivedAddr)
|
|
}
|
|
}
|
|
|
|
func TestParallelQuery(t *testing.T) {
|
|
log.Println("TestParallelQuery starting")
|
|
mdnsClient, server, _ := setup(t)
|
|
defer mdnsClient.Shutdown()
|
|
defer server.Shutdown()
|
|
|
|
context1 := newTestContext()
|
|
context2 := newTestContext()
|
|
|
|
go mdnsClient.SendQuery(successTestName, dns.TypeA, context1.channel)
|
|
go mdnsClient.SendQuery(successTestName, dns.TypeA, context2.channel)
|
|
timeout := time.After(2 * time.Second)
|
|
outerloop:
|
|
for context1.channel != nil || context2.channel != nil {
|
|
select {
|
|
case resp, ok := <-context1.channel:
|
|
context1.checkResponse(t, ok, resp)
|
|
case resp, ok := <-context2.channel:
|
|
context2.checkResponse(t, ok, resp)
|
|
case <-timeout:
|
|
break outerloop
|
|
}
|
|
}
|
|
|
|
if !context1.receivedAddr.Equal(testAddr) || !context2.receivedAddr.Equal(testAddr) || context1.receivedCount != 1 || context2.receivedCount != 1 {
|
|
t.Fatal("Unexpected result for", successTestName, context1.receivedAddr, context2.receivedAddr, context1.receivedCount, context2.receivedCount)
|
|
}
|
|
}
|
|
|
|
func TestAsLookup(t *testing.T) {
|
|
mdnsClient, server, _ := setup(t)
|
|
defer mdnsClient.Shutdown()
|
|
defer server.Shutdown()
|
|
|
|
ip, err := mdnsClient.LookupName(successTestName)
|
|
wt.AssertNoErr(t, err)
|
|
if !testAddr.Equal(ip) {
|
|
t.Fatalf("Returned address incorrect %s", ip)
|
|
}
|
|
|
|
ip, err = mdnsClient.LookupName("foo.example.com.")
|
|
wt.AssertErrorType(t, err, (*LookupError)(nil), "unknown hostname")
|
|
|
|
name, err := mdnsClient.LookupInaddr(testInAddr)
|
|
wt.AssertNoErr(t, err)
|
|
if !(successTestName == name) {
|
|
t.Fatalf("Expected name %s, got %s", successTestName, name)
|
|
}
|
|
}
|