github.com/m3db/m3@v1.5.1-0.20231129193456-75a402aa583b/src/x/server/server_test.go (about) 1 // Copyright (c) 2017 Uber Technologies, Inc. 2 // 3 // Permission is hereby granted, free of charge, to any person obtaining a copy 4 // of this software and associated documentation files (the "Software"), to deal 5 // in the Software without restriction, including without limitation the rights 6 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 // copies of the Software, and to permit persons to whom the Software is 8 // furnished to do so, subject to the following conditions: 9 // 10 // The above copyright notice and this permission notice shall be included in 11 // all copies or substantial portions of the Software. 12 // 13 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 // THE SOFTWARE. 20 21 package server 22 23 import ( 24 "fmt" 25 "net" 26 "sort" 27 "sync" 28 "sync/atomic" 29 "testing" 30 "time" 31 32 "github.com/m3db/m3/src/x/retry" 33 34 "github.com/stretchr/testify/require" 35 ) 36 37 const ( 38 testListenAddress = "127.0.0.1:0" 39 ) 40 41 // nolint: unparam 42 func testServer(addr string) (*server, *mockHandler, *int32, *int32) { 43 var ( 44 numAdded int32 45 numRemoved int32 46 ) 47 48 opts := NewOptions().SetRetryOptions(retry.NewOptions().SetMaxRetries(2)) 49 opts = opts.SetInstrumentOptions(opts.InstrumentOptions().SetReportInterval(time.Second)) 50 51 h := newMockHandler() 52 s := NewServer(addr, h, opts).(*server) 53 54 s.addConnectionFn = func(conn net.Conn) bool { 55 atomic.AddInt32(&numAdded, 1) 56 ret := s.addConnection(conn) 57 return ret 58 } 59 60 s.removeConnectionFn = func(conn net.Conn) { 61 atomic.AddInt32(&numRemoved, 1) 62 s.removeConnection(conn) 63 } 64 65 return s, h, &numAdded, &numRemoved 66 } 67 68 func TestServerListenAndClose(t *testing.T) { 69 s, h, numAdded, numRemoved := testServer(testListenAddress) 70 71 var ( 72 numClients = 9 73 expectedRes []string 74 ) 75 76 err := s.ListenAndServe() 77 require.NoError(t, err) 78 listenAddr := s.listener.Addr().String() 79 80 for i := 0; i < numClients; i++ { 81 conn, err := net.Dial("tcp", listenAddr) 82 require.NoError(t, err) 83 84 msg := fmt.Sprintf("msg%d", i) 85 expectedRes = append(expectedRes, msg) 86 87 _, err = conn.Write([]byte(msg)) 88 require.NoError(t, err) 89 } 90 91 for h.called() < numClients { 92 time.Sleep(100 * time.Millisecond) 93 } 94 95 require.False(t, h.isClosed()) 96 97 s.Close() 98 99 require.True(t, h.isClosed()) 100 require.Equal(t, int32(numClients), atomic.LoadInt32(numAdded)) 101 require.Equal(t, int32(numClients), atomic.LoadInt32(numRemoved)) 102 require.Equal(t, numClients, h.called()) 103 require.Equal(t, expectedRes, h.res()) 104 } 105 106 func TestServe(t *testing.T) { 107 s, _, _, _ := testServer(testListenAddress) 108 109 l, err := net.Listen("tcp", testListenAddress) 110 require.NoError(t, err) 111 112 err = s.Serve(l) 113 require.NoError(t, err) 114 require.Equal(t, l, s.listener) 115 require.Equal(t, l.Addr().String(), s.address) 116 117 s.Close() 118 } 119 120 type mockHandler struct { 121 sync.Mutex 122 123 n int 124 closed bool 125 received []string 126 } 127 128 func newMockHandler() *mockHandler { return &mockHandler{} } 129 130 func (h *mockHandler) Handle(conn net.Conn) { 131 h.Lock() 132 b := make([]byte, 16) 133 134 n, _ := conn.Read(b) 135 h.n++ 136 h.received = append(h.received, string(b[:n])) 137 h.Unlock() 138 } 139 140 func (h *mockHandler) Close() { 141 h.Lock() 142 h.closed = true 143 h.Unlock() 144 } 145 146 func (h *mockHandler) isClosed() bool { 147 h.Lock() 148 defer h.Unlock() 149 150 return h.closed 151 } 152 153 func (h *mockHandler) called() int { 154 h.Lock() 155 defer h.Unlock() 156 157 return h.n 158 } 159 160 func (h *mockHandler) res() []string { 161 h.Lock() 162 defer h.Unlock() 163 164 sort.Strings(h.received) 165 return h.received 166 }