* plugin/forward: add HealthChecker interface Make the HealthChecker interface and morph the current DNS health checker into that interface. Remove all whole bunch of method on Forward that didn't make sense. This is done in preparation of adding a DoH client to forward - which requires a completely different healthcheck implementation (and more, but lets start here) Signed-off-by: Miek Gieben <miek@miek.nl> * Use protocol Signed-off-by: Miek Gieben <miek@miek.nl> * Dial doesnt need to be method an Forward either Signed-off-by: Miek Gieben <miek@miek.nl> * Address comments Address various comments on the PR. Signed-off-by: Miek Gieben <miek@miek.nl>
182 lines
3.7 KiB
Go
182 lines
3.7 KiB
Go
package forward
|
|
|
|
import (
|
|
"context"
|
|
"sync/atomic"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/coredns/coredns/plugin/pkg/dnstest"
|
|
"github.com/coredns/coredns/plugin/test"
|
|
|
|
"github.com/miekg/dns"
|
|
)
|
|
|
|
func TestHealth(t *testing.T) {
|
|
const expected = 0
|
|
i := uint32(0)
|
|
s := dnstest.NewServer(func(w dns.ResponseWriter, r *dns.Msg) {
|
|
if r.Question[0].Name == "." {
|
|
atomic.AddUint32(&i, 1)
|
|
}
|
|
ret := new(dns.Msg)
|
|
ret.SetReply(r)
|
|
w.WriteMsg(ret)
|
|
})
|
|
defer s.Close()
|
|
|
|
p := NewProxy(s.Addr, DNS)
|
|
f := New()
|
|
f.SetProxy(p)
|
|
defer f.Close()
|
|
|
|
req := new(dns.Msg)
|
|
req.SetQuestion("example.org.", dns.TypeA)
|
|
|
|
f.ServeDNS(context.TODO(), &test.ResponseWriter{}, req)
|
|
|
|
time.Sleep(1 * time.Second)
|
|
i1 := atomic.LoadUint32(&i)
|
|
if i1 != expected {
|
|
t.Errorf("Expected number of health checks to be %d, got %d", expected, i1)
|
|
}
|
|
}
|
|
|
|
func TestHealthTimeout(t *testing.T) {
|
|
const expected = 1
|
|
i := uint32(0)
|
|
q := uint32(0)
|
|
s := dnstest.NewServer(func(w dns.ResponseWriter, r *dns.Msg) {
|
|
if r.Question[0].Name == "." {
|
|
// health check, answer
|
|
atomic.AddUint32(&i, 1)
|
|
ret := new(dns.Msg)
|
|
ret.SetReply(r)
|
|
w.WriteMsg(ret)
|
|
return
|
|
}
|
|
if atomic.LoadUint32(&q) == 0 { //drop only first query
|
|
atomic.AddUint32(&q, 1)
|
|
return
|
|
}
|
|
ret := new(dns.Msg)
|
|
ret.SetReply(r)
|
|
w.WriteMsg(ret)
|
|
})
|
|
defer s.Close()
|
|
|
|
p := NewProxy(s.Addr, DNS)
|
|
f := New()
|
|
f.SetProxy(p)
|
|
defer f.Close()
|
|
|
|
req := new(dns.Msg)
|
|
req.SetQuestion("example.org.", dns.TypeA)
|
|
|
|
f.ServeDNS(context.TODO(), &test.ResponseWriter{}, req)
|
|
|
|
time.Sleep(1 * time.Second)
|
|
i1 := atomic.LoadUint32(&i)
|
|
if i1 != expected {
|
|
t.Errorf("Expected number of health checks to be %d, got %d", expected, i1)
|
|
}
|
|
}
|
|
|
|
func TestHealthFailTwice(t *testing.T) {
|
|
const expected = 2
|
|
i := uint32(0)
|
|
q := uint32(0)
|
|
s := dnstest.NewServer(func(w dns.ResponseWriter, r *dns.Msg) {
|
|
if r.Question[0].Name == "." {
|
|
atomic.AddUint32(&i, 1)
|
|
i1 := atomic.LoadUint32(&i)
|
|
// Timeout health until we get the second one
|
|
if i1 < 2 {
|
|
return
|
|
}
|
|
ret := new(dns.Msg)
|
|
ret.SetReply(r)
|
|
w.WriteMsg(ret)
|
|
return
|
|
}
|
|
if atomic.LoadUint32(&q) == 0 { //drop only first query
|
|
atomic.AddUint32(&q, 1)
|
|
return
|
|
}
|
|
ret := new(dns.Msg)
|
|
ret.SetReply(r)
|
|
w.WriteMsg(ret)
|
|
})
|
|
defer s.Close()
|
|
|
|
p := NewProxy(s.Addr, DNS)
|
|
f := New()
|
|
f.SetProxy(p)
|
|
defer f.Close()
|
|
|
|
req := new(dns.Msg)
|
|
req.SetQuestion("example.org.", dns.TypeA)
|
|
|
|
f.ServeDNS(context.TODO(), &test.ResponseWriter{}, req)
|
|
|
|
time.Sleep(3 * time.Second)
|
|
i1 := atomic.LoadUint32(&i)
|
|
if i1 != expected {
|
|
t.Errorf("Expected number of health checks to be %d, got %d", expected, i1)
|
|
}
|
|
}
|
|
|
|
func TestHealthMaxFails(t *testing.T) {
|
|
s := dnstest.NewServer(func(w dns.ResponseWriter, r *dns.Msg) {
|
|
// timeout
|
|
})
|
|
defer s.Close()
|
|
|
|
p := NewProxy(s.Addr, DNS)
|
|
f := New()
|
|
f.maxfails = 2
|
|
f.SetProxy(p)
|
|
defer f.Close()
|
|
|
|
req := new(dns.Msg)
|
|
req.SetQuestion("example.org.", dns.TypeA)
|
|
|
|
f.ServeDNS(context.TODO(), &test.ResponseWriter{}, req)
|
|
|
|
time.Sleep(1 * time.Second)
|
|
if !p.Down(f.maxfails) {
|
|
t.Errorf("Expected Proxy fails to be greater than %d, got %d", f.maxfails, p.fails)
|
|
}
|
|
}
|
|
|
|
func TestHealthNoMaxFails(t *testing.T) {
|
|
const expected = 0
|
|
i := uint32(0)
|
|
s := dnstest.NewServer(func(w dns.ResponseWriter, r *dns.Msg) {
|
|
if r.Question[0].Name == "." {
|
|
// health check, answer
|
|
atomic.AddUint32(&i, 1)
|
|
ret := new(dns.Msg)
|
|
ret.SetReply(r)
|
|
w.WriteMsg(ret)
|
|
}
|
|
})
|
|
defer s.Close()
|
|
|
|
p := NewProxy(s.Addr, DNS)
|
|
f := New()
|
|
f.maxfails = 0
|
|
f.SetProxy(p)
|
|
defer f.Close()
|
|
|
|
req := new(dns.Msg)
|
|
req.SetQuestion("example.org.", dns.TypeA)
|
|
|
|
f.ServeDNS(context.TODO(), &test.ResponseWriter{}, req)
|
|
|
|
time.Sleep(1 * time.Second)
|
|
i1 := atomic.LoadUint32(&i)
|
|
if i1 != expected {
|
|
t.Errorf("Expected number of health checks to be %d, got %d", expected, i1)
|
|
}
|
|
}
|