diff --git a/const.go b/const.go index f4ca371..0ef2e1a 100644 --- a/const.go +++ b/const.go @@ -27,4 +27,5 @@ const ( readTimeout = 2 * time.Second tcptlc = "tcp-tls" tcp = "tcp" + udp = "udp" ) diff --git a/coredns/go.sum b/coredns/go.sum index 3bd5c68..576e806 100644 --- a/coredns/go.sum +++ b/coredns/go.sum @@ -83,6 +83,7 @@ github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:ma github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/davecgh/go-spew v0.0.0-20151105211317-5215b55f46b2/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/decker502/dnspod-go v0.2.0/go.mod h1:qsurYu1FgxcDwfSwXJdLt4kRsBLZeosEb9uq4Sy+08g= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= @@ -133,6 +134,7 @@ github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7a github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/goji/httpauth v0.0.0-20160601135302-2da839ab0f4d/go.mod h1:nnjvkQ9ptGaCkuDUx6wNykzzlUixGxvkme+H/lnzb+A= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -151,6 +153,7 @@ github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= @@ -211,8 +214,10 @@ github.com/kolo/xmlrpc v0.0.0-20190717152603-07c4ee3fd181/go.mod h1:o03bZfuBwAXH github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k= github.com/labbsr0x/bindman-dns-webhook v1.0.2/go.mod h1:p6b+VCXIR8NYKpDr8/dg1HKfQoRHCdcsROXKvmoehKA= @@ -252,8 +257,6 @@ github.com/namedotcom/go v0.0.0-20180403034216-08470befbe04/go.mod h1:5sN+Lt1CaY github.com/naoina/go-stringutil v0.1.0/go.mod h1:XJ2SJL9jCtBh+P9q5btrd/Ylo8XwT/h1USek5+NqSA0= github.com/naoina/toml v0.1.1/go.mod h1:NBIhNtsFMo3G2szEBne+bO4gS192HuIYRqfvOWb4i1E= github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32/go.mod h1:9wM+0iRr9ahx58uYLpLIr5fm8diHn0JbqRycJi6w0Ms= -github.com/networkservicemesh/fanout v0.0.0-20200313150119-ddef81d89163 h1:3R7Y1QbDm/IgD8GKVSapNf/yejHoaCpTGbCQf03gZm4= -github.com/networkservicemesh/fanout v0.0.0-20200313150119-ddef81d89163/go.mod h1:RhFSL1f500swQghNPxQBgwraSb1SZAlghX7ivLsH/mQ= github.com/nrdcg/auroradns v1.0.0/go.mod h1:6JPXKzIRzZzMqtTDgueIhTi6rFf1QvYE/HzqidhOhjw= github.com/nrdcg/goinwx v0.6.1/go.mod h1:XPiut7enlbEdntAqalBIqcYcTEVhpv/dKWgDCX2SwKQ= github.com/nrdcg/namesilo v0.2.1/go.mod h1:lwMvfQTyYq+BbjJd30ylEG4GPSS6PII0Tia4rRpRiyw= @@ -281,6 +284,7 @@ github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= @@ -333,6 +337,8 @@ github.com/stretchr/testify v0.0.0-20151208002404-e3a8ff8ce365/go.mod h1:a8OnRci github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/timewasted/linode v0.0.0-20160829202747-37e84520dcf7/go.mod h1:imsgLplxEC/etjIhdr3dNzV3JeT27LbVu5pYWm0JCBY= github.com/tinylib/msgp v1.1.0/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= @@ -412,6 +418,7 @@ golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180622082034-63fc586f45fe/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -466,6 +473,7 @@ golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgw golang.org/x/tools v0.0.0-20190624190245-7f2218787638/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= @@ -498,6 +506,7 @@ gopkg.in/DataDog/dd-trace-go.v1 v1.20.1/go.mod h1:DVp8HmDh8PuTu2Z0fVVlBsyWaC++fz gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= @@ -516,6 +525,7 @@ gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bl gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5 h1:ymVxjfMaHvXD8RqPRmzHHsB3VvucivSkIAvJFDI5O3c= gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/coredns/main.go b/coredns/main.go index d00fdb5..1fdca30 100644 --- a/coredns/main.go +++ b/coredns/main.go @@ -23,6 +23,7 @@ import ( _ "github.com/coredns/coredns/plugin/hosts" _ "github.com/coredns/coredns/plugin/log" _ "github.com/coredns/coredns/plugin/reload" + _ "github.com/networkservicemesh/fanout" ) diff --git a/fanout_test.go b/fanout_test.go index 37c9495..cbd21e0 100644 --- a/fanout_test.go +++ b/fanout_test.go @@ -26,6 +26,8 @@ import ( "github.com/caddyserver/caddy" "github.com/coredns/coredns/plugin/pkg/dnstest" + "github.com/stretchr/testify/suite" + "github.com/coredns/coredns/plugin/test" "github.com/miekg/dns" ) @@ -54,13 +56,27 @@ func (s *server) close() { logErrIfNotNil(s.inner.Shutdown()) } -func newServer(f dns.HandlerFunc) *server { +func newServer(network string, f dns.HandlerFunc) *server { ch := make(chan bool) s := &dns.Server{} s.Handler = f for i := 0; i < 10; i++ { - s.Listener, _ = net.Listen(tcp, ":0") + if network == tcp { + s.Listener, _ = net.Listen(tcp, ":0") + if s.Listener != nil { + break + } + } else { + s.Listener, _ = net.Listen(tcp, ":0") + if s.Listener == nil { + continue + } + s.PacketConn, _ = net.ListenPacket("udp", s.Listener.Addr().String()) + if s.PacketConn != nil { + break + } + } if s.Listener != nil { break } @@ -83,34 +99,88 @@ func makeRecordA(rr string) *dns.A { return r.(*dns.A) } -func TestFanoutCanReturnUnsuccessRespnse(t *testing.T) { - s := newServer(func(w dns.ResponseWriter, r *dns.Msg) { - msg := nxdomainMsg() - msg.SetRcode(r, msg.Rcode) - logErrIfNotNil(w.WriteMsg(msg)) +type fanoutTestSuite struct { + suite.Suite + network string +} + +func (t *fanoutTestSuite) TestConfigFromCorefile() { + s := newServer(t.network, func(w dns.ResponseWriter, r *dns.Msg) { + ret := new(dns.Msg) + ret.SetReply(r) + ret.Answer = append(ret.Answer, test.A("example.org. IN A 127.0.0.1")) + logErrIfNotNil(w.WriteMsg(ret)) }) + defer s.close() + source := `fanout . %v { + NETWORK %v +}` + c := caddy.NewTestController("dns", fmt.Sprintf(source, s.addr, t.network)) + f, err := parseFanout(c) + t.Nil(err) + err = f.OnStartup() + t.Nil(err) + defer func() { + logErrIfNotNil(f.OnShutdown()) + }() + + m := new(dns.Msg) + m.SetQuestion("example.org.", dns.TypeA) + rec := dnstest.NewRecorder(&test.ResponseWriter{}) + + _, err = f.ServeDNS(context.TODO(), rec, m) + t.Nil(err) + t.Equal(rec.Msg.Answer[0].Header().Name, "example.org.") +} + +func (t *fanoutTestSuite) TestWorkerCountLessThenServers() { + const expected = 1 + answerCount := 0 + var mutex sync.Mutex + var closeFuncs []func() + free := func() { + for _, f := range closeFuncs { + f() + } + } + defer free() f := New() f.from = "." - c := NewClient(s.addr, "tcp") - f.addClient(c) + + for i := 0; i < 4; i++ { + incorrectServer := newServer(t.network, func(w dns.ResponseWriter, r *dns.Msg) { + }) + f.addClient(NewClient(incorrectServer.addr, t.network)) + closeFuncs = append(closeFuncs, incorrectServer.close) + } + correctServer := newServer(t.network, func(w dns.ResponseWriter, r *dns.Msg) { + if r.Question[0].Name == testQuery { + msg := dns.Msg{ + Answer: []dns.RR{makeRecordA("example1 3600 IN A 10.0.0.1")}, + } + mutex.Lock() + answerCount++ + mutex.Unlock() + msg.SetReply(r) + logErrIfNotNil(w.WriteMsg(&msg)) + } + }) + + f.addClient(NewClient(correctServer.addr, t.network)) + f.workerCount = 1 req := new(dns.Msg) req.SetQuestion(testQuery, dns.TypeA) - writer := &cachedDNSWriter{ResponseWriter: new(test.ResponseWriter)} - _, err := f.ServeDNS(context.TODO(), writer, req) - if err != nil { - t.Fatal(err) - } - if len(writer.answers) != 1 { - t.FailNow() - } - if writer.answers[0].MsgHdr.Rcode != dns.RcodeNameError { - t.Error("fanout plugin returns first negative answer if other answers on request are negative") - } + _, err := f.ServeDNS(context.TODO(), &test.ResponseWriter{}, req) + t.Nil(err) + <-time.After(time.Second) + mutex.Lock() + defer mutex.Unlock() + t.Equal(answerCount, expected) } -func TestFanoutTwoServersNotSuccessResponse(t *testing.T) { +func (t *fanoutTestSuite) TestTwoServersUnsuccessfulResponse() { rcode := 1 rcodeMutex := sync.Mutex{} - s1 := newServer(func(w dns.ResponseWriter, r *dns.Msg) { + s1 := newServer(t.network, func(w dns.ResponseWriter, r *dns.Msg) { if r.Question[0].Name == testQuery { msg := nxdomainMsg() rcodeMutex.Lock() @@ -121,7 +191,7 @@ func TestFanoutTwoServersNotSuccessResponse(t *testing.T) { logErrIfNotNil(w.WriteMsg(msg)) } }) - s2 := newServer(func(w dns.ResponseWriter, r *dns.Msg) { + s2 := newServer(t.network, func(w dns.ResponseWriter, r *dns.Msg) { if r.Question[0].Name == testQuery { msg := dns.Msg{ Answer: []dns.RR{makeRecordA("example1. 3600 IN A 10.0.0.1")}, @@ -132,9 +202,10 @@ func TestFanoutTwoServersNotSuccessResponse(t *testing.T) { }) defer s1.close() defer s2.close() - c1 := NewClient(s1.addr, "tcp") - c2 := NewClient(s2.addr, "tcp") + c1 := NewClient(s1.addr, t.network) + c2 := NewClient(s2.addr, t.network) f := New() + f.net = t.network f.from = "." f.addClient(c1) f.addClient(c2) @@ -143,23 +214,39 @@ func TestFanoutTwoServersNotSuccessResponse(t *testing.T) { req := new(dns.Msg) req.SetQuestion(testQuery, dns.TypeA) _, err := f.ServeDNS(context.TODO(), writer, req) - if err != nil { - t.Fatal(err.Error()) - } + t.Nil(err) } for _, m := range writer.answers { - if m.MsgHdr.Rcode != dns.RcodeSuccess { - t.Error("fanout should return only positive answers") - } + t.Equal(m.MsgHdr.Rcode, dns.RcodeSuccess) } } -func TestFanoutTwoServers(t *testing.T) { +func (t *fanoutTestSuite) TestCanReturnUnsuccessfulRepose() { + s := newServer(t.network, func(w dns.ResponseWriter, r *dns.Msg) { + msg := nxdomainMsg() + msg.SetRcode(r, msg.Rcode) + logErrIfNotNil(w.WriteMsg(msg)) + }) + f := New() + f.net = t.network + f.from = "." + c := NewClient(s.addr, t.network) + f.addClient(c) + req := new(dns.Msg) + req.SetQuestion(testQuery, dns.TypeA) + writer := &cachedDNSWriter{ResponseWriter: new(test.ResponseWriter)} + _, err := f.ServeDNS(context.Background(), writer, req) + t.Nil(err) + t.Len(writer.answers, 1) + t.Equal(writer.answers[0].MsgHdr.Rcode, dns.RcodeNameError, "fanout plugin returns first negative answer if other answers on request are negative") +} + +func (t *fanoutTestSuite) TestTwoServers() { const expected = 1 var mutex sync.Mutex answerCount1 := 0 answerCount2 := 0 - s1 := newServer(func(w dns.ResponseWriter, r *dns.Msg) { + s1 := newServer(t.network, func(w dns.ResponseWriter, r *dns.Msg) { if r.Question[0].Name == testQuery { msg := dns.Msg{ Answer: []dns.RR{makeRecordA("example1 3600 IN A 10.0.0.1")}, @@ -171,7 +258,7 @@ func TestFanoutTwoServers(t *testing.T) { logErrIfNotNil(w.WriteMsg(&msg)) } }) - s2 := newServer(func(w dns.ResponseWriter, r *dns.Msg) { + s2 := newServer(t.network, func(w dns.ResponseWriter, r *dns.Msg) { if r.Question[0].Name == "example2." { msg := dns.Msg{ Answer: []dns.RR{makeRecordA("example2. 3600 IN A 10.0.0.1")}, @@ -186,9 +273,10 @@ func TestFanoutTwoServers(t *testing.T) { defer s1.close() defer s2.close() - c1 := NewClient(s1.addr, "tcp") - c2 := NewClient(s2.addr, "tcp") + c1 := NewClient(s1.addr, t.network) + c2 := NewClient(s2.addr, t.network) f := New() + f.net = t.network f.from = "." f.addClient(c1) f.addClient(c2) @@ -196,107 +284,25 @@ func TestFanoutTwoServers(t *testing.T) { req := new(dns.Msg) req.SetQuestion(testQuery, dns.TypeA) _, err := f.ServeDNS(context.TODO(), &test.ResponseWriter{}, req) - if err != nil { - t.Fatal(err.Error()) - } + t.Nil(err) <-time.After(time.Second) req = new(dns.Msg) req.SetQuestion("example2.", dns.TypeA) _, err = f.ServeDNS(context.TODO(), &test.ResponseWriter{}, req) - if err != nil { - t.Fatal(err.Error()) - } + t.Nil(err) mutex.Lock() defer mutex.Unlock() - if answerCount2 != expected || answerCount1 != expected { - t.Errorf("Expected number of health checks to be %d, got s1: %d, s2: %d", expected, answerCount1, answerCount2) - } + t.Equal(answerCount1, expected) + t.Equal(answerCount2, expected) } -func TestFanouWorkerCountLessThenServers(t *testing.T) { - const expected = 1 - answerCount1 := 0 - var mutex sync.Mutex - var closeFuncs []func() - free := func() { - for _, f := range closeFuncs { - f() - } - } - defer free() - f := New() - f.from = "." - - for i := 0; i < 4; i++ { - incorrectServer := newServer(func(w dns.ResponseWriter, r *dns.Msg) { - }) - f.addClient(NewClient(incorrectServer.addr, "tcp")) - closeFuncs = append(closeFuncs, incorrectServer.close) - } - correctServer := newServer(func(w dns.ResponseWriter, r *dns.Msg) { - if r.Question[0].Name == testQuery { - msg := dns.Msg{ - Answer: []dns.RR{makeRecordA("example1 3600 IN A 10.0.0.1")}, - } - mutex.Lock() - answerCount1++ - mutex.Unlock() - msg.SetReply(r) - logErrIfNotNil(w.WriteMsg(&msg)) - } - }) - - f.addClient(NewClient(correctServer.addr, "tcp")) - f.workerCount = 1 - req := new(dns.Msg) - req.SetQuestion(testQuery, dns.TypeA) - _, err := f.ServeDNS(context.TODO(), &test.ResponseWriter{}, req) - if err != nil { - t.FailNow() - } - <-time.After(time.Second) - mutex.Lock() - defer mutex.Unlock() - if answerCount1 != expected { - t.Errorf("Expected number of health checks to be %d, got : %d,", expected, answerCount1) - } +func TestFanoutUDPSuite(t *testing.T) { + suite.Run(t, &fanoutTestSuite{network: udp}) } - -func TestFanout(t *testing.T) { - s := newServer(func(w dns.ResponseWriter, r *dns.Msg) { - ret := new(dns.Msg) - ret.SetReply(r) - ret.Answer = append(ret.Answer, test.A("example.org. IN A 127.0.0.1")) - logErrIfNotNil(w.WriteMsg(ret)) - }) - defer s.close() - source := `fanout . %v { - NETWORK tcp -}` - c := caddy.NewTestController("dns", fmt.Sprintf(source, s.addr)) - f, err := parseFanout(c) - if err != nil { - t.Fatalf("Failed to create fanout: %s", err) - } - err = f.OnStartup() - if err != nil { - t.Fatal(err.Error()) - } - defer func() { - logErrIfNotNil(f.OnShutdown()) - }() - - m := new(dns.Msg) - m.SetQuestion("example.org.", dns.TypeA) - rec := dnstest.NewRecorder(&test.ResponseWriter{}) - - if _, err := f.ServeDNS(context.TODO(), rec, m); err != nil { - t.Fatal("Expected to receive reply, but didn't") - } - if x := rec.Msg.Answer[0].Header().Name; x != "example.org." { - t.Errorf("Expected %s, got %s", "example.org.", x) - } +func TestFanoutTCPSuite(t *testing.T) { + suite.Run(t, &fanoutTestSuite{network: tcp}) } + func nxdomainMsg() *dns.Msg { return &dns.Msg{MsgHdr: dns.MsgHdr{Rcode: dns.RcodeNameError}, Question: []dns.Question{{Name: "wwww.example1.", Qclass: dns.ClassINET, Qtype: dns.TypeTXT}}, diff --git a/go.mod b/go.mod index b0351a5..508084b 100644 --- a/go.mod +++ b/go.mod @@ -9,4 +9,5 @@ require ( github.com/miekg/dns v1.1.28 github.com/pkg/errors v0.9.1 github.com/prometheus/client_golang v1.5.0 + github.com/stretchr/testify v1.5.1 ) diff --git a/go.sum b/go.sum index 9c52bb8..41e47b0 100644 --- a/go.sum +++ b/go.sum @@ -332,12 +332,15 @@ github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzu github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v0.0.0-20151208002404-e3a8ff8ce365/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/timewasted/linode v0.0.0-20160829202747-37e84520dcf7/go.mod h1:imsgLplxEC/etjIhdr3dNzV3JeT27LbVu5pYWm0JCBY= github.com/tinylib/msgp v1.1.0/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=