derp: deflake test

Signed-off-by: David Crawshaw <crawshaw@tailscale.com>
reviewable/pr194/r1
David Crawshaw 4 years ago
parent 52d9613b42
commit 131541c06d

@ -9,7 +9,6 @@ import (
"context"
crand "crypto/rand"
"errors"
"expvar"
"fmt"
"io"
"net"
@ -215,10 +214,27 @@ func TestSendFreeze(t *testing.T) {
cathyKey := newPrivateKey(t)
cathyClient, cathyConn := newClient("cathy", cathyKey)
var aliceCount, bobCount, cathyCount expvar.Int
var (
aliceCh = make(chan struct{}, 32)
bobCh = make(chan struct{}, 32)
cathyCh = make(chan struct{}, 32)
)
chs := func(name string) chan struct{} {
switch name {
case "alice":
return aliceCh
case "bob":
return bobCh
case "cathy":
return cathyCh
default:
panic("unknown ch: " + name)
}
}
errCh := make(chan error, 4)
recvAndCount := func(count *expvar.Int, name string, client *Client) {
recv := func(name string, client *Client) {
ch := chs(name)
for {
b := make([]byte, 1<<9)
m, err := client.Recv(b)
@ -235,13 +251,16 @@ func TestSendFreeze(t *testing.T) {
errCh <- fmt.Errorf("%s: zero Source address in ReceivedPacket", name)
return
}
count.Add(1)
select {
case ch <- struct{}{}:
default:
}
}
}
}
go recvAndCount(&aliceCount, "alice", aliceClient)
go recvAndCount(&bobCount, "bob", bobClient)
go recvAndCount(&cathyCount, "cathy", cathyClient)
go recv("alice", aliceClient)
go recv("bob", bobClient)
go recv("cathy", cathyClient)
var cancel func()
go func() {
@ -270,38 +289,52 @@ func TestSendFreeze(t *testing.T) {
}
}()
var countSnapshot [3]int64
loadCounts := func() (adiff, bdiff, cdiff int64) {
drainAny := func(ch chan struct{}) {
// We are draining potentially infinite sources,
// so place some reasonable upper limit.
//
// The important thing here is to make sure that
// if any tokens remain in the channel, they
// must have been generated after drainAny was
// called.
for i := 0; i < cap(ch); i++ {
select {
case <-ch:
default:
return
}
}
}
drain := func(t *testing.T, name string) bool {
t.Helper()
timer := time.NewTimer(1 * time.Second)
defer timer.Stop()
atotal := aliceCount.Value()
btotal := bobCount.Value()
ctotal := cathyCount.Value()
adiff = atotal - countSnapshot[0]
bdiff = btotal - countSnapshot[1]
cdiff = ctotal - countSnapshot[2]
countSnapshot[0] = atotal
countSnapshot[1] = btotal
countSnapshot[2] = ctotal
t.Logf("count diffs: alice=%d, bob=%d, cathy=%d", adiff, bdiff, cdiff)
return adiff, bdiff, cdiff
// Ensure ch has at least one element.
ch := chs(name)
select {
case <-ch:
case <-timer.C:
t.Errorf("no packet received by %s", name)
return false
}
// Drain remaining.
drainAny(ch)
return true
}
isEmpty := func(t *testing.T, name string) {
t.Helper()
select {
case <-chs(name):
t.Errorf("packet received by %s, want none", name)
default:
}
}
t.Run("initial send", func(t *testing.T) {
time.Sleep(10 * time.Millisecond)
a, b, c := loadCounts()
if a != 0 {
t.Errorf("alice diff=%d, want 0", a)
}
if b == 0 {
t.Errorf("no bob diff, want positive value")
}
if c == 0 {
t.Errorf("no cathy diff, want positive value")
}
drain(t, "bob")
drain(t, "cathy")
isEmpty(t, "alice")
})
t.Run("block cathy", func(t *testing.T) {
@ -310,17 +343,12 @@ func TestSendFreeze(t *testing.T) {
cathyConn.SetReadBlock(true)
time.Sleep(2 * s.WriteTimeout)
a, b, _ := loadCounts()
if a != 0 {
t.Errorf("alice diff=%d, want 0", a)
}
if b == 0 {
t.Errorf("no bob diff, want positive value")
}
drain(t, "bob")
drainAny(chs("cathy"))
isEmpty(t, "alice")
// Now wait a little longer, and ensure packets still flow to bob
time.Sleep(10 * time.Millisecond)
if _, b, _ := loadCounts(); b == 0 {
if !drain(t, "bob") {
t.Errorf("connection alice->bob frozen by alice->cathy")
}
})

Loading…
Cancel
Save