nanomsg.org/go/mangos/v2@v2.0.9-0.20200203084354-8a092611e461/protocol/surveyor/surveyor_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 surveyor 16 17 import ( 18 "bytes" 19 "encoding/binary" 20 "nanomsg.org/go/mangos/v2/protocol/respondent" 21 "sync" 22 "testing" 23 "time" 24 25 "nanomsg.org/go/mangos/v2" 26 . "nanomsg.org/go/mangos/v2/internal/test" 27 _ "nanomsg.org/go/mangos/v2/transport/inproc" 28 ) 29 30 func TestSurveyorIdentity(t *testing.T) { 31 s, err := NewSocket() 32 MustSucceed(t, err) 33 id := s.Info() 34 MustBeTrue(t, id.Self == mangos.ProtoSurveyor) 35 MustBeTrue(t, id.SelfName == "surveyor") 36 MustBeTrue(t, id.Peer == mangos.ProtoRespondent) 37 MustBeTrue(t, id.PeerName == "respondent") 38 MustSucceed(t, s.Close()) 39 } 40 41 func TestSurveyorCooked(t *testing.T) { 42 VerifyCooked(t, NewSocket) 43 } 44 45 func TestSurveyorNonBlock(t *testing.T) { 46 maxqlen := 2 47 48 rp, err := NewSocket() 49 MustSucceed(t, err) 50 MustNotBeNil(t, rp) 51 52 MustSucceed(t, rp.SetOption(mangos.OptionWriteQLen, maxqlen)) 53 MustSucceed(t, rp.Listen(AddrTestInp())) 54 55 msg := []byte{'A', 'B', 'C'} 56 start := time.Now() 57 for i := 0; i < maxqlen*10; i++ { 58 MustSucceed(t, rp.Send(msg)) 59 } 60 end := time.Now() 61 MustBeTrue(t, end.Sub(start) < time.Second/10) 62 MustSucceed(t, rp.Close()) 63 } 64 65 func TestSurveyorOptions(t *testing.T) { 66 VerifyInvalidOption(t, NewSocket) 67 VerifyOptionDuration(t, NewSocket, mangos.OptionRecvDeadline) 68 VerifyOptionDuration(t, NewSocket, mangos.OptionSurveyTime) 69 VerifyOptionQLen(t, NewSocket, mangos.OptionReadQLen) 70 VerifyOptionQLen(t, NewSocket, mangos.OptionWriteQLen) 71 } 72 73 func TestSurveyorClosed(t *testing.T) { 74 VerifyClosedRecv(t, NewSocket) 75 VerifyClosedSend(t, NewSocket) 76 VerifyClosedClose(t, NewSocket) 77 VerifyClosedDial(t, NewSocket) 78 VerifyClosedListen(t, NewSocket) 79 VerifyClosedAddPipe(t, NewSocket) 80 } 81 82 func TestSurveyorRecvState(t *testing.T) { 83 s, e := NewSocket() 84 MustSucceed(t, e) 85 v, e := s.Recv() 86 MustBeError(t, e, mangos.ErrProtoState) 87 MustBeNil(t, v) 88 MustSucceed(t, s.Close()) 89 } 90 91 // This test demonstrates that sending a second survey cancels any Rx on the 92 // earlier outstanding ones. 93 func TestSurveyorCancel(t *testing.T) { 94 self := GetSocket(t, NewSocket) 95 MustSucceed(t, self.SetOption(mangos.OptionSurveyTime, time.Second)) 96 MustSucceed(t, self.Send([]byte("first"))) 97 var wg sync.WaitGroup 98 wg.Add(1) 99 pass := false 100 go func() { 101 MustNotRecv(t, self, mangos.ErrCanceled) 102 pass = true 103 wg.Done() 104 }() 105 time.Sleep(time.Millisecond * 50) // to allow go routine to run 106 MustSucceed(t, self.Send([]byte("second"))) 107 wg.Wait() 108 MustSucceed(t, self.Close()) 109 MustBeTrue(t, pass) 110 } 111 112 // This test demonstrates that sending a second survey discards any received 113 // messages from the earlier survey. 114 func TestSurveyorCancelDiscard(t *testing.T) { 115 s := GetSocket(t, NewSocket) 116 // r1's message will get into the queue, but r2's will be sent 117 // after we have canceled -- neither should get through 118 r1 := GetSocket(t, respondent.NewSocket) 119 r2 := GetSocket(t, respondent.NewSocket) 120 a := AddrTestInp() 121 MustSucceed(t, s.Listen(a)) 122 MustSucceed(t, r1.Dial(a)) 123 MustSucceed(t, r2.Dial(a)) 124 time.Sleep(time.Millisecond * 20) 125 MustSucceed(t, s.SetOption(mangos.OptionSurveyTime, time.Second)) 126 MustSucceed(t, s.SetOption(mangos.OptionRecvDeadline, time.Millisecond*10)) 127 MustSucceed(t, s.Send([]byte("first"))) 128 v1, e := r1.Recv() 129 MustSucceed(t, e) 130 MustBeTrue(t, string(v1) == "first") 131 MustSucceed(t, r1.Send([]byte("reply1"))) 132 v2, e := r2.Recv() 133 MustSucceed(t, e) 134 MustBeTrue(t, string(v2) == "first") 135 136 time.Sleep(time.Millisecond * 10) 137 MustSucceed(t, s.Send([]byte("second"))) 138 time.Sleep(time.Millisecond * 10) // to allow async cancel to finish 139 MustSucceed(t, r2.Send([]byte("reply2"))) 140 v, e := s.Recv() 141 MustBeError(t, e, mangos.ErrRecvTimeout) 142 MustBeNil(t, v) 143 MustSucceed(t, s.Close()) 144 MustSucceed(t, r1.Close()) 145 MustSucceed(t, r2.Close()) 146 } 147 148 // This test demonstrates that closing the socket aborts outstanding receives. 149 func TestSurveyorCloseRx(t *testing.T) { 150 s := GetSocket(t, NewSocket) 151 MustSucceed(t, s.SetOption(mangos.OptionSurveyTime, time.Second)) 152 MustSucceed(t, s.Send([]byte("first"))) 153 var wg sync.WaitGroup 154 wg.Add(1) 155 pass := false 156 go func() { 157 defer wg.Done() 158 v, e := s.Recv() 159 MustBeError(t, e, mangos.ErrClosed) 160 MustBeNil(t, v) 161 pass = true 162 }() 163 time.Sleep(time.Millisecond * 50) // to allow go routine to run 164 MustSucceed(t, s.Close()) 165 wg.Wait() 166 MustBeTrue(t, pass) 167 } 168 169 // This test demonstrates that surveys expire on their own. 170 func TestSurveyExpire(t *testing.T) { 171 s := GetSocket(t, NewSocket) 172 MustSucceed(t, s.SetOption(mangos.OptionSurveyTime, time.Millisecond*10)) 173 MustSucceed(t, s.Send([]byte("first"))) 174 v, e := s.Recv() 175 MustBeError(t, e, mangos.ErrProtoState) 176 MustBeNil(t, v) 177 MustSucceed(t, s.Close()) 178 } 179 180 // This test demonstrates that we can keep sending even if the pipes are full. 181 func TestSurveyorBestEffortSend(t *testing.T) { 182 s := GetSocket(t, NewSocket) 183 r := GetSocket(t, respondent.NewSocket) 184 a := AddrTestInp() 185 MustSucceed(t, s.SetOption(mangos.OptionWriteQLen, 1)) 186 MustSucceed(t, s.Listen(a)) 187 MustSucceed(t, r.Dial(a)) 188 189 MustSucceed(t, s.SetOption(mangos.OptionSurveyTime, time.Second)) 190 191 time.Sleep(time.Millisecond * 10) 192 for i := 0; i < 100; i++ { 193 MustSucceed(t, s.Send([]byte{byte(i)})) 194 } 195 MustSucceed(t, s.Close()) 196 } 197 198 // This test demonstrates that if too many responses are received they will 199 // be dropped. 200 func TestSurveyorRxDiscard(t *testing.T) { 201 a := AddrTestInp() 202 s := GetSocket(t, NewSocket) 203 MustSucceed(t, s.SetOption(mangos.OptionReadQLen, 2)) 204 MustSucceed(t, s.SetOption(mangos.OptionRecvDeadline, time.Millisecond*10)) 205 MustSucceed(t, s.SetOption(mangos.OptionSurveyTime, time.Second)) 206 MustSucceed(t, s.Listen(a)) 207 208 nresp := 100 209 var rs []mangos.Socket 210 var wg sync.WaitGroup 211 wg.Add(nresp) 212 for i := 0; i < nresp; i++ { 213 r := GetSocket(t, respondent.NewSocket) 214 MustSucceed(t, r.Dial(a)) 215 rs = append(rs, r) 216 go func() { 217 defer wg.Done() 218 m, e := r.RecvMsg() 219 MustSucceed(t, e) 220 MustSucceed(t, r.SendMsg(m)) 221 }() 222 } 223 time.Sleep(time.Millisecond * 10) 224 MustSucceed(t, s.Send([]byte{'a'})) 225 wg.Wait() 226 time.Sleep(time.Millisecond * 10) 227 nrecv := 0 228 for { 229 m, e := s.RecvMsg() 230 if e != nil { 231 MustBeError(t, e, mangos.ErrRecvTimeout) 232 break 233 } 234 m.Free() 235 nrecv++ 236 } 237 MustBeTrue(t, nrecv == 2) // must match the queue length 238 for _, r := range rs { 239 MustSucceed(t, r.Close()) 240 } 241 MustSucceed(t, s.Close()) 242 } 243 244 // This test demonstrates that we can send surveys to a bunch of peers, 245 // and collect responses from them all. 246 func TestSurveyorBroadcast(t *testing.T) { 247 a := AddrTestInp() 248 249 s := GetSocket(t, NewSocket) 250 MustSucceed(t, s.Listen(a)) 251 252 // note the total number of messages exchanged will be nresp * repeat 253 nresp := 100 254 repeat := 300 255 256 MustSucceed(t, s.SetOption(mangos.OptionReadQLen, nresp)) 257 r := make([]mangos.Socket, 0, nresp) 258 var wg sync.WaitGroup 259 wg.Add(nresp) 260 261 for i := 0; i < nresp; i++ { 262 x := GetSocket(t, respondent.NewSocket) 263 MustSucceed(t, x.Dial(a)) 264 r = append(r, x) 265 266 go func(idx int) { 267 defer wg.Done() 268 269 for num := 0; num < repeat; num++ { 270 v, e := x.Recv() 271 MustSucceed(t, e) 272 MustBeTrue(t, string(v) == "survey") 273 body := make([]byte, 8) 274 binary.BigEndian.PutUint32(body, uint32(idx)) 275 binary.BigEndian.PutUint32(body[4:], uint32(num)) 276 MustSucceed(t, x.Send(body)) 277 } 278 }(i) 279 } 280 281 time.Sleep(time.Millisecond * 100) 282 283 MustSucceed(t, s.SetOption(mangos.OptionSurveyTime, time.Millisecond*200)) 284 MustSucceed(t, s.SetOption(mangos.OptionReadQLen, nresp)) 285 MustSucceed(t, s.SetOption(mangos.OptionRecvDeadline, time.Millisecond*500)) 286 287 recv := make([]int, nresp) 288 289 for num := 0; num < repeat; num++ { 290 MustSucceed(t, s.Send([]byte("survey"))) 291 for i := 0; i < nresp; i++ { 292 v, e := s.Recv() 293 MustSucceed(t, e) 294 MustBeTrue(t, len(v) == 8) 295 peer := binary.BigEndian.Uint32(v) 296 MustBeTrue(t, peer < uint32(nresp)) 297 MustBeTrue(t, binary.BigEndian.Uint32(v[4:]) == uint32(num)) 298 MustBeTrue(t, recv[peer] == num) 299 recv[peer]++ 300 } 301 302 // We could wait for the survey to timeout, but we don't. 303 } 304 wg.Wait() 305 306 MustSucceed(t, s.Close()) 307 for i := 0; i < nresp; i++ { 308 MustSucceed(t, r[i].Close()) 309 } 310 } 311 312 func TestSurveyorContextClosed(t *testing.T) { 313 s := GetSocket(t, NewSocket) 314 c, e := s.OpenContext() 315 MustSucceed(t, e) 316 MustNotBeNil(t, c) 317 MustSucceed(t, c.Close()) 318 MustBeError(t, c.Close(), mangos.ErrClosed) 319 320 c, e = s.OpenContext() 321 MustSucceed(t, e) 322 MustNotBeNil(t, c) 323 324 MustSucceed(t, s.Close()) 325 326 MustBeError(t, c.Close(), mangos.ErrClosed) 327 328 _, e = s.OpenContext() 329 MustBeError(t, e, mangos.ErrClosed) 330 } 331 332 func TestSurveyorContextCloseAbort(t *testing.T) { 333 s := GetSocket(t, NewSocket) 334 defer MustClose(t, s) 335 336 c, e := s.OpenContext() 337 MustSucceed(t, e) 338 MustNotBeNil(t, c) 339 MustSucceed(t, c.SetOption(mangos.OptionRecvDeadline, time.Second)) 340 341 // To get us an id. 342 MustSucceed(t, c.Send([]byte{})) 343 var wg sync.WaitGroup 344 wg.Add(1) 345 go func() { 346 defer wg.Done() 347 time.Sleep(time.Millisecond * 50) 348 MustSucceed(t, c.Close()) 349 }() 350 351 _, e = c.Recv() 352 MustBeError(t, e, mangos.ErrClosed) 353 } 354 355 // This sets up a bunch of contexts to run in parallel, and verifies that 356 // they all seem to run with no mis-deliveries. 357 func TestSurveyorMultiContexts(t *testing.T) { 358 count := 30 359 repeat := 20 360 361 s := GetSocket(t, NewSocket) 362 r := GetSocket(t, respondent.NewSocket) 363 MustSucceed(t, s.SetOption(mangos.OptionReadQLen, count*repeat)) 364 MustSucceed(t, r.SetOption(mangos.OptionReadQLen, count*repeat)) 365 MustSucceed(t, r.SetOption(mangos.OptionWriteQLen, count*repeat)) 366 MustSucceed(t, s.SetOption(mangos.OptionWriteQLen, count*repeat)) 367 368 a := AddrTestInp() 369 370 MustSucceed(t, r.Listen(a)) 371 MustSucceed(t, s.Dial(a)) 372 373 // Make sure we have dialed properly 374 time.Sleep(time.Millisecond * 20) 375 376 recv := make([]int, count) 377 ctxs := make([]mangos.Context, 0, count) 378 var wg1 sync.WaitGroup 379 var wg2 sync.WaitGroup 380 wg1.Add(count) 381 fn := func(index int) { 382 defer wg1.Done() 383 c, e := s.OpenContext() 384 MustSucceed(t, e) 385 MustNotBeNil(t, c) 386 387 ctxs = append(ctxs, c) 388 topic := make([]byte, 4) 389 binary.BigEndian.PutUint32(topic, uint32(index)) 390 391 MustSucceed(t, c.SetOption(mangos.OptionRecvDeadline, time.Minute/4)) 392 MustSucceed(t, c.SetOption(mangos.OptionSurveyTime, time.Minute)) 393 394 for i := 0; i < repeat; i++ { 395 MustSucceed(t, c.Send(topic)) 396 m, e := c.RecvMsg() 397 MustSucceed(t, e) 398 MustBeTrue(t, len(m.Body) == 4) 399 MustBeTrue(t, bytes.Equal(m.Body, topic)) 400 recv[index]++ 401 } 402 } 403 404 for i := 0; i < count; i++ { 405 go fn(i) 406 } 407 408 wg2.Add(1) 409 go func() { 410 defer wg2.Done() 411 var e error 412 var m *mangos.Message 413 for { 414 if m, e = r.RecvMsg(); e != nil { 415 break 416 } 417 if e = r.SendMsg(m); e != nil { 418 break 419 } 420 } 421 MustBeError(t, e, mangos.ErrClosed) 422 }() 423 424 // Give time for everything to be delivered. 425 wg1.Wait() 426 MustSucceed(t, r.Close()) 427 wg2.Wait() 428 MustSucceed(t, s.Close()) 429 430 for i := 0; i < count; i++ { 431 MustBeTrue(t, recv[i] == repeat) 432 } 433 } 434 435 func TestSurveyorRecvGarbage(t *testing.T) { 436 self := GetSocket(t, NewSocket) 437 mock, _ := MockConnect(t, self) 438 expire := time.Millisecond * 20 439 440 MustSucceed(t, self.SetOption(mangos.OptionRecvDeadline, expire)) 441 442 MustSendString(t, self, "") 443 MockMustSendStr(t, mock, "abc", expire) 444 MustNotRecv(t, self, mangos.ErrRecvTimeout) 445 446 var msg []byte 447 // No header 448 MustSendString(t, self, "") 449 MockMustSend(t, mock, msg, expire) 450 MustNotRecv(t, self, mangos.ErrRecvTimeout) 451 452 // No request ID 453 MustSendString(t, self, "") 454 msg = append(msg, 0, 1, 2, 3) 455 MockMustSend(t, mock, msg, expire) 456 MustNotRecv(t, self, mangos.ErrRecvTimeout) 457 458 // Also send a bogus header -- no request ID 459 MustSendString(t, self, "") 460 MockMustSendStr(t, mock, "\001\002\003\004", time.Second) 461 MustNotRecv(t, self, mangos.ErrRecvTimeout) 462 463 MustSucceed(t, self.Close()) 464 }