Merge pull request #113 from asergeyev/master

No timeouts in tests
This commit is contained in:
Miek Gieben 2014-08-30 07:19:21 +01:00
commit a2ad8f8ac5
4 changed files with 182 additions and 108 deletions

View File

@ -133,4 +133,3 @@ Example programs can be found in the `github.com/miekg/exdns` repository.
* CAA parsing is broken;
* Replies with TC bit are not parsed to the end.
* SIG(0)
* Make tests run faster by removing the time.Sleep()s

View File

@ -9,27 +9,25 @@ import (
"time"
)
func newTestServer(t *testing.T) {
// Defined in server_test.go
func TestClientSync(t *testing.T) {
HandleFunc("miek.nl.", HelloServer)
HandleFunc("example.com.", AnotherHelloServer)
go func() {
err := ListenAndServe(":8063", "udp", nil)
if err != nil {
t.Log("ListenAndServe: ", err.Error())
t.Fatal()
}
}()
time.Sleep(4e8)
}
func TestClientSync(t *testing.T) {
s, addrstr, err := RunLocalUDPServer("127.0.0.1:0")
if err != nil {
t.Fatalf("Unable to run test server: %s", err)
}
defer s.Shutdown()
m := new(Msg)
m.SetQuestion("miek.nl.", TypeSOA)
c := new(Client)
r, _, _ := c.Exchange(m, "127.0.0.1:6053")
r, _, e := c.Exchange(m, addrstr)
if e != nil {
t.Logf("failed to exchange: %s", e.Error())
t.Fail()
}
if r != nil && r.Rcode != RcodeSuccess {
t.Log("failed to get an valid answer")
t.Fail()
@ -38,13 +36,26 @@ func TestClientSync(t *testing.T) {
}
func TestClientEDNS0(t *testing.T) {
HandleFunc("miek.nl.", HelloServer)
HandleFunc("example.com.", AnotherHelloServer)
s, addrstr, err := RunLocalUDPServer("127.0.0.1:0")
if err != nil {
t.Fatalf("Unable to run test server: %s", err)
}
defer s.Shutdown()
m := new(Msg)
m.SetQuestion("miek.nl.", TypeDNSKEY)
m.SetEdns0(2048, true)
c := new(Client)
r, _, _ := c.Exchange(m, "127.0.0.1:6053")
r, _, e := c.Exchange(m, addrstr)
if e != nil {
t.Logf("failed to exchange: %s", e.Error())
t.Fail()
}
if r != nil && r.Rcode != RcodeSuccess {
t.Log("failed to get an valid answer")
@ -54,6 +65,15 @@ func TestClientEDNS0(t *testing.T) {
}
func TestSingleSingleInflight(t *testing.T) {
HandleFunc("miek.nl.", HelloServer)
HandleFunc("example.com.", AnotherHelloServer)
s, addrstr, err := RunLocalUDPServer("127.0.0.1:0")
if err != nil {
t.Fatalf("Unable to run test server: %s", err)
}
defer s.Shutdown()
m := new(Msg)
m.SetQuestion("miek.nl.", TypeDNSKEY)
@ -63,7 +83,7 @@ func TestSingleSingleInflight(t *testing.T) {
ch := make(chan time.Duration)
for i := 0; i < nr; i++ {
go func() {
_, rtt, _ := c.Exchange(m, "127.0.0.1:6053")
_, rtt, _ := c.Exchange(m, addrstr)
ch <- rtt
}()
}

View File

@ -302,20 +302,54 @@ func (srv *Server) ActivateAndServe() error {
// Shutdown gracefully shuts down a server. After a call to Shutdown, ListenAndServe and
// ActivateAndServe will return. All in progress queries are completed before the server
// is taken down. If the Shutdown was not succesful an error is returned.
// is taken down. If the Shutdown was not succesful an error is taking longer than reading
// timeout.
func (srv *Server) Shutdown() error {
// TODO(miek): does this work with socket activation? Double check if we set the
// address there. And... is it needed?
c := new(Client)
c.Net = srv.Net
switch srv.Net {
case "tcp", "tcp4", "tcp6":
go func() { srv.stopTCP <- true }()
case "udp", "udp4", "udp6":
go func() { srv.stopUDP <- true }()
net, addr := srv.Net, srv.Addr
switch {
case srv.Listener != nil:
a := srv.Listener.Addr()
net, addr = a.Network(), a.String()
case srv.PacketConn != nil:
a := srv.PacketConn.LocalAddr()
net, addr = a.Network(), a.String()
}
c.Exchange(new(Msg), srv.Addr)
return nil
fin := make(chan bool)
switch net {
case "tcp", "tcp4", "tcp6":
go func() {
srv.stopTCP <- true
srv.wgTCP.Wait()
fin <- true
}()
case "udp", "udp4", "udp6":
go func() {
srv.stopUDP <- true
srv.wgUDP.Wait()
fin <- true
}()
}
c := &Client{Net: net}
go c.Exchange(new(Msg), addr) // extra query to help ReadXXX loop to pass
select {
case <-time.After(srv.getReadTimeout()):
return &Error{err: "server shutdown is pending"}
case <-fin:
return nil
}
}
// getReadTimeout is a helper func to use system timeout if server did not intend to change it.
func (srv *Server) getReadTimeout() time.Duration {
rtimeout := dnsTimeout
if srv.ReadTimeout != 0 {
rtimeout = srv.ReadTimeout
}
return rtimeout
}
// serveTCP starts a TCP listener for the server.
@ -326,23 +360,19 @@ func (srv *Server) serveTCP(l *net.TCPListener) error {
if handler == nil {
handler = DefaultServeMux
}
rtimeout := dnsTimeout
if srv.ReadTimeout != 0 {
rtimeout = srv.ReadTimeout
}
rtimeout := srv.getReadTimeout()
// deadline is not used here
for {
rw, e := l.AcceptTCP()
select {
case <-srv.stopTCP:
// Asked to shutdown
srv.wgTCP.Wait()
return nil
default:
}
if e != nil {
continue
}
m, e := srv.readTCP(rw, rtimeout)
select {
case <-srv.stopTCP:
return nil
default:
}
if e != nil {
continue
}
@ -356,21 +386,17 @@ func (srv *Server) serveTCP(l *net.TCPListener) error {
// Each request is handled in a seperate goroutine.
func (srv *Server) serveUDP(l *net.UDPConn) error {
defer l.Close()
handler := srv.Handler
if handler == nil {
handler = DefaultServeMux
}
rtimeout := dnsTimeout
if srv.ReadTimeout != 0 {
rtimeout = srv.ReadTimeout
}
rtimeout := srv.getReadTimeout()
// deadline is not used here
for {
m, s, e := srv.readUDP(l, rtimeout)
select {
case <-srv.stopUDP:
// Asked to shutdown
srv.wgUDP.Wait()
return nil
default:
}

View File

@ -10,7 +10,6 @@ import (
"runtime"
"sync"
"testing"
"time"
)
func HelloServer(w ResponseWriter, req *Msg) {
@ -31,21 +30,54 @@ func AnotherHelloServer(w ResponseWriter, req *Msg) {
w.WriteMsg(m)
}
func RunLocalUDPServer(laddr string) (*Server, string, error) {
pc, err := net.ListenPacket("udp", laddr)
if err != nil {
return nil, "", err
}
server := &Server{PacketConn: pc}
go func() {
server.ActivateAndServe()
pc.Close()
}()
// in order to let all Server internals to finish before test will touch
// server's internal fields, we need to cycle thru other goroutinges for
// one more time
runtime.Gosched()
return server, pc.LocalAddr().String(), nil
}
func RunLocalTCPServer(laddr string) (*Server, string, error) {
l, err := net.Listen("tcp", laddr)
if err != nil {
return nil, "", err
}
server := &Server{Listener: l}
go func() {
server.ActivateAndServe()
l.Close()
}()
// in order to let all Server internals to finish before test will touch
// server's internal fields, we need to cycle thru other goroutinges for
// one more time
runtime.Gosched()
return server, l.Addr().String(), nil
}
func TestServing(t *testing.T) {
HandleFunc("miek.nl.", HelloServer)
HandleFunc("example.com.", AnotherHelloServer)
go func() {
err := ListenAndServe(":8053", "udp", nil)
if err != nil {
t.Log("ListenAndServe: ", err.Error())
t.Fatal()
}
}()
time.Sleep(4e8)
s, addrstr, err := RunLocalUDPServer("127.0.0.1:0")
if err != nil {
t.Fatalf("Unable to run test server: %s", err)
}
defer s.Shutdown()
c := new(Client)
m := new(Msg)
m.SetQuestion("miek.nl.", TypeTXT)
r, _, err := c.Exchange(m, "127.0.0.1:8053")
r, _, err := c.Exchange(m, addrstr)
if err != nil {
t.Log("failed to exchange miek.nl", err)
t.Fatal()
@ -57,7 +89,7 @@ func TestServing(t *testing.T) {
}
m.SetQuestion("example.com.", TypeTXT)
r, _, err = c.Exchange(m, "127.0.0.1:8053")
r, _, err = c.Exchange(m, addrstr)
if err != nil {
t.Log("failed to exchange example.com", err)
t.Fatal()
@ -70,7 +102,7 @@ func TestServing(t *testing.T) {
// Test Mixes cased as noticed by Ask.
m.SetQuestion("eXaMplE.cOm.", TypeTXT)
r, _, err = c.Exchange(m, "127.0.0.1:8053")
r, _, err = c.Exchange(m, addrstr)
if err != nil {
t.Log("failed to exchange eXaMplE.cOm", err)
t.Fail()
@ -86,16 +118,20 @@ func BenchmarkServe(b *testing.B) {
b.StopTimer()
HandleFunc("miek.nl.", HelloServer)
a := runtime.GOMAXPROCS(4)
go func() {
ListenAndServe("127.0.0.1:8053", "udp", nil)
}()
s, addrstr, err := RunLocalUDPServer("127.0.0.1:0")
if err != nil {
b.Fatalf("Unable to run test server: %s", err)
}
defer s.Shutdown()
c := new(Client)
m := new(Msg)
m.SetQuestion("miek.nl", TypeSOA)
b.StartTimer()
for i := 0; i < b.N; i++ {
c.Exchange(m, "127.0.0.1:8053")
c.Exchange(m, addrstr)
}
runtime.GOMAXPROCS(a)
}
@ -104,16 +140,19 @@ func benchmarkServe6(b *testing.B) {
b.StopTimer()
HandleFunc("miek.nl.", HelloServer)
a := runtime.GOMAXPROCS(4)
go func() {
ListenAndServe("[::1]:8053", "udp", nil)
}()
s, addrstr, err := RunLocalUDPServer("[::1]:0")
if err != nil {
b.Fatalf("Unable to run test server: %s", err)
}
defer s.Shutdown()
c := new(Client)
m := new(Msg)
m.SetQuestion("miek.nl", TypeSOA)
b.StartTimer()
for i := 0; i < b.N; i++ {
c.Exchange(m, "[::1]:8053")
c.Exchange(m, addrstr)
}
runtime.GOMAXPROCS(a)
}
@ -131,16 +170,18 @@ func BenchmarkServeCompress(b *testing.B) {
b.StopTimer()
HandleFunc("miek.nl.", HelloServerCompress)
a := runtime.GOMAXPROCS(4)
go func() {
ListenAndServe("127.0.0.1:8053", "udp", nil)
}()
s, addrstr, err := RunLocalUDPServer("127.0.0.1:0")
if err != nil {
b.Fatalf("Unable to run test server: %s", err)
}
defer s.Shutdown()
c := new(Client)
m := new(Msg)
m.SetQuestion("miek.nl", TypeSOA)
b.StartTimer()
for i := 0; i < b.N; i++ {
c.Exchange(m, "127.0.0.1:8053")
c.Exchange(m, addrstr)
}
runtime.GOMAXPROCS(a)
}
@ -227,19 +268,13 @@ func HelloServerLargeResponse(resp ResponseWriter, req *Msg) {
}
func TestServingLargeResponses(t *testing.T) {
mux := NewServeMux()
mux.HandleFunc("example.", HelloServerLargeResponse)
HandleFunc("example.", HelloServerLargeResponse)
server := &Server{
Addr: "127.0.0.1:10000",
Net: "udp",
Handler: mux,
s, addrstr, err := RunLocalUDPServer("127.0.0.1:0")
if err != nil {
t.Fatalf("Unable to run test server: %s", err)
}
go func() {
server.ListenAndServe()
}()
time.Sleep(50 * time.Millisecond)
defer s.Shutdown()
// Create request
m := new(Msg)
@ -250,7 +285,7 @@ func TestServingLargeResponses(t *testing.T) {
M.Lock()
M.max = 2
M.Unlock()
_, _, err := c.Exchange(m, "127.0.0.1:10000")
_, _, err = c.Exchange(m, addrstr)
if err != nil {
t.Logf("failed to exchange: %s", err.Error())
t.Fail()
@ -259,14 +294,14 @@ func TestServingLargeResponses(t *testing.T) {
M.Lock()
M.max = 20
M.Unlock()
_, _, err = c.Exchange(m, "127.0.0.1:10000")
_, _, err = c.Exchange(m, addrstr)
if err == nil {
t.Logf("failed to fail exchange, this should generate packet error")
t.Fail()
}
// But this must work again
c.UDPSize = 7000
_, _, err = c.Exchange(m, "127.0.0.1:10000")
_, _, err = c.Exchange(m, addrstr)
if err != nil {
t.Logf("failed to exchange: %s", err.Error())
t.Fail()
@ -275,32 +310,26 @@ func TestServingLargeResponses(t *testing.T) {
// TODO(miek): These tests should actually fail when the server does
// not shut down.
// (asergeyev) I put err check logic which is not yet in use but IMO
// this test will not change as shutdown internals improve.
func TestShutdownTCP(t *testing.T) {
server := Server{Addr: ":8055", Net: "tcp"}
go func() {
err := server.ListenAndServe()
if err != nil {
t.Logf("failed to setup the tcp server: %s\n", err.Error())
t.Fail()
}
t.Logf("successfully stopped the tcp server")
}()
time.Sleep(4e8)
server.Shutdown()
time.Sleep(1e9)
s, _, err := RunLocalTCPServer("127.0.0.1:0")
if err != nil {
t.Fatalf("Unable to run test server: %s", err)
}
err = s.Shutdown()
if err != nil {
t.Errorf("Could not shutdown test TCP server, %s", err)
}
}
func TestShutdownUDP(t *testing.T) {
server := Server{Addr: ":8054", Net: "udp"}
go func() {
err := server.ListenAndServe()
if err != nil {
t.Logf("failed to setup the udp server: %s\n", err.Error())
t.Fail()
}
t.Logf("successfully stopped the udp server")
}()
time.Sleep(4e8)
server.Shutdown()
time.Sleep(1e9)
s, _, err := RunLocalUDPServer("127.0.0.1:0")
if err != nil {
t.Fatalf("Unable to run test server: %s", err)
}
err = s.Shutdown()
if err != nil {
t.Errorf("Could not shutdown test UDP server, %s", err)
}
}