278 lines
		
	
	
		
			6.5 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			278 lines
		
	
	
		
			6.5 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| // +build ignore
 | |
| 
 | |
| package mdns
 | |
| 
 | |
| import (
 | |
| 	"bytes"
 | |
| 	"net"
 | |
| 	"reflect"
 | |
| 	"testing"
 | |
| 
 | |
| 	"github.com/miekg/dns"
 | |
| )
 | |
| 
 | |
| func makeService(t *testing.T) *MDNSService {
 | |
| 	return makeServiceWithServiceName(t, "_http._tcp")
 | |
| }
 | |
| 
 | |
| func makeServiceWithServiceName(t *testing.T, service string) *MDNSService {
 | |
| 	m, err := NewMDNSService(
 | |
| 		"hostname",
 | |
| 		service,
 | |
| 		"local.",
 | |
| 		"testhost.",
 | |
| 		80, // port
 | |
| 		[]net.IP{net.IP([]byte{192, 168, 0, 42}), net.ParseIP("2620:0:1000:1900:b0c2:d0b2:c411:18bc")},
 | |
| 		[]string{"Local web server"}) // TXT
 | |
| 
 | |
| 	if err != nil {
 | |
| 		t.Fatalf("err: %v", err)
 | |
| 	}
 | |
| 
 | |
| 	return m
 | |
| }
 | |
| 
 | |
| func TestNewMDNSService_BadParams(t *testing.T) {
 | |
| 	for _, test := range []struct {
 | |
| 		testName string
 | |
| 		hostName string
 | |
| 		domain   string
 | |
| 	}{
 | |
| 		{
 | |
| 			"NewMDNSService should fail when passed hostName that is not a legal fully-qualified domain name",
 | |
| 			"hostname", // not legal FQDN - should be "hostname." or "hostname.local.", etc.
 | |
| 			"local.",   // legal
 | |
| 		},
 | |
| 		{
 | |
| 			"NewMDNSService should fail when passed domain that is not a legal fully-qualified domain name",
 | |
| 			"hostname.", // legal
 | |
| 			"local",     // should be "local."
 | |
| 		},
 | |
| 	} {
 | |
| 		_, err := NewMDNSService(
 | |
| 			"instance name",
 | |
| 			"_http._tcp",
 | |
| 			test.domain,
 | |
| 			test.hostName,
 | |
| 			80, // port
 | |
| 			[]net.IP{net.IP([]byte{192, 168, 0, 42})},
 | |
| 			[]string{"Local web server"}) // TXT
 | |
| 		if err == nil {
 | |
| 			t.Fatalf("%s: error expected, but got none", test.testName)
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func TestMDNSService_BadAddr(t *testing.T) {
 | |
| 	s := makeService(t)
 | |
| 	q := dns.Question{
 | |
| 		Name:  "random",
 | |
| 		Qtype: dns.TypeANY,
 | |
| 	}
 | |
| 	recs := s.Records(q)
 | |
| 	if len(recs) != 0 {
 | |
| 		t.Fatalf("bad: %v", recs)
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func TestMDNSService_ServiceAddr(t *testing.T) {
 | |
| 	s := makeService(t)
 | |
| 	q := dns.Question{
 | |
| 		Name:  "_http._tcp.local.",
 | |
| 		Qtype: dns.TypeANY,
 | |
| 	}
 | |
| 	recs := s.Records(q)
 | |
| 	if got, want := len(recs), 5; got != want {
 | |
| 		t.Fatalf("got %d records, want %d: %v", got, want, recs)
 | |
| 	}
 | |
| 
 | |
| 	if ptr, ok := recs[0].(*dns.PTR); !ok {
 | |
| 		t.Errorf("recs[0] should be PTR record, got: %v, all records: %v", recs[0], recs)
 | |
| 	} else if got, want := ptr.Ptr, "hostname._http._tcp.local."; got != want {
 | |
| 		t.Fatalf("bad PTR record %v: got %v, want %v", ptr, got, want)
 | |
| 	}
 | |
| 
 | |
| 	if _, ok := recs[1].(*dns.SRV); !ok {
 | |
| 		t.Errorf("recs[1] should be SRV record, got: %v, all reccords: %v", recs[1], recs)
 | |
| 	}
 | |
| 	if _, ok := recs[2].(*dns.A); !ok {
 | |
| 		t.Errorf("recs[2] should be A record, got: %v, all records: %v", recs[2], recs)
 | |
| 	}
 | |
| 	if _, ok := recs[3].(*dns.AAAA); !ok {
 | |
| 		t.Errorf("recs[3] should be AAAA record, got: %v, all records: %v", recs[3], recs)
 | |
| 	}
 | |
| 	if _, ok := recs[4].(*dns.TXT); !ok {
 | |
| 		t.Errorf("recs[4] should be TXT record, got: %v, all records: %v", recs[4], recs)
 | |
| 	}
 | |
| 
 | |
| 	q.Qtype = dns.TypePTR
 | |
| 	if recs2 := s.Records(q); !reflect.DeepEqual(recs, recs2) {
 | |
| 		t.Fatalf("PTR question should return same result as ANY question: ANY => %v, PTR => %v", recs, recs2)
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func TestMDNSService_InstanceAddr_ANY(t *testing.T) {
 | |
| 	s := makeService(t)
 | |
| 	q := dns.Question{
 | |
| 		Name:  "hostname._http._tcp.local.",
 | |
| 		Qtype: dns.TypeANY,
 | |
| 	}
 | |
| 	recs := s.Records(q)
 | |
| 	if len(recs) != 4 {
 | |
| 		t.Fatalf("bad: %v", recs)
 | |
| 	}
 | |
| 	if _, ok := recs[0].(*dns.SRV); !ok {
 | |
| 		t.Fatalf("bad: %v", recs[0])
 | |
| 	}
 | |
| 	if _, ok := recs[1].(*dns.A); !ok {
 | |
| 		t.Fatalf("bad: %v", recs[1])
 | |
| 	}
 | |
| 	if _, ok := recs[2].(*dns.AAAA); !ok {
 | |
| 		t.Fatalf("bad: %v", recs[2])
 | |
| 	}
 | |
| 	if _, ok := recs[3].(*dns.TXT); !ok {
 | |
| 		t.Fatalf("bad: %v", recs[3])
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func TestMDNSService_InstanceAddr_SRV(t *testing.T) {
 | |
| 	s := makeService(t)
 | |
| 	q := dns.Question{
 | |
| 		Name:  "hostname._http._tcp.local.",
 | |
| 		Qtype: dns.TypeSRV,
 | |
| 	}
 | |
| 	recs := s.Records(q)
 | |
| 	if len(recs) != 3 {
 | |
| 		t.Fatalf("bad: %v", recs)
 | |
| 	}
 | |
| 	srv, ok := recs[0].(*dns.SRV)
 | |
| 	if !ok {
 | |
| 		t.Fatalf("bad: %v", recs[0])
 | |
| 	}
 | |
| 	if _, ok := recs[1].(*dns.A); !ok {
 | |
| 		t.Fatalf("bad: %v", recs[1])
 | |
| 	}
 | |
| 	if _, ok := recs[2].(*dns.AAAA); !ok {
 | |
| 		t.Fatalf("bad: %v", recs[2])
 | |
| 	}
 | |
| 
 | |
| 	if srv.Port != uint16(s.Port) {
 | |
| 		t.Fatalf("bad: %v", recs[0])
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func TestMDNSService_InstanceAddr_A(t *testing.T) {
 | |
| 	s := makeService(t)
 | |
| 	q := dns.Question{
 | |
| 		Name:  "hostname._http._tcp.local.",
 | |
| 		Qtype: dns.TypeA,
 | |
| 	}
 | |
| 	recs := s.Records(q)
 | |
| 	if len(recs) != 1 {
 | |
| 		t.Fatalf("bad: %v", recs)
 | |
| 	}
 | |
| 	a, ok := recs[0].(*dns.A)
 | |
| 	if !ok {
 | |
| 		t.Fatalf("bad: %v", recs[0])
 | |
| 	}
 | |
| 	if !bytes.Equal(a.A, []byte{192, 168, 0, 42}) {
 | |
| 		t.Fatalf("bad: %v", recs[0])
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func TestMDNSService_InstanceAddr_AAAA(t *testing.T) {
 | |
| 	s := makeService(t)
 | |
| 	q := dns.Question{
 | |
| 		Name:  "hostname._http._tcp.local.",
 | |
| 		Qtype: dns.TypeAAAA,
 | |
| 	}
 | |
| 	recs := s.Records(q)
 | |
| 	if len(recs) != 1 {
 | |
| 		t.Fatalf("bad: %v", recs)
 | |
| 	}
 | |
| 	a4, ok := recs[0].(*dns.AAAA)
 | |
| 	if !ok {
 | |
| 		t.Fatalf("bad: %v", recs[0])
 | |
| 	}
 | |
| 	ip6 := net.ParseIP("2620:0:1000:1900:b0c2:d0b2:c411:18bc")
 | |
| 	if got := len(ip6); got != net.IPv6len {
 | |
| 		t.Fatalf("test IP failed to parse (len = %d, want %d)", got, net.IPv6len)
 | |
| 	}
 | |
| 	if !bytes.Equal(a4.AAAA, ip6) {
 | |
| 		t.Fatalf("bad: %v", recs[0])
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func TestMDNSService_InstanceAddr_TXT(t *testing.T) {
 | |
| 	s := makeService(t)
 | |
| 	q := dns.Question{
 | |
| 		Name:  "hostname._http._tcp.local.",
 | |
| 		Qtype: dns.TypeTXT,
 | |
| 	}
 | |
| 	recs := s.Records(q)
 | |
| 	if len(recs) != 1 {
 | |
| 		t.Fatalf("bad: %v", recs)
 | |
| 	}
 | |
| 	txt, ok := recs[0].(*dns.TXT)
 | |
| 	if !ok {
 | |
| 		t.Fatalf("bad: %v", recs[0])
 | |
| 	}
 | |
| 	if got, want := txt.Txt, s.TXT; !reflect.DeepEqual(got, want) {
 | |
| 		t.Fatalf("TXT record mismatch for %v: got %v, want %v", recs[0], got, want)
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func TestMDNSService_HostNameQuery(t *testing.T) {
 | |
| 	s := makeService(t)
 | |
| 	for _, test := range []struct {
 | |
| 		q    dns.Question
 | |
| 		want []dns.RR
 | |
| 	}{
 | |
| 		{
 | |
| 			dns.Question{Name: "testhost.", Qtype: dns.TypeA},
 | |
| 			[]dns.RR{&dns.A{
 | |
| 				Hdr: dns.RR_Header{
 | |
| 					Name:   "testhost.",
 | |
| 					Rrtype: dns.TypeA,
 | |
| 					Class:  dns.ClassINET,
 | |
| 					Ttl:    120,
 | |
| 				},
 | |
| 				A: net.IP([]byte{192, 168, 0, 42}),
 | |
| 			}},
 | |
| 		},
 | |
| 		{
 | |
| 			dns.Question{Name: "testhost.", Qtype: dns.TypeAAAA},
 | |
| 			[]dns.RR{&dns.AAAA{
 | |
| 				Hdr: dns.RR_Header{
 | |
| 					Name:   "testhost.",
 | |
| 					Rrtype: dns.TypeAAAA,
 | |
| 					Class:  dns.ClassINET,
 | |
| 					Ttl:    120,
 | |
| 				},
 | |
| 				AAAA: net.ParseIP("2620:0:1000:1900:b0c2:d0b2:c411:18bc"),
 | |
| 			}},
 | |
| 		},
 | |
| 	} {
 | |
| 		if got := s.Records(test.q); !reflect.DeepEqual(got, test.want) {
 | |
| 			t.Errorf("hostname query failed: s.Records(%v) = %v, want %v", test.q, got, test.want)
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func TestMDNSService_serviceEnum_PTR(t *testing.T) {
 | |
| 	s := makeService(t)
 | |
| 	q := dns.Question{
 | |
| 		Name:  "_services._dns-sd._udp.local.",
 | |
| 		Qtype: dns.TypePTR,
 | |
| 	}
 | |
| 	recs := s.Records(q)
 | |
| 	if len(recs) != 1 {
 | |
| 		t.Fatalf("bad: %v", recs)
 | |
| 	}
 | |
| 	if ptr, ok := recs[0].(*dns.PTR); !ok {
 | |
| 		t.Errorf("recs[0] should be PTR record, got: %v, all records: %v", recs[0], recs)
 | |
| 	} else if got, want := ptr.Ptr, "_http._tcp.local."; got != want {
 | |
| 		t.Fatalf("bad PTR record %v: got %v, want %v", ptr, got, want)
 | |
| 	}
 | |
| }
 |