Prevent timeout in TestConcurrentExchanges (#862)
This eliminates the possibility of deadlocking the handler and also simplifies the test considerably.
This commit is contained in:
parent
65b2aa0a63
commit
870a59089c
|
@ -7,7 +7,6 @@ import (
|
|||
"net"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
@ -521,17 +520,13 @@ func TestConcurrentExchanges(t *testing.T) {
|
|||
cases[0] = new(Msg)
|
||||
cases[1] = new(Msg)
|
||||
cases[1].Truncated = true
|
||||
for _, m := range cases {
|
||||
block := make(chan struct{})
|
||||
waiting := make(chan struct{})
|
||||
|
||||
for _, m := range cases {
|
||||
mm := m // redeclare m so as not to trip the race detector
|
||||
handler := func(w ResponseWriter, req *Msg) {
|
||||
r := mm.Copy()
|
||||
r.SetReply(req)
|
||||
|
||||
waiting <- struct{}{}
|
||||
<-block
|
||||
w.WriteMsg(r)
|
||||
}
|
||||
|
||||
|
@ -546,29 +541,24 @@ func TestConcurrentExchanges(t *testing.T) {
|
|||
|
||||
m := new(Msg)
|
||||
m.SetQuestion("miek.nl.", TypeSRV)
|
||||
|
||||
c := &Client{
|
||||
SingleInflight: true,
|
||||
}
|
||||
r := make([]*Msg, 2)
|
||||
// Force this client to always return the same request,
|
||||
// even though we're querying sequentially. Running the
|
||||
// Exchange calls below concurrently can fail due to
|
||||
// goroutine scheduling, but this simulates the same
|
||||
// outcome.
|
||||
c.group.dontDeleteForTesting = true
|
||||
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(len(r))
|
||||
for i := 0; i < len(r); i++ {
|
||||
go func(i int) {
|
||||
defer wg.Done()
|
||||
r := make([]*Msg, 2)
|
||||
for i := range r {
|
||||
r[i], _, _ = c.Exchange(m.Copy(), addrstr)
|
||||
if r[i] == nil {
|
||||
t.Errorf("response %d is nil", i)
|
||||
}
|
||||
}(i)
|
||||
}
|
||||
select {
|
||||
case <-waiting:
|
||||
case <-time.After(time.Second):
|
||||
t.FailNow()
|
||||
}
|
||||
close(block)
|
||||
wg.Wait()
|
||||
|
||||
if r[0] == r[1] {
|
||||
t.Errorf("got same response, expected non-shared responses")
|
||||
|
|
|
@ -23,6 +23,8 @@ type call struct {
|
|||
type singleflight struct {
|
||||
sync.Mutex // protects m
|
||||
m map[string]*call // lazily initialized
|
||||
|
||||
dontDeleteForTesting bool // this is only to be used by TestConcurrentExchanges
|
||||
}
|
||||
|
||||
// Do executes and returns the results of the given function, making
|
||||
|
@ -49,9 +51,11 @@ func (g *singleflight) Do(key string, fn func() (*Msg, time.Duration, error)) (v
|
|||
c.val, c.rtt, c.err = fn()
|
||||
c.wg.Done()
|
||||
|
||||
if !g.dontDeleteForTesting {
|
||||
g.Lock()
|
||||
delete(g.m, key)
|
||||
g.Unlock()
|
||||
}
|
||||
|
||||
return c.val, c.rtt, c.err, c.dups > 0
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue