* gcc.dg/guality/guality.exp: Skip on AIX.
[official-gcc.git] / libgo / go / net / dial_test.go
blob03a0bad7a5b650f4109146ab54b0954c41d7e2be
1 // Copyright 2011 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
5 package net
7 import (
8 "flag"
9 "fmt"
10 "io"
11 "os"
12 "reflect"
13 "regexp"
14 "runtime"
15 "testing"
16 "time"
19 func newLocalListener(t *testing.T) Listener {
20 ln, err := Listen("tcp", "127.0.0.1:0")
21 if err != nil {
22 ln, err = Listen("tcp6", "[::1]:0")
24 if err != nil {
25 t.Fatal(err)
27 return ln
30 func TestDialTimeout(t *testing.T) {
31 origBacklog := listenerBacklog
32 defer func() {
33 listenerBacklog = origBacklog
34 }()
35 listenerBacklog = 1
37 ln := newLocalListener(t)
38 defer ln.Close()
40 errc := make(chan error)
42 numConns := listenerBacklog + 100
44 // TODO(bradfitz): It's hard to test this in a portable
45 // way. This is unfortunate, but works for now.
46 switch runtime.GOOS {
47 case "linux":
48 // The kernel will start accepting TCP connections before userspace
49 // gets a chance to not accept them, so fire off a bunch to fill up
50 // the kernel's backlog. Then we test we get a failure after that.
51 for i := 0; i < numConns; i++ {
52 go func() {
53 _, err := DialTimeout("tcp", ln.Addr().String(), 200*time.Millisecond)
54 errc <- err
55 }()
57 case "darwin", "windows":
58 // At least OS X 10.7 seems to accept any number of
59 // connections, ignoring listen's backlog, so resort
60 // to connecting to a hopefully-dead 127/8 address.
61 // Same for windows.
63 // Use an IANA reserved port (49151) instead of 80, because
64 // on our 386 builder, this Dial succeeds, connecting
65 // to an IIS web server somewhere. The data center
66 // or VM or firewall must be stealing the TCP connection.
68 // IANA Service Name and Transport Protocol Port Number Registry
69 // <http://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xml>
70 go func() {
71 c, err := DialTimeout("tcp", "127.0.71.111:49151", 200*time.Millisecond)
72 if err == nil {
73 err = fmt.Errorf("unexpected: connected to %s!", c.RemoteAddr())
74 c.Close()
76 errc <- err
77 }()
78 default:
79 // TODO(bradfitz):
80 // OpenBSD may have a reject route to 127/8 except 127.0.0.1/32
81 // by default. FreeBSD likely works, but is untested.
82 // TODO(rsc):
83 // The timeout never happens on Windows. Why? Issue 3016.
84 t.Skipf("skipping test on %q; untested.", runtime.GOOS)
87 connected := 0
88 for {
89 select {
90 case <-time.After(15 * time.Second):
91 t.Fatal("too slow")
92 case err := <-errc:
93 if err == nil {
94 connected++
95 if connected == numConns {
96 t.Fatal("all connections connected; expected some to time out")
98 } else {
99 terr, ok := err.(timeout)
100 if !ok {
101 t.Fatalf("got error %q; want error with timeout interface", err)
103 if !terr.Timeout() {
104 t.Fatalf("got error %q; not a timeout", err)
106 // Pass. We saw a timeout error.
107 return
113 func TestSelfConnect(t *testing.T) {
114 if runtime.GOOS == "windows" {
115 // TODO(brainman): do not know why it hangs.
116 t.Skip("skipping known-broken test on windows")
118 // Test that Dial does not honor self-connects.
119 // See the comment in DialTCP.
121 // Find a port that would be used as a local address.
122 l, err := Listen("tcp", "127.0.0.1:0")
123 if err != nil {
124 t.Fatal(err)
126 c, err := Dial("tcp", l.Addr().String())
127 if err != nil {
128 t.Fatal(err)
130 addr := c.LocalAddr().String()
131 c.Close()
132 l.Close()
134 // Try to connect to that address repeatedly.
135 n := 100000
136 if testing.Short() {
137 n = 1000
139 switch runtime.GOOS {
140 case "darwin", "freebsd", "netbsd", "openbsd", "plan9", "solaris", "windows":
141 // Non-Linux systems take a long time to figure
142 // out that there is nothing listening on localhost.
143 n = 100
145 for i := 0; i < n; i++ {
146 c, err := Dial("tcp", addr)
147 if err == nil {
148 c.Close()
149 t.Errorf("#%d: Dial %q succeeded", i, addr)
154 var runErrorTest = flag.Bool("run_error_test", false, "let TestDialError check for dns errors")
156 type DialErrorTest struct {
157 Net string
158 Raddr string
159 Pattern string
162 var dialErrorTests = []DialErrorTest{
164 "datakit", "mh/astro/r70",
165 "dial datakit mh/astro/r70: unknown network datakit",
168 "tcp", "127.0.0.1:☺",
169 "dial tcp 127.0.0.1:☺: unknown port tcp/☺",
172 "tcp", "no-such-name.google.com.:80",
173 "dial tcp no-such-name.google.com.:80: lookup no-such-name.google.com.( on .*)?: no (.*)",
176 "tcp", "no-such-name.no-such-top-level-domain.:80",
177 "dial tcp no-such-name.no-such-top-level-domain.:80: lookup no-such-name.no-such-top-level-domain.( on .*)?: no (.*)",
180 "tcp", "no-such-name:80",
181 `dial tcp no-such-name:80: lookup no-such-name\.(.*\.)?( on .*)?: no (.*)`,
184 "tcp", "mh/astro/r70:http",
185 "dial tcp mh/astro/r70:http: lookup mh/astro/r70: invalid domain name",
188 "unix", "/etc/file-not-found",
189 "dial unix /etc/file-not-found: no such file or directory",
192 "unix", "/etc/",
193 "dial unix /etc/: (permission denied|socket operation on non-socket|connection refused)",
196 "unixpacket", "/etc/file-not-found",
197 "dial unixpacket /etc/file-not-found: no such file or directory",
200 "unixpacket", "/etc/",
201 "dial unixpacket /etc/: (permission denied|socket operation on non-socket|connection refused)",
205 var duplicateErrorPattern = `dial (.*) dial (.*)`
207 func TestDialError(t *testing.T) {
208 if !*runErrorTest {
209 t.Logf("test disabled; use -run_error_test to enable")
210 return
212 for i, tt := range dialErrorTests {
213 c, err := Dial(tt.Net, tt.Raddr)
214 if c != nil {
215 c.Close()
217 if err == nil {
218 t.Errorf("#%d: nil error, want match for %#q", i, tt.Pattern)
219 continue
221 s := err.Error()
222 match, _ := regexp.MatchString(tt.Pattern, s)
223 if !match {
224 t.Errorf("#%d: %q, want match for %#q", i, s, tt.Pattern)
226 match, _ = regexp.MatchString(duplicateErrorPattern, s)
227 if match {
228 t.Errorf("#%d: %q, duplicate error return from Dial", i, s)
233 var invalidDialAndListenArgTests = []struct {
234 net string
235 addr string
236 err error
238 {"foo", "bar", &OpError{Op: "dial", Net: "foo", Addr: nil, Err: UnknownNetworkError("foo")}},
239 {"baz", "", &OpError{Op: "listen", Net: "baz", Addr: nil, Err: UnknownNetworkError("baz")}},
240 {"tcp", "", &OpError{Op: "dial", Net: "tcp", Addr: nil, Err: errMissingAddress}},
243 func TestInvalidDialAndListenArgs(t *testing.T) {
244 for _, tt := range invalidDialAndListenArgTests {
245 var err error
246 switch tt.err.(*OpError).Op {
247 case "dial":
248 _, err = Dial(tt.net, tt.addr)
249 case "listen":
250 _, err = Listen(tt.net, tt.addr)
252 if !reflect.DeepEqual(tt.err, err) {
253 t.Fatalf("got %#v; expected %#v", err, tt.err)
258 func TestDialTimeoutFDLeak(t *testing.T) {
259 if runtime.GOOS != "linux" {
260 // TODO(bradfitz): test on other platforms
261 t.Skipf("skipping test on %q", runtime.GOOS)
264 ln := newLocalListener(t)
265 defer ln.Close()
267 type connErr struct {
268 conn Conn
269 err error
271 dials := listenerBacklog + 100
272 // used to be listenerBacklog + 5, but was found to be unreliable, issue 4384.
273 maxGoodConnect := listenerBacklog + runtime.NumCPU()*10
274 resc := make(chan connErr)
275 for i := 0; i < dials; i++ {
276 go func() {
277 conn, err := DialTimeout("tcp", ln.Addr().String(), 500*time.Millisecond)
278 resc <- connErr{conn, err}
282 var firstErr string
283 var ngood int
284 var toClose []io.Closer
285 for i := 0; i < dials; i++ {
286 ce := <-resc
287 if ce.err == nil {
288 ngood++
289 if ngood > maxGoodConnect {
290 t.Errorf("%d good connects; expected at most %d", ngood, maxGoodConnect)
292 toClose = append(toClose, ce.conn)
293 continue
295 err := ce.err
296 if firstErr == "" {
297 firstErr = err.Error()
298 } else if err.Error() != firstErr {
299 t.Fatalf("inconsistent error messages: first was %q, then later %q", firstErr, err)
302 for _, c := range toClose {
303 c.Close()
305 for i := 0; i < 100; i++ {
306 if got := numFD(); got < dials {
307 // Test passes.
308 return
310 time.Sleep(10 * time.Millisecond)
312 if got := numFD(); got >= dials {
313 t.Errorf("num fds after %d timeouts = %d; want <%d", dials, got, dials)
317 func numFD() int {
318 if runtime.GOOS == "linux" {
319 f, err := os.Open("/proc/self/fd")
320 if err != nil {
321 panic(err)
323 defer f.Close()
324 names, err := f.Readdirnames(0)
325 if err != nil {
326 panic(err)
328 return len(names)
330 // All tests using this should be skipped anyway, but:
331 panic("numFDs not implemented on " + runtime.GOOS)
334 var testPoller = flag.Bool("poller", false, "platform supports runtime-integrated poller")
336 // Assert that a failed Dial attempt does not leak
337 // runtime.PollDesc structures
338 func TestDialFailPDLeak(t *testing.T) {
339 if !*testPoller {
340 t.Skip("test disabled; use -poller to enable")
343 const loops = 10
344 const count = 20000
345 var old runtime.MemStats // used by sysdelta
346 runtime.ReadMemStats(&old)
347 sysdelta := func() uint64 {
348 var new runtime.MemStats
349 runtime.ReadMemStats(&new)
350 delta := old.Sys - new.Sys
351 old = new
352 return delta
354 d := &Dialer{Timeout: time.Nanosecond} // don't bother TCP with handshaking
355 failcount := 0
356 for i := 0; i < loops; i++ {
357 for i := 0; i < count; i++ {
358 conn, err := d.Dial("tcp", "127.0.0.1:1")
359 if err == nil {
360 t.Error("dial should not succeed")
361 conn.Close()
362 t.FailNow()
365 if delta := sysdelta(); delta > 0 {
366 failcount++
368 // there are always some allocations on the first loop
369 if failcount > 3 {
370 t.Error("detected possible memory leak in runtime")
371 t.FailNow()
376 func TestDialer(t *testing.T) {
377 ln, err := Listen("tcp4", "127.0.0.1:0")
378 if err != nil {
379 t.Fatalf("Listen failed: %v", err)
381 defer ln.Close()
382 ch := make(chan error, 1)
383 go func() {
384 var err error
385 c, err := ln.Accept()
386 if err != nil {
387 ch <- fmt.Errorf("Accept failed: %v", err)
388 return
390 defer c.Close()
391 ch <- nil
394 laddr, err := ResolveTCPAddr("tcp4", "127.0.0.1:0")
395 if err != nil {
396 t.Fatalf("ResolveTCPAddr failed: %v", err)
398 d := &Dialer{LocalAddr: laddr}
399 c, err := d.Dial("tcp4", ln.Addr().String())
400 if err != nil {
401 t.Fatalf("Dial failed: %v", err)
403 defer c.Close()
404 c.Read(make([]byte, 1))
405 err = <-ch
406 if err != nil {
407 t.Error(err)