github.com/go-board/x-go@v0.1.2-0.20220610024734-db1323f6cb15/xnet/limited_test.go (about) 1 // Copyright 2013 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. 4 5 package xnet 6 7 import ( 8 "errors" 9 "fmt" 10 "io" 11 "io/ioutil" 12 "net" 13 "net/http" 14 "sync" 15 "sync/atomic" 16 "testing" 17 "time" 18 ) 19 20 const defaultMaxOpenFiles = 256 21 22 func TestLimitListener(t *testing.T) { 23 const max = 5 24 attempts := (maxOpenFiles() - max) / 2 25 if attempts > 256 { // maximum length of accept queue is 128 by default 26 attempts = 256 27 } 28 29 l, err := net.Listen("tcp", "127.0.0.1:0") 30 if err != nil { 31 t.Fatal(err) 32 } 33 defer l.Close() 34 l = LimitedListener(l, max) 35 36 var open int32 37 go http.Serve(l, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 38 if n := atomic.AddInt32(&open, 1); n > max { 39 t.Errorf("%d open connections, want <= %d", n, max) 40 } 41 defer atomic.AddInt32(&open, -1) 42 time.Sleep(10 * time.Millisecond) 43 fmt.Fprint(w, "some body") 44 })) 45 46 var wg sync.WaitGroup 47 var failed int32 48 for i := 0; i < attempts; i++ { 49 wg.Add(1) 50 go func() { 51 defer wg.Done() 52 c := http.Client{Timeout: 3 * time.Second} 53 r, err := c.Get("http://" + l.Addr().String()) 54 if err != nil { 55 t.Log(err) 56 atomic.AddInt32(&failed, 1) 57 return 58 } 59 defer r.Body.Close() 60 io.Copy(ioutil.Discard, r.Body) 61 }() 62 } 63 wg.Wait() 64 65 // We expect some Gets to fail as the kernel's accept queue is filled, 66 // but most should succeed. 67 if int(failed) >= attempts/2 { 68 t.Errorf("%d requests failed within %d attempts", failed, attempts) 69 } 70 } 71 72 type errorListener struct { 73 net.Listener 74 } 75 76 func (errorListener) Accept() (net.Conn, error) { 77 return nil, errFake 78 } 79 80 var errFake = errors.New("fake error from errorListener") 81 82 // This used to hang. 83 func TestLimitListenerError(t *testing.T) { 84 donec := make(chan bool, 1) 85 go func() { 86 const n = 2 87 ll := LimitedListener(errorListener{}, n) 88 for i := 0; i < n+1; i++ { 89 _, err := ll.Accept() 90 if err != errFake { 91 t.Fatalf("Accept error = %v; want errFake", err) 92 } 93 } 94 donec <- true 95 }() 96 select { 97 case <-donec: 98 case <-time.After(5 * time.Second): 99 t.Fatal("timeout. deadlock?") 100 } 101 } 102 103 func TestLimitListenerClose(t *testing.T) { 104 ln, err := net.Listen("tcp", "127.0.0.1:0") 105 if err != nil { 106 t.Fatal(err) 107 } 108 defer ln.Close() 109 ln = LimitedListener(ln, 1) 110 111 doneCh := make(chan struct{}) 112 defer close(doneCh) 113 go func() { 114 c, err := net.Dial("tcp", ln.Addr().String()) 115 if err != nil { 116 t.Fatal(err) 117 } 118 defer c.Close() 119 <-doneCh 120 }() 121 122 c, err := ln.Accept() 123 if err != nil { 124 t.Fatal(err) 125 } 126 defer c.Close() 127 128 acceptDone := make(chan struct{}) 129 go func() { 130 c, err := ln.Accept() 131 if err == nil { 132 c.Close() 133 t.Errorf("Unexpected successful Accept()") 134 } 135 close(acceptDone) 136 }() 137 138 // Wait a tiny bit to ensure the Accept() is blocking. 139 time.Sleep(10 * time.Millisecond) 140 ln.Close() 141 142 select { 143 case <-acceptDone: 144 case <-time.After(5 * time.Second): 145 t.Fatalf("Accept() still blocking") 146 } 147 }