983f5a717a
Concurrent calls to Interface methods on autodisc could return a "not discovered" error if the discovery did not finish before the call. autodisc.wait expected the done channel to carry the found Interface but it was closed instead. The fix is to use sync.Once for now, which is easier to get right. And there is a test. Finally. This will have to change again when we introduce re-discovery.
49 lines
1.1 KiB
Go
49 lines
1.1 KiB
Go
package nat
|
|
|
|
import (
|
|
"bytes"
|
|
"net"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
// This test checks that autodisc doesn't hang and returns
|
|
// consistent results when multiple goroutines call its methods
|
|
// concurrently.
|
|
func TestAutoDiscRace(t *testing.T) {
|
|
ad := startautodisc("thing", func() Interface {
|
|
time.Sleep(500 * time.Millisecond)
|
|
return extIP{33, 44, 55, 66}
|
|
})
|
|
|
|
// Spawn a few concurrent calls to ad.ExternalIP.
|
|
type rval struct {
|
|
ip net.IP
|
|
err error
|
|
}
|
|
results := make(chan rval, 50)
|
|
for i := 0; i < cap(results); i++ {
|
|
go func() {
|
|
ip, err := ad.ExternalIP()
|
|
results <- rval{ip, err}
|
|
}()
|
|
}
|
|
|
|
// Check that they all return the correct result within the deadline.
|
|
deadline := time.After(550 * time.Millisecond)
|
|
for i := 0; i < cap(results); i++ {
|
|
select {
|
|
case <-deadline:
|
|
t.Fatal("deadline exceeded")
|
|
case rval := <-results:
|
|
if rval.err != nil {
|
|
t.Errorf("result %d: unexpected error: %v", i, rval.err)
|
|
}
|
|
wantIP := net.IP{33, 44, 55, 66}
|
|
if !bytes.Equal(rval.ip, wantIP) {
|
|
t.Errorf("result %d: got IP %v, want %v", i, rval.ip, wantIP)
|
|
}
|
|
}
|
|
}
|
|
}
|