github.com/cmd-stream/base-go@v0.0.0-20230813145615-dd6ac24c16f5/server/conn_receiver_test.go (about) 1 package server 2 3 import ( 4 "errors" 5 "fmt" 6 "net" 7 "testing" 8 "time" 9 10 "github.com/cmd-stream/base-go/testdata/mock" 11 "github.com/ymz-ncnk/mok" 12 ) 13 14 func TestConnReceiver(t *testing.T) { 15 16 t.Run("Conf.FirstConnTimeout should be applied only to the first conn + if Listener.SetDeadline failed with an error, Run should return it", 17 func(t *testing.T) { 18 var ( 19 wantErr = errors.New("SetDeadline error") 20 startTime = time.Now() 21 conf = ConnReceiverConf{FirstConnTimeout: time.Second} 22 listener = mock.NewListener().RegisterSetDeadline( 23 func(deadline time.Time) (err error) { 24 wantDeadline := startTime.Add(conf.FirstConnTimeout) 25 if !SameTime(deadline, wantDeadline) { 26 return fmt.Errorf("unexpected deadline, want '%v' actual '%v'", 27 wantDeadline, 28 deadline) 29 } 30 return wantErr 31 }, 32 ) 33 mocks = []*mok.Mock{listener.Mock} 34 receiver = NewConnReceiver(conf, listener, make(chan net.Conn)) 35 ) 36 testConnReceiver(receiver, wantErr, mocks, t) 37 }) 38 39 t.Run("If accepting of the first conn failed with an error, Run should return it", 40 func(t *testing.T) { 41 var ( 42 wantErr = errors.New("accept error") 43 listener = mock.NewListener().RegisterAccept( 44 func() (net.Conn, error) { return nil, wantErr }, 45 ) 46 conns = make(chan net.Conn) 47 mocks = []*mok.Mock{listener.Mock} 48 receiver = NewConnReceiver(ConnReceiverConf{}, listener, conns) 49 ) 50 testConnReceiver(receiver, wantErr, mocks, t) 51 }) 52 53 t.Run("Conf.FirstConnTimeout should be applied to only first conn + if cancelation of the first conn deadline failed with an error, Run should return it", 54 func(t *testing.T) { 55 var ( 56 wantErr = errors.New("set deadline error") 57 wantConn = mock.NewConn().RegisterClose( 58 func() (err error) { return nil }, 59 ) 60 startTime = time.Now() 61 conf = ConnReceiverConf{FirstConnTimeout: time.Second} 62 listener = mock.NewListener().RegisterSetDeadline( 63 func(deadline time.Time) (err error) { 64 wantDeadline := startTime.Add(conf.FirstConnTimeout) 65 if !SameTime(deadline, wantDeadline) { 66 return fmt.Errorf("unexpected deadline, want '%v' actual '%v'", 67 wantDeadline, 68 deadline) 69 } 70 return 71 }, 72 ).RegisterAccept( 73 func() (conn net.Conn, err error) { 74 return wantConn, nil 75 }, 76 ).RegisterSetDeadline( 77 func(deadline time.Time) (err error) { 78 if !deadline.IsZero() { 79 return fmt.Errorf("unexpected deadline, want '%v' actual '%v'", 80 time.Time{}, 81 deadline) 82 } 83 return wantErr 84 }, 85 ) 86 mocks = []*mok.Mock{wantConn.Mock, listener.Mock} 87 receiver = NewConnReceiver(conf, listener, make(chan net.Conn, 1)) 88 ) 89 testConnReceiver(receiver, wantErr, mocks, t) 90 }) 91 92 t.Run("If Listener.Accept for the first conn failed with an error, Run should return it", 93 func(t *testing.T) { 94 var ( 95 wantErr = errors.New("set deadline error") 96 97 listener = mock.NewListener().RegisterAccept( 98 func() (conn net.Conn, err error) { 99 return nil, wantErr 100 }, 101 ) 102 mocks = []*mok.Mock{listener.Mock} 103 receiver = NewConnReceiver(ConnReceiverConf{}, listener, make(chan net.Conn, 1)) 104 ) 105 testConnReceiver(receiver, wantErr, mocks, t) 106 }) 107 108 t.Run("If Listener.Accept for the second conn failed with an error, Run should return it", 109 func(t *testing.T) { 110 var ( 111 wantErr = errors.New("set deadline error") 112 wantConn = mock.NewConn().RegisterClose( 113 func() (err error) { return nil }, 114 ) 115 listener = mock.NewListener().RegisterAccept( 116 func() (conn net.Conn, err error) { 117 return wantConn, nil 118 }, 119 ).RegisterAccept( 120 func() (conn net.Conn, err error) { 121 return nil, wantErr 122 }, 123 ) 124 mocks = []*mok.Mock{wantConn.Mock, listener.Mock} 125 receiver = NewConnReceiver(ConnReceiverConf{}, listener, make(chan net.Conn, 1)) 126 ) 127 testConnReceiver(receiver, wantErr, mocks, t) 128 }) 129 130 t.Run("ConnReceiver should be able to accept several connections", 131 func(t *testing.T) { 132 var ( 133 // wantErr = errors.New("done") 134 done = make(chan struct{}) 135 conn1 = mock.NewConn() 136 conn2 = mock.NewConn() 137 listener = mock.NewListener().RegisterAccept( 138 func() (net.Conn, error) { return conn1, nil }, 139 ).RegisterAccept( 140 func() (net.Conn, error) { return conn2, nil }, 141 ).RegisterAccept( 142 func() (net.Conn, error) { 143 <-done 144 return nil, errors.New("done") 145 }, 146 ).RegisterClose( 147 func() error { close(done); return nil }, 148 ) 149 conns = make(chan net.Conn, 2) 150 mocks = []*mok.Mock{conn1.Mock, conn2.Mock, listener.Mock} 151 receiver = NewConnReceiver(ConnReceiverConf{}, listener, conns) 152 ) 153 go func() { 154 i := 0 155 for { 156 select { 157 case <-conns: 158 i++ 159 if i == 2 { 160 goto Stop 161 } 162 case <-time.NewTimer(200 * time.Millisecond).C: 163 panic("test lasts too long") 164 } 165 } 166 Stop: 167 if err := receiver.Stop(); err != nil { 168 t.Error(err) 169 } 170 }() 171 testConnReceiver(receiver, ErrClosed, mocks, t) 172 }) 173 174 t.Run("We should be able to close the ConnHandler while Listener.Accept", 175 func(t *testing.T) { 176 testStopWhileAccept(false, t) 177 }) 178 179 t.Run("We should be able to shutdown the ConnHandler while Listener.Accept", 180 func(t *testing.T) { 181 testStopWhileAccept(true, t) 182 }) 183 184 t.Run("We should be able to close the ConnHandler while it adds conn to queue", 185 func(t *testing.T) { 186 testStopWhileQueueConn(false, t) 187 }) 188 189 t.Run("We should be able to shutdown the ConnHandler while it adds conn to queue", 190 func(t *testing.T) { 191 testStopWhileQueueConn(true, t) 192 }) 193 194 } 195 196 func RunConnReceiver(r *ConnReceiver) (errs chan error) { 197 errs = make(chan error, 1) 198 go func() { 199 if err := r.Run(); err != nil { 200 errs <- err 201 } 202 close(errs) 203 }() 204 return 205 } 206 207 func testConnReceiver(r *ConnReceiver, wantErr error, mocks []*mok.Mock, 208 t *testing.T) { 209 errs := RunConnReceiver(r) 210 testAsyncErr(wantErr, errs, mocks, t) 211 } 212 213 func testStopWhileAccept(shutdown bool, t *testing.T) { 214 // wantErr := errors.New("accept failed, cause close") 215 wantErr := ErrClosed 216 if shutdown { 217 wantErr = nil 218 } 219 var ( 220 listener = func() mock.Listener { 221 done := make(chan error) 222 return mock.NewListener().RegisterAccept( 223 func() (net.Conn, error) { 224 <-done 225 if shutdown { 226 return nil, errors.New("accept failed, cause shutdown") 227 } 228 return nil, wantErr 229 }, 230 ).RegisterClose( 231 func() error { close(done); return nil }, 232 ) 233 }() 234 conns = make(chan net.Conn) 235 mocks = []*mok.Mock{listener.Mock} 236 ) 237 receiver := NewConnReceiver(ConnReceiverConf{}, listener, conns) 238 go func() { 239 time.Sleep(100 * time.Millisecond) 240 if shutdown { 241 receiver.Shutdown() 242 } else { 243 receiver.Stop() 244 } 245 }() 246 testConnReceiver(receiver, wantErr, mocks, t) 247 _, more := <-conns 248 if more { 249 t.Error("conns chan is not closed") 250 } 251 } 252 253 func testStopWhileQueueConn(shutdown bool, t *testing.T) { 254 wantErr := ErrClosed 255 if shutdown { 256 wantErr = nil 257 } 258 var ( 259 done = make(chan error) 260 conn = func() mock.Conn { 261 conn := mock.NewConn().RegisterClose( 262 func() (err error) { return nil }, 263 ) 264 return conn 265 }() 266 listener = mock.NewListener().RegisterAccept( 267 func() (net.Conn, error) { 268 return conn, nil 269 }, 270 ).RegisterClose( 271 func() error { close(done); return nil }, 272 ) 273 conns = make(chan net.Conn) 274 mocks = []*mok.Mock{conn.Mock, listener.Mock} 275 receiver = NewConnReceiver(ConnReceiverConf{}, listener, conns) 276 ) 277 go func() { 278 time.Sleep(100 * time.Millisecond) 279 if shutdown { 280 receiver.Shutdown() 281 } else { 282 receiver.Stop() 283 } 284 }() 285 testConnReceiver(receiver, wantErr, mocks, t) 286 _, more := <-conns 287 if more { 288 t.Error("conns chan is not closed") 289 } 290 }