|
|
@@ -0,0 +1,48 @@
|
|
|
+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)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|