go.nanomsg.org/mangos/v3@v3.4.3-0.20240217232803-46464076f1f5/protocol/req/req_test.go (about) 1 // Copyright 2019 The Mangos Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use file except in compliance with the License. 5 // You may obtain a copy of the license at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package req 16 17 import ( 18 "bytes" 19 "encoding/binary" 20 "sync" 21 "testing" 22 "time" 23 24 "go.nanomsg.org/mangos/v3" 25 . "go.nanomsg.org/mangos/v3/internal/test" 26 "go.nanomsg.org/mangos/v3/protocol/rep" 27 _ "go.nanomsg.org/mangos/v3/transport/inproc" 28 ) 29 30 func TestReqIdentity(t *testing.T) { 31 id := MustGetInfo(t, NewSocket) 32 MustBeTrue(t, id.Self == mangos.ProtoReq) 33 MustBeTrue(t, id.SelfName == "req") 34 MustBeTrue(t, id.Peer == mangos.ProtoRep) 35 MustBeTrue(t, id.PeerName == "rep") 36 } 37 38 func TestReqCooked(t *testing.T) { 39 VerifyCooked(t, NewSocket) 40 } 41 42 func TestReqOptions(t *testing.T) { 43 VerifyInvalidOption(t, NewSocket) 44 VerifyOptionDuration(t, NewSocket, mangos.OptionRecvDeadline) 45 VerifyOptionDuration(t, NewSocket, mangos.OptionSendDeadline) 46 VerifyOptionDuration(t, NewSocket, mangos.OptionRetryTime) 47 VerifyOptionBool(t, NewSocket, mangos.OptionBestEffort) 48 VerifyOptionBool(t, NewSocket, mangos.OptionFailNoPeers) 49 } 50 51 func TestReqClosed(t *testing.T) { 52 VerifyClosedRecv(t, NewSocket) 53 VerifyClosedSend(t, NewSocket) 54 VerifyClosedClose(t, NewSocket) 55 VerifyClosedDial(t, NewSocket) 56 VerifyClosedListen(t, NewSocket) 57 VerifyClosedAddPipe(t, NewSocket) 58 } 59 60 func TestReqRecvState(t *testing.T) { 61 s := GetSocket(t, NewSocket) 62 v, e := s.Recv() 63 MustBeError(t, e, mangos.ErrProtoState) 64 MustBeNil(t, v) 65 MustSucceed(t, s.Close()) 66 } 67 68 func TestReqRecvDeadline(t *testing.T) { 69 self := GetSocket(t, NewSocket) 70 peer := GetSocket(t, rep.NewSocket) 71 ConnectPair(t, self, peer) 72 MustSucceed(t, self.SetOption(mangos.OptionRecvDeadline, time.Millisecond)) 73 MustSucceed(t, self.Send([]byte{})) 74 _ = MustRecv(t, peer) 75 m, e := self.RecvMsg() 76 MustBeError(t, e, mangos.ErrRecvTimeout) 77 MustBeNil(t, m) 78 MustSucceed(t, self.Close()) 79 MustSucceed(t, peer.Close()) 80 } 81 82 func TestReqContextClosed(t *testing.T) { 83 s := GetSocket(t, NewSocket) 84 c, e := s.OpenContext() 85 MustSucceed(t, e) 86 MustNotBeNil(t, c) 87 MustSucceed(t, c.Close()) 88 MustBeError(t, c.Close(), mangos.ErrClosed) 89 90 c, e = s.OpenContext() 91 MustSucceed(t, e) 92 MustNotBeNil(t, c) 93 94 MustSucceed(t, s.Close()) 95 96 MustBeError(t, c.Close(), mangos.ErrClosed) 97 98 _, e = s.OpenContext() 99 MustBeError(t, e, mangos.ErrClosed) 100 } 101 102 // This test demonstrates that sending a second request cancels any Rx on the 103 // earlier outstanding ones. 104 func TestReqCancel(t *testing.T) { 105 s := GetSocket(t, NewSocket) 106 MustSucceed(t, s.SetOption(mangos.OptionRecvDeadline, time.Second)) 107 MustSucceed(t, s.SetOption(mangos.OptionBestEffort, true)) 108 MustSendString(t, s, "first") 109 var wg sync.WaitGroup 110 wg.Add(1) 111 pass := false 112 go func() { 113 defer wg.Done() 114 v, e := s.Recv() 115 MustBeError(t, e, mangos.ErrCanceled) 116 MustBeNil(t, v) 117 pass = true 118 }() 119 time.Sleep(time.Millisecond * 50) // to allow go routine to run 120 MustSendString(t, s, "second") 121 wg.Wait() 122 MustBeTrue(t, pass) 123 MustSucceed(t, s.Close()) 124 } 125 126 // This test demonstrates that sending a second request cancels any Rx on the 127 // earlier outstanding ones. 128 func TestReqCancelDisconnect(t *testing.T) { 129 s := GetSocket(t, NewSocket) 130 peer := GetSocket(t, rep.NewSocket) 131 ConnectPair(t, s, peer) 132 MustSucceed(t, s.SetOption(mangos.OptionRecvDeadline, time.Second*3)) 133 MustSucceed(t, s.SetOption(mangos.OptionRetryTime, time.Duration(0))) 134 MustSucceed(t, s.SetOption(mangos.OptionBestEffort, true)) 135 MustSendString(t, s, "first") 136 go func() { 137 time.Sleep(time.Millisecond * 100) 138 peer.Close() 139 }() 140 v, e := s.Recv() 141 MustBeError(t, e, mangos.ErrCanceled) 142 MustBeNil(t, v) 143 MustSucceed(t, s.Close()) 144 } 145 146 // This test demonstrates cancellation before calling receive but after the 147 // message is received causes the original message to be discarded. 148 func TestReqCancelReply(t *testing.T) { 149 self := GetSocket(t, NewSocket) 150 peer := GetSocket(t, rep.NewSocket) 151 ConnectPair(t, self, peer) 152 MustSucceed(t, self.SetOption(mangos.OptionRecvDeadline, time.Second)) 153 MustSucceed(t, peer.SetOption(mangos.OptionRecvDeadline, time.Second)) 154 155 MustSendString(t, self, "query1") 156 MustRecvString(t, peer, "query1") 157 MustSendString(t, peer, "reply1") 158 // And we don't pick up the reply 159 160 time.Sleep(time.Millisecond * 50) 161 162 MustSendString(t, self, "query2") 163 MustRecvString(t, peer, "query2") 164 MustSendString(t, peer, "reply2") 165 MustRecvString(t, self, "reply2") 166 167 MustSucceed(t, self.Close()) 168 MustSucceed(t, peer.Close()) 169 } 170 171 func TestReqBestEffort(t *testing.T) { 172 timeout := time.Millisecond 173 msg := []byte{'0', '1', '2', '3'} 174 175 s := GetSocket(t, NewSocket) 176 MustSucceed(t, s.SetOption(mangos.OptionSendDeadline, timeout)) 177 MustSucceed(t, s.Listen(AddrTestInp())) 178 MustSucceed(t, s.SetOption(mangos.OptionBestEffort, true)) 179 MustSucceed(t, s.Send(msg)) 180 MustSucceed(t, s.Send(msg)) 181 MustSucceed(t, s.SetOption(mangos.OptionBestEffort, false)) 182 MustBeError(t, s.Send(msg), mangos.ErrSendTimeout) 183 MustBeError(t, s.Send(msg), mangos.ErrSendTimeout) 184 } 185 186 // This test demonstrates cancellation before calling receive but after the 187 // message is received causes the original message to be discarded. 188 func TestReqRetry(t *testing.T) { 189 self := GetSocket(t, NewSocket) 190 peer := GetSocket(t, rep.NewSocket) 191 ConnectPair(t, self, peer) 192 193 MustSucceed(t, self.SetOption(mangos.OptionRetryTime, time.Millisecond*10)) 194 MustSucceed(t, self.SetOption(mangos.OptionRecvDeadline, time.Millisecond*10)) 195 MustSucceed(t, peer.SetOption(mangos.OptionRecvDeadline, time.Millisecond*200)) 196 197 start := time.Now() 198 199 MustSendString(t, self, "query") 200 MustRecvString(t, peer, "query") 201 MustRecvString(t, peer, "query") 202 MustSendString(t, peer, "reply") 203 204 MustBeTrue(t, time.Since(start) < time.Second) 205 MustNotRecv(t, peer, mangos.ErrRecvTimeout) 206 MustBeTrue(t, time.Since(start) < time.Second) 207 208 MustSucceed(t, self.Close()) 209 MustSucceed(t, peer.Close()) 210 } 211 212 // This test repeats he retry at very frequent intervals. The idea here is 213 // to demonstrate that there are multiple resend entries in the queue. 214 // This case covers github issue #179. 215 func TestReqRetryFast(t *testing.T) { 216 self := GetSocket(t, NewSocket) 217 peer := GetSocket(t, rep.NewSocket) 218 ConnectPair(t, self, peer) 219 220 mp, p := MockConnect(t, self) 221 MustSucceed(t, self.SetOption(mangos.OptionRetryTime, time.Nanosecond)) 222 MustSucceed(t, self.SetOption(mangos.OptionRecvDeadline, time.Millisecond*10)) 223 MustSucceed(t, peer.SetOption(mangos.OptionRecvDeadline, time.Millisecond*200)) 224 225 start := time.Now() 226 227 MustSendString(t, self, "query") 228 MockMustRecvStr(t, mp, "query", time.Second) 229 MockMustRecvStr(t, mp, "query", time.Second) 230 time.Sleep(time.Millisecond * 10) 231 MustSucceed(t, p.Close()) 232 233 ConnectPair(t, self, peer) 234 MustRecvString(t, peer, "query") 235 MustRecvString(t, peer, "query") 236 MustSendString(t, peer, "reply") 237 238 MustBeTrue(t, time.Since(start) < time.Second) 239 MustBeTrue(t, time.Since(start) < time.Second) 240 241 MustSucceed(t, self.Close()) 242 MustSucceed(t, peer.Close()) 243 } 244 245 func TestReqRetryLateConnect(t *testing.T) { 246 self := GetSocket(t, NewSocket) 247 peer := GetSocket(t, rep.NewSocket) 248 249 MustSucceed(t, self.SetOption(mangos.OptionReconnectTime, 250 time.Millisecond*100)) 251 252 MustSucceed(t, self.SetOption(mangos.OptionBestEffort, true)) 253 MustSendString(t, self, "hello") 254 255 ConnectPair(t, self, peer) 256 257 MustRecvString(t, peer, "hello") 258 MustSendString(t, peer, "world") 259 260 MustRecvString(t, self, "world") 261 262 MustSucceed(t, self.Close()) 263 MustSucceed(t, peer.Close()) 264 } 265 266 func TestReqRetryReconnect(t *testing.T) { 267 self := GetSocket(t, NewSocket) 268 peer1 := GetSocket(t, rep.NewSocket) 269 peer2 := GetSocket(t, rep.NewSocket) 270 271 MustSucceed(t, self.SetOption(mangos.OptionReconnectTime, time.Second)) 272 MustSucceed(t, self.SetOption(mangos.OptionRetryTime, time.Second*10)) 273 274 ConnectPair(t, self, peer1) 275 276 start := time.Now() 277 278 MustSendString(t, self, "ping") 279 MustRecvString(t, peer1, "ping") 280 281 MustSucceed(t, peer1.Close()) 282 time.Sleep(time.Millisecond * 10) 283 284 ConnectPair(t, self, peer2) 285 MustRecvString(t, peer2, "ping") 286 MustSendString(t, peer2, "pong") 287 MustRecvString(t, self, "pong") 288 289 // Reconnect needs to happen immediately, and start a timely reply. 290 MustBeTrue(t, time.Since(start) < time.Second) 291 292 MustSucceed(t, self.Close()) 293 MustSucceed(t, peer2.Close()) 294 } 295 296 // This demonstrates receiving a frame with garbage data. 297 func TestReqRecvGarbage(t *testing.T) { 298 self := GetSocket(t, NewSocket) 299 mock, pipe := MockConnect(t, self) 300 expire := time.Millisecond * 10 301 302 MustSucceed(t, self.SetOption(mangos.OptionRecvDeadline, expire)) 303 MustSucceed(t, self.SetOption(mangos.OptionBestEffort, true)) 304 305 MustSendString(t, self, "") 306 MockMustSendStr(t, mock, "abc", expire) 307 MustNotRecv(t, self, mangos.ErrRecvTimeout) 308 309 var msg []byte 310 // No header 311 MustSendString(t, self, "") 312 MockMustSend(t, mock, msg, expire) 313 MustNotRecv(t, self, mangos.ErrRecvTimeout) 314 315 // No request ID 316 MustSendString(t, self, "") 317 msg = append(msg, 0, 1, 2, 3) 318 MockMustSend(t, mock, msg, expire) 319 MustNotRecv(t, self, mangos.ErrRecvTimeout) 320 321 // Incorrect pipe ID 322 MustSendString(t, self, "") 323 binary.BigEndian.PutUint32(msg, pipe.ID()^0xff) 324 msg = append(msg, 0x80, 4, 3, 2) 325 MockMustSend(t, mock, msg, expire) 326 MustNotRecv(t, self, mangos.ErrRecvTimeout) 327 328 // Also send a bogus header -- no request ID 329 MustSendString(t, self, "") 330 MockMustSendStr(t, mock, "\001\002\003\004", time.Millisecond*10) 331 MustNotRecv(t, self, mangos.ErrRecvTimeout) 332 333 MustSucceed(t, self.Close()) 334 } 335 336 func TestReqCtxCloseSend(t *testing.T) { 337 self := GetSocket(t, NewSocket) 338 _, _ = MockConnect(t, self) 339 340 c, e := self.OpenContext() 341 MustSucceed(t, e) 342 343 // This gets something on the pipe. 344 MustSendString(t, self, "") 345 var wg sync.WaitGroup 346 wg.Add(1) 347 348 time.AfterFunc(time.Millisecond*10, func() { 349 MustSucceed(t, c.Close()) 350 wg.Done() 351 }) 352 MustBeError(t, c.Send([]byte{}), mangos.ErrClosed) 353 wg.Wait() 354 355 MustSucceed(t, self.Close()) 356 } 357 358 func TestReqCtxCloseRecv(t *testing.T) { 359 self := GetSocket(t, NewSocket) 360 peer := GetSocket(t, rep.NewSocket) 361 362 ConnectPair(t, self, peer) 363 c, e := self.OpenContext() 364 MustSucceed(t, e) 365 366 MustSucceed(t, c.Send([]byte{})) 367 MustSucceed(t, self.SetOption(mangos.OptionRecvDeadline, time.Second)) 368 369 var wg sync.WaitGroup 370 wg.Add(1) 371 372 time.AfterFunc(time.Millisecond*20, func() { 373 MustSucceed(t, c.Close()) 374 wg.Done() 375 }) 376 b, e := c.Recv() 377 MustBeError(t, e, mangos.ErrClosed) 378 MustBeNil(t, b) 379 wg.Wait() 380 MustSucceed(t, self.Close()) 381 MustSucceed(t, peer.Close()) 382 } 383 384 // This sets up a bunch of contexts to run in parallel, and verifies that 385 // they all seem to run with no mis-deliveries. 386 func TestReqMultiContexts(t *testing.T) { 387 count := 300 388 repeat := 20 389 390 self := GetSocket(t, NewSocket) 391 peer := GetSocket(t, rep.NewSocket) 392 393 ConnectPair(t, self, peer) 394 395 recv := make([]int, count) 396 ctxs := make([]mangos.Context, 0, count) 397 var wg1 sync.WaitGroup 398 var wg2 sync.WaitGroup 399 wg1.Add(count) 400 fn := func(index int) { 401 defer wg1.Done() 402 c, e := self.OpenContext() 403 MustSucceed(t, e) 404 MustNotBeNil(t, c) 405 defer c.Close() 406 407 ctxs = append(ctxs, c) 408 topic := make([]byte, 4) 409 binary.BigEndian.PutUint32(topic, uint32(index)) 410 411 MustSucceed(t, c.SetOption(mangos.OptionSendDeadline, time.Second)) 412 MustSucceed(t, c.SetOption(mangos.OptionRecvDeadline, time.Second)) 413 414 for i := 0; i < repeat; i++ { 415 MustSucceed(t, c.Send(topic)) 416 m, e := c.RecvMsg() 417 MustSucceed(t, e) 418 MustBeTrue(t, len(m.Body) == 4) 419 MustBeTrue(t, bytes.Equal(m.Body, topic)) 420 recv[index]++ 421 } 422 } 423 424 for i := 0; i < count; i++ { 425 go fn(i) 426 } 427 428 wg2.Add(1) 429 go func() { 430 defer wg2.Done() 431 var e error 432 var m *mangos.Message 433 for { 434 if m, e = peer.RecvMsg(); e != nil { 435 break 436 } 437 if e = peer.SendMsg(m); e != nil { 438 break 439 } 440 } 441 MustBeError(t, e, mangos.ErrClosed) 442 }() 443 444 // Give time for everything to be delivered. 445 wg1.Wait() 446 MustSucceed(t, peer.Close()) 447 wg2.Wait() 448 MustSucceed(t, self.Close()) 449 450 for i := 0; i < count; i++ { 451 MustBeTrue(t, recv[i] == repeat) 452 } 453 } 454 455 func TestReqSendNoPeers(t *testing.T) { 456 s := GetSocket(t, NewSocket) 457 MustSucceed(t, s.SetOption(mangos.OptionFailNoPeers, true)) 458 MustBeError(t, s.Send([]byte("junk")), mangos.ErrNoPeers) 459 MustSucceed(t, s.Close()) 460 } 461 462 func TestReqSendNoPeerDisconnect(t *testing.T) { 463 VerifyOptionBool(t, NewSocket, mangos.OptionFailNoPeers) 464 465 s := GetSocket(t, NewSocket) 466 p := GetSocket(t, rep.NewSocket) 467 c1, err := s.OpenContext() 468 MustSucceed(t, err) 469 c2, err := s.OpenContext() 470 MustSucceed(t, err) 471 MustSucceed(t, s.SetOption(mangos.OptionSendDeadline, time.Second)) 472 473 MustSucceed(t, s.SetOption(mangos.OptionFailNoPeers, true)) 474 475 // Now connect them so they can drain -- we should only have 3 messages 476 // that arrive at the peer. 477 ConnectPair(t, s, p) 478 time.Sleep(time.Millisecond * 20) 479 // this logic fills the queue 480 go func() { 481 _ = c1.Send([]byte("one")) 482 }() 483 go func() { 484 _ = c2.Send([]byte("one")) 485 }() 486 time.Sleep(time.Millisecond * 10) 487 go func() { 488 time.Sleep(time.Millisecond * 20) 489 MustSucceed(t, p.Close()) 490 }() 491 time.Sleep(time.Millisecond * 20) 492 493 MustBeError(t, s.Send([]byte("three")), mangos.ErrNoPeers) 494 MustSucceed(t, s.Close()) 495 } 496 497 498 func TestReqRecvNoPeer(t *testing.T) { 499 VerifyOptionBool(t, NewSocket, mangos.OptionFailNoPeers) 500 501 s := GetSocket(t, NewSocket) 502 p := GetSocket(t, rep.NewSocket) 503 MustSucceed(t, s.SetOption(mangos.OptionSendDeadline, time.Second)) 504 505 MustSucceed(t, s.SetOption(mangos.OptionFailNoPeers, true)) 506 507 // Now connect them so they can drain -- we should only have 3 messages 508 // that arrive at the peer. 509 ConnectPair(t, s, p) 510 time.Sleep(time.Millisecond * 20) 511 MustSucceed(t, s.Send([]byte("one"))) // sent by the socket, picked up by rep socket 512 time.Sleep(time.Millisecond * 20) 513 MustSucceed(t, p.Close()) 514 time.Sleep(time.Millisecond*20) 515 MustNotRecv(t, s, mangos.ErrNoPeers) 516 MustSucceed(t, s.Close()) 517 } 518 519 func TestReqRecvNoPeerDisconnect(t *testing.T) { 520 VerifyOptionBool(t, NewSocket, mangos.OptionFailNoPeers) 521 522 s := GetSocket(t, NewSocket) 523 p := GetSocket(t, rep.NewSocket) 524 MustSucceed(t, s.SetOption(mangos.OptionSendDeadline, time.Second)) 525 526 MustSucceed(t, s.SetOption(mangos.OptionFailNoPeers, true)) 527 528 // Now connect them so they can drain -- we should only have 3 messages 529 // that arrive at the peer. 530 ConnectPair(t, s, p) 531 time.Sleep(time.Millisecond * 20) 532 MustSucceed(t, s.Send([]byte("one"))) // sent by the socket, picked up by rep socket 533 go func() { 534 time.Sleep(time.Millisecond*10) 535 MustSucceed(t, p.Close()) 536 }() 537 MustNotRecv(t, s, mangos.ErrNoPeers) 538 MustSucceed(t, s.Close()) 539 }