github.com/nsqio/nsq@v1.3.0/nsqd/protocol_v2_test.go (about) 1 package nsqd 2 3 import ( 4 "bufio" 5 "bytes" 6 "compress/flate" 7 "crypto/tls" 8 "encoding/json" 9 "errors" 10 "fmt" 11 "io" 12 "math" 13 "math/rand" 14 "net" 15 "net/http" 16 "net/http/httptest" 17 "net/url" 18 "os" 19 "runtime" 20 "strconv" 21 "sync" 22 "sync/atomic" 23 "testing" 24 "time" 25 26 "github.com/golang/snappy" 27 "github.com/nsqio/go-nsq" 28 "github.com/nsqio/nsq/internal/protocol" 29 "github.com/nsqio/nsq/internal/test" 30 ) 31 32 func mustStartNSQD(opts *Options) (net.Addr, net.Addr, *NSQD) { 33 opts.TCPAddress = "127.0.0.1:0" 34 opts.HTTPAddress = "127.0.0.1:0" 35 opts.HTTPSAddress = "127.0.0.1:0" 36 if opts.DataPath == "" { 37 tmpDir, err := os.MkdirTemp("", "nsq-test-") 38 if err != nil { 39 panic(err) 40 } 41 opts.DataPath = tmpDir 42 } 43 nsqd, err := New(opts) 44 if err != nil { 45 panic(err) 46 } 47 go func() { 48 err := nsqd.Main() 49 if err != nil { 50 panic(err) 51 } 52 }() 53 return nsqd.RealTCPAddr(), nsqd.RealHTTPAddr(), nsqd 54 } 55 56 func mustConnectNSQD(tcpAddr net.Addr) (net.Conn, error) { 57 conn, err := net.DialTimeout("tcp", tcpAddr.String(), time.Second) 58 if err != nil { 59 return nil, err 60 } 61 conn.Write(nsq.MagicV2) 62 return conn, nil 63 } 64 65 func identify(t *testing.T, conn io.ReadWriter, extra map[string]interface{}, f int32) []byte { 66 ci := make(map[string]interface{}) 67 ci["client_id"] = "test" 68 ci["feature_negotiation"] = true 69 for k, v := range extra { 70 ci[k] = v 71 } 72 cmd, _ := nsq.Identify(ci) 73 _, err := cmd.WriteTo(conn) 74 test.Nil(t, err) 75 resp, err := nsq.ReadResponse(conn) 76 test.Nil(t, err) 77 frameType, data, err := nsq.UnpackResponse(resp) 78 test.Nil(t, err) 79 test.Equal(t, frameType, f) 80 return data 81 } 82 83 func sub(t *testing.T, conn io.ReadWriter, topicName string, channelName string) { 84 _, err := nsq.Subscribe(topicName, channelName).WriteTo(conn) 85 test.Nil(t, err) 86 readValidate(t, conn, frameTypeResponse, "OK") 87 } 88 89 func authCmd(t *testing.T, conn io.ReadWriter, authSecret string, expectSuccess string) { 90 auth, _ := nsq.Auth(authSecret) 91 _, err := auth.WriteTo(conn) 92 test.Nil(t, err) 93 if expectSuccess != "" { 94 readValidate(t, conn, nsq.FrameTypeResponse, expectSuccess) 95 } 96 } 97 98 func subFail(t *testing.T, conn io.ReadWriter, topicName string, channelName string) { 99 _, err := nsq.Subscribe(topicName, channelName).WriteTo(conn) 100 test.Nil(t, err) 101 resp, _ := nsq.ReadResponse(conn) 102 frameType, _, _ := nsq.UnpackResponse(resp) 103 test.Equal(t, frameTypeError, frameType) 104 } 105 106 func readValidate(t *testing.T, conn io.Reader, f int32, d string) []byte { 107 resp, err := nsq.ReadResponse(conn) 108 test.Nil(t, err) 109 frameType, data, err := nsq.UnpackResponse(resp) 110 test.Nil(t, err) 111 test.Equal(t, f, frameType) 112 test.Equal(t, d, string(data)) 113 return data 114 } 115 116 // test channel/topic names 117 func TestChannelTopicNames(t *testing.T) { 118 test.Equal(t, true, protocol.IsValidChannelName("test")) 119 test.Equal(t, true, protocol.IsValidChannelName("test-with_period.")) 120 test.Equal(t, true, protocol.IsValidChannelName("test#ephemeral")) 121 test.Equal(t, true, protocol.IsValidTopicName("test")) 122 test.Equal(t, true, protocol.IsValidTopicName("test-with_period.")) 123 test.Equal(t, true, protocol.IsValidTopicName("test#ephemeral")) 124 test.Equal(t, false, protocol.IsValidTopicName("test:ephemeral")) 125 } 126 127 // exercise the basic operations of the V2 protocol 128 func TestBasicV2(t *testing.T) { 129 opts := NewOptions() 130 opts.Logger = test.NewTestLogger(t) 131 opts.ClientTimeout = 60 * time.Second 132 tcpAddr, _, nsqd := mustStartNSQD(opts) 133 defer os.RemoveAll(opts.DataPath) 134 defer nsqd.Exit() 135 136 topicName := "test_v2" + strconv.Itoa(int(time.Now().Unix())) 137 topic := nsqd.GetTopic(topicName) 138 msg := NewMessage(topic.GenerateID(), []byte("test body")) 139 topic.PutMessage(msg) 140 141 conn, err := mustConnectNSQD(tcpAddr) 142 test.Nil(t, err) 143 defer conn.Close() 144 145 identify(t, conn, nil, frameTypeResponse) 146 sub(t, conn, topicName, "ch") 147 148 _, err = nsq.Ready(1).WriteTo(conn) 149 test.Nil(t, err) 150 151 resp, err := nsq.ReadResponse(conn) 152 test.Nil(t, err) 153 frameType, data, _ := nsq.UnpackResponse(resp) 154 msgOut, _ := decodeMessage(data) 155 test.Equal(t, frameTypeMessage, frameType) 156 test.Equal(t, msg.ID, msgOut.ID) 157 test.Equal(t, msg.Body, msgOut.Body) 158 test.Equal(t, uint16(1), msgOut.Attempts) 159 } 160 161 func TestMultipleConsumerV2(t *testing.T) { 162 msgChan := make(chan *Message) 163 164 opts := NewOptions() 165 opts.Logger = test.NewTestLogger(t) 166 opts.ClientTimeout = 60 * time.Second 167 tcpAddr, _, nsqd := mustStartNSQD(opts) 168 defer os.RemoveAll(opts.DataPath) 169 defer nsqd.Exit() 170 171 topicName := "test_multiple_v2" + strconv.Itoa(int(time.Now().Unix())) 172 topic := nsqd.GetTopic(topicName) 173 msg := NewMessage(topic.GenerateID(), []byte("test body")) 174 topic.GetChannel("ch1") 175 topic.GetChannel("ch2") 176 topic.PutMessage(msg) 177 178 for _, i := range []string{"1", "2"} { 179 conn, err := mustConnectNSQD(tcpAddr) 180 test.Nil(t, err) 181 defer conn.Close() 182 183 identify(t, conn, nil, frameTypeResponse) 184 sub(t, conn, topicName, "ch"+i) 185 186 _, err = nsq.Ready(1).WriteTo(conn) 187 test.Nil(t, err) 188 189 go func(c net.Conn) { 190 resp, err := nsq.ReadResponse(c) 191 test.Nil(t, err) 192 _, data, err := nsq.UnpackResponse(resp) 193 test.Nil(t, err) 194 msg, err := decodeMessage(data) 195 test.Nil(t, err) 196 msgChan <- msg 197 }(conn) 198 } 199 200 msgOut := <-msgChan 201 test.Equal(t, msg.ID, msgOut.ID) 202 test.Equal(t, msg.Body, msgOut.Body) 203 test.Equal(t, uint16(1), msgOut.Attempts) 204 msgOut = <-msgChan 205 test.Equal(t, msg.ID, msgOut.ID) 206 test.Equal(t, msg.Body, msgOut.Body) 207 test.Equal(t, uint16(1), msgOut.Attempts) 208 } 209 210 func TestClientTimeout(t *testing.T) { 211 topicName := "test_client_timeout_v2" + strconv.Itoa(int(time.Now().Unix())) 212 213 opts := NewOptions() 214 opts.Logger = test.NewTestLogger(t) 215 opts.ClientTimeout = 150 * time.Millisecond 216 opts.LogLevel = LOG_DEBUG 217 tcpAddr, _, nsqd := mustStartNSQD(opts) 218 defer os.RemoveAll(opts.DataPath) 219 defer nsqd.Exit() 220 221 conn, err := mustConnectNSQD(tcpAddr) 222 test.Nil(t, err) 223 defer conn.Close() 224 225 identify(t, conn, nil, frameTypeResponse) 226 sub(t, conn, topicName, "ch") 227 228 time.Sleep(150 * time.Millisecond) 229 230 // depending on timing there may be 1 or 2 hearbeats sent 231 // just read until we get an error 232 timer := time.After(100 * time.Millisecond) 233 for { 234 select { 235 case <-timer: 236 t.Fatalf("test timed out") 237 default: 238 _, err := nsq.ReadResponse(conn) 239 if err != nil { 240 goto done 241 } 242 } 243 } 244 done: 245 } 246 247 func TestClientHeartbeat(t *testing.T) { 248 topicName := "test_hb_v2" + strconv.Itoa(int(time.Now().Unix())) 249 250 opts := NewOptions() 251 opts.Logger = test.NewTestLogger(t) 252 opts.ClientTimeout = 200 * time.Millisecond 253 tcpAddr, _, nsqd := mustStartNSQD(opts) 254 defer os.RemoveAll(opts.DataPath) 255 defer nsqd.Exit() 256 257 conn, err := mustConnectNSQD(tcpAddr) 258 test.Nil(t, err) 259 defer conn.Close() 260 261 identify(t, conn, nil, frameTypeResponse) 262 sub(t, conn, topicName, "ch") 263 264 _, err = nsq.Ready(1).WriteTo(conn) 265 test.Nil(t, err) 266 267 resp, _ := nsq.ReadResponse(conn) 268 _, data, _ := nsq.UnpackResponse(resp) 269 test.Equal(t, []byte("_heartbeat_"), data) 270 271 time.Sleep(20 * time.Millisecond) 272 273 _, err = nsq.Nop().WriteTo(conn) 274 test.Nil(t, err) 275 276 // wait long enough that would have timed out (had we not sent the above cmd) 277 time.Sleep(100 * time.Millisecond) 278 279 _, err = nsq.Nop().WriteTo(conn) 280 test.Nil(t, err) 281 } 282 283 func TestClientHeartbeatDisableSUB(t *testing.T) { 284 topicName := "test_hb_v2" + strconv.Itoa(int(time.Now().Unix())) 285 286 opts := NewOptions() 287 opts.Logger = test.NewTestLogger(t) 288 opts.ClientTimeout = 200 * time.Millisecond 289 opts.LogLevel = LOG_DEBUG 290 tcpAddr, _, nsqd := mustStartNSQD(opts) 291 defer os.RemoveAll(opts.DataPath) 292 defer nsqd.Exit() 293 294 conn, err := mustConnectNSQD(tcpAddr) 295 test.Nil(t, err) 296 defer conn.Close() 297 298 identify(t, conn, map[string]interface{}{ 299 "heartbeat_interval": -1, 300 }, frameTypeResponse) 301 subFail(t, conn, topicName, "ch") 302 } 303 304 func TestClientHeartbeatDisable(t *testing.T) { 305 opts := NewOptions() 306 opts.Logger = test.NewTestLogger(t) 307 opts.ClientTimeout = 100 * time.Millisecond 308 tcpAddr, _, nsqd := mustStartNSQD(opts) 309 defer os.RemoveAll(opts.DataPath) 310 defer nsqd.Exit() 311 312 conn, err := mustConnectNSQD(tcpAddr) 313 test.Nil(t, err) 314 defer conn.Close() 315 316 identify(t, conn, map[string]interface{}{ 317 "heartbeat_interval": -1, 318 }, frameTypeResponse) 319 320 time.Sleep(150 * time.Millisecond) 321 322 _, err = nsq.Nop().WriteTo(conn) 323 test.Nil(t, err) 324 } 325 326 func TestMaxHeartbeatIntervalValid(t *testing.T) { 327 opts := NewOptions() 328 opts.Logger = test.NewTestLogger(t) 329 opts.MaxHeartbeatInterval = 300 * time.Second 330 tcpAddr, _, nsqd := mustStartNSQD(opts) 331 defer os.RemoveAll(opts.DataPath) 332 defer nsqd.Exit() 333 334 conn, err := mustConnectNSQD(tcpAddr) 335 test.Nil(t, err) 336 defer conn.Close() 337 338 hbi := int(opts.MaxHeartbeatInterval / time.Millisecond) 339 identify(t, conn, map[string]interface{}{ 340 "heartbeat_interval": hbi, 341 }, frameTypeResponse) 342 } 343 344 func TestMaxHeartbeatIntervalInvalid(t *testing.T) { 345 opts := NewOptions() 346 opts.Logger = test.NewTestLogger(t) 347 opts.MaxHeartbeatInterval = 300 * time.Second 348 tcpAddr, _, nsqd := mustStartNSQD(opts) 349 defer os.RemoveAll(opts.DataPath) 350 defer nsqd.Exit() 351 352 conn, err := mustConnectNSQD(tcpAddr) 353 test.Nil(t, err) 354 defer conn.Close() 355 356 hbi := int(opts.MaxHeartbeatInterval/time.Millisecond + 1) 357 data := identify(t, conn, map[string]interface{}{ 358 "heartbeat_interval": hbi, 359 }, frameTypeError) 360 test.Equal(t, "E_BAD_BODY IDENTIFY heartbeat interval (300001) is invalid", string(data)) 361 } 362 363 func TestPausing(t *testing.T) { 364 topicName := "test_pause_v2" + strconv.Itoa(int(time.Now().Unix())) 365 366 opts := NewOptions() 367 opts.Logger = test.NewTestLogger(t) 368 tcpAddr, _, nsqd := mustStartNSQD(opts) 369 defer os.RemoveAll(opts.DataPath) 370 defer nsqd.Exit() 371 372 conn, err := mustConnectNSQD(tcpAddr) 373 test.Nil(t, err) 374 defer conn.Close() 375 376 identify(t, conn, nil, frameTypeResponse) 377 sub(t, conn, topicName, "ch") 378 379 _, err = nsq.Ready(1).WriteTo(conn) 380 test.Nil(t, err) 381 382 topic := nsqd.GetTopic(topicName) 383 msg := NewMessage(topic.GenerateID(), []byte("test body")) 384 channel := topic.GetChannel("ch") 385 topic.PutMessage(msg) 386 387 // receive the first message via the client, finish it, and send new RDY 388 resp, _ := nsq.ReadResponse(conn) 389 _, data, _ := nsq.UnpackResponse(resp) 390 msg, _ = decodeMessage(data) 391 test.Equal(t, []byte("test body"), msg.Body) 392 393 _, err = nsq.Finish(nsq.MessageID(msg.ID)).WriteTo(conn) 394 test.Nil(t, err) 395 396 _, err = nsq.Ready(1).WriteTo(conn) 397 test.Nil(t, err) 398 399 // sleep to allow the RDY state to take effect 400 time.Sleep(50 * time.Millisecond) 401 402 // pause the channel... the client shouldn't receive any more messages 403 channel.Pause() 404 405 // sleep to allow the paused state to take effect 406 time.Sleep(50 * time.Millisecond) 407 408 msg = NewMessage(topic.GenerateID(), []byte("test body2")) 409 topic.PutMessage(msg) 410 411 // allow the client to possibly get a message, the test would hang indefinitely 412 // if pausing was not working 413 time.Sleep(50 * time.Millisecond) 414 msg = <-channel.memoryMsgChan 415 test.Equal(t, []byte("test body2"), msg.Body) 416 417 // unpause the channel... the client should now be pushed a message 418 channel.UnPause() 419 420 msg = NewMessage(topic.GenerateID(), []byte("test body3")) 421 topic.PutMessage(msg) 422 423 resp, _ = nsq.ReadResponse(conn) 424 _, data, _ = nsq.UnpackResponse(resp) 425 msg, _ = decodeMessage(data) 426 test.Equal(t, []byte("test body3"), msg.Body) 427 } 428 429 func TestEmptyCommand(t *testing.T) { 430 opts := NewOptions() 431 opts.Logger = test.NewTestLogger(t) 432 tcpAddr, _, nsqd := mustStartNSQD(opts) 433 defer os.RemoveAll(opts.DataPath) 434 defer nsqd.Exit() 435 436 conn, err := mustConnectNSQD(tcpAddr) 437 test.Nil(t, err) 438 defer conn.Close() 439 440 _, err = conn.Write([]byte("\n\n")) 441 test.Nil(t, err) 442 443 // if we didn't panic here we're good, see issue #120 444 } 445 446 func TestSizeLimits(t *testing.T) { 447 opts := NewOptions() 448 opts.Logger = test.NewTestLogger(t) 449 opts.LogLevel = LOG_DEBUG 450 opts.MaxMsgSize = 100 451 opts.MaxBodySize = 1000 452 tcpAddr, _, nsqd := mustStartNSQD(opts) 453 defer os.RemoveAll(opts.DataPath) 454 defer nsqd.Exit() 455 456 conn, err := mustConnectNSQD(tcpAddr) 457 test.Nil(t, err) 458 defer conn.Close() 459 460 topicName := "test_limits_v2" + strconv.Itoa(int(time.Now().Unix())) 461 462 identify(t, conn, nil, frameTypeResponse) 463 sub(t, conn, topicName, "ch") 464 465 // PUB that's valid 466 nsq.Publish(topicName, make([]byte, 95)).WriteTo(conn) 467 resp, _ := nsq.ReadResponse(conn) 468 frameType, data, _ := nsq.UnpackResponse(resp) 469 t.Logf("frameType: %d, data: %s", frameType, data) 470 test.Equal(t, frameTypeResponse, frameType) 471 test.Equal(t, []byte("OK"), data) 472 473 // PUB that's invalid (too big) 474 nsq.Publish(topicName, make([]byte, 105)).WriteTo(conn) 475 resp, _ = nsq.ReadResponse(conn) 476 frameType, data, _ = nsq.UnpackResponse(resp) 477 t.Logf("frameType: %d, data: %s", frameType, data) 478 test.Equal(t, frameTypeError, frameType) 479 test.Equal(t, "E_BAD_MESSAGE PUB message too big 105 > 100", string(data)) 480 481 // need to reconnect 482 conn, err = mustConnectNSQD(tcpAddr) 483 test.Nil(t, err) 484 defer conn.Close() 485 486 // PUB thats empty 487 nsq.Publish(topicName, []byte{}).WriteTo(conn) 488 resp, _ = nsq.ReadResponse(conn) 489 frameType, data, _ = nsq.UnpackResponse(resp) 490 t.Logf("frameType: %d, data: %s", frameType, data) 491 test.Equal(t, frameTypeError, frameType) 492 test.Equal(t, "E_BAD_MESSAGE PUB invalid message body size 0", string(data)) 493 494 // need to reconnect 495 conn, err = mustConnectNSQD(tcpAddr) 496 test.Nil(t, err) 497 defer conn.Close() 498 499 // MPUB body that's valid 500 mpub := make([][]byte, 5) 501 for i := range mpub { 502 mpub[i] = make([]byte, 100) 503 } 504 cmd, _ := nsq.MultiPublish(topicName, mpub) 505 cmd.WriteTo(conn) 506 resp, _ = nsq.ReadResponse(conn) 507 frameType, data, _ = nsq.UnpackResponse(resp) 508 t.Logf("frameType: %d, data: %s", frameType, data) 509 test.Equal(t, frameTypeResponse, frameType) 510 test.Equal(t, []byte("OK"), data) 511 512 // MPUB body that's invalid (body too big) 513 mpub = make([][]byte, 11) 514 for i := range mpub { 515 mpub[i] = make([]byte, 100) 516 } 517 cmd, _ = nsq.MultiPublish(topicName, mpub) 518 cmd.WriteTo(conn) 519 resp, _ = nsq.ReadResponse(conn) 520 frameType, data, _ = nsq.UnpackResponse(resp) 521 t.Logf("frameType: %d, data: %s", frameType, data) 522 test.Equal(t, frameTypeError, frameType) 523 test.Equal(t, "E_BAD_BODY MPUB body too big 1148 > 1000", string(data)) 524 525 // need to reconnect 526 conn, err = mustConnectNSQD(tcpAddr) 527 test.Nil(t, err) 528 defer conn.Close() 529 530 // MPUB that's invalid (one message empty) 531 mpub = make([][]byte, 5) 532 for i := range mpub { 533 mpub[i] = make([]byte, 100) 534 } 535 mpub = append(mpub, []byte{}) 536 cmd, _ = nsq.MultiPublish(topicName, mpub) 537 cmd.WriteTo(conn) 538 resp, _ = nsq.ReadResponse(conn) 539 frameType, data, _ = nsq.UnpackResponse(resp) 540 t.Logf("frameType: %d, data: %s", frameType, data) 541 test.Equal(t, frameTypeError, frameType) 542 test.Equal(t, "E_BAD_MESSAGE MPUB invalid message(5) body size 0", string(data)) 543 544 // need to reconnect 545 conn, err = mustConnectNSQD(tcpAddr) 546 test.Nil(t, err) 547 defer conn.Close() 548 549 // MPUB body that's invalid (one of the messages is too big) 550 mpub = make([][]byte, 5) 551 for i := range mpub { 552 mpub[i] = make([]byte, 101) 553 } 554 cmd, _ = nsq.MultiPublish(topicName, mpub) 555 cmd.WriteTo(conn) 556 resp, _ = nsq.ReadResponse(conn) 557 frameType, data, _ = nsq.UnpackResponse(resp) 558 t.Logf("frameType: %d, data: %s", frameType, data) 559 test.Equal(t, frameTypeError, frameType) 560 test.Equal(t, "E_BAD_MESSAGE MPUB message too big 101 > 100", string(data)) 561 } 562 563 func TestDPUB(t *testing.T) { 564 opts := NewOptions() 565 opts.Logger = test.NewTestLogger(t) 566 opts.LogLevel = LOG_DEBUG 567 tcpAddr, _, nsqd := mustStartNSQD(opts) 568 defer os.RemoveAll(opts.DataPath) 569 defer nsqd.Exit() 570 571 conn, err := mustConnectNSQD(tcpAddr) 572 test.Nil(t, err) 573 defer conn.Close() 574 575 topicName := "test_dpub_v2" + strconv.Itoa(int(time.Now().Unix())) 576 577 identify(t, conn, nil, frameTypeResponse) 578 sub(t, conn, topicName, "ch") 579 580 // valid 581 nsq.DeferredPublish(topicName, time.Second, make([]byte, 100)).WriteTo(conn) 582 resp, _ := nsq.ReadResponse(conn) 583 frameType, data, _ := nsq.UnpackResponse(resp) 584 t.Logf("frameType: %d, data: %s", frameType, data) 585 test.Equal(t, frameTypeResponse, frameType) 586 test.Equal(t, []byte("OK"), data) 587 588 time.Sleep(25 * time.Millisecond) 589 590 ch := nsqd.GetTopic(topicName).GetChannel("ch") 591 ch.deferredMutex.Lock() 592 numDef := len(ch.deferredMessages) 593 ch.deferredMutex.Unlock() 594 test.Equal(t, 1, numDef) 595 test.Equal(t, 1, int(atomic.LoadUint64(&ch.messageCount))) 596 597 // duration out of range 598 nsq.DeferredPublish(topicName, opts.MaxReqTimeout+100*time.Millisecond, make([]byte, 100)).WriteTo(conn) 599 resp, _ = nsq.ReadResponse(conn) 600 frameType, data, _ = nsq.UnpackResponse(resp) 601 t.Logf("frameType: %d, data: %s", frameType, data) 602 test.Equal(t, frameTypeError, frameType) 603 test.Equal(t, "E_INVALID DPUB timeout 3600100 out of range 0-3600000", string(data)) 604 } 605 606 func TestTouch(t *testing.T) { 607 opts := NewOptions() 608 opts.Logger = test.NewTestLogger(t) 609 opts.LogLevel = LOG_DEBUG 610 opts.MsgTimeout = 150 * time.Millisecond 611 tcpAddr, _, nsqd := mustStartNSQD(opts) 612 defer os.RemoveAll(opts.DataPath) 613 defer nsqd.Exit() 614 615 topicName := "test_touch" + strconv.Itoa(int(time.Now().Unix())) 616 617 conn, err := mustConnectNSQD(tcpAddr) 618 test.Nil(t, err) 619 defer conn.Close() 620 621 identify(t, conn, nil, frameTypeResponse) 622 sub(t, conn, topicName, "ch") 623 624 topic := nsqd.GetTopic(topicName) 625 channel := topic.GetChannel("ch") 626 msg := NewMessage(topic.GenerateID(), []byte("test body")) 627 topic.PutMessage(msg) 628 629 _, err = nsq.Ready(1).WriteTo(conn) 630 test.Nil(t, err) 631 632 resp, err := nsq.ReadResponse(conn) 633 test.Nil(t, err) 634 frameType, data, _ := nsq.UnpackResponse(resp) 635 msgOut, _ := decodeMessage(data) 636 test.Equal(t, frameTypeMessage, frameType) 637 test.Equal(t, msg.ID, msgOut.ID) 638 639 time.Sleep(75 * time.Millisecond) 640 641 _, err = nsq.Touch(nsq.MessageID(msg.ID)).WriteTo(conn) 642 test.Nil(t, err) 643 644 time.Sleep(75 * time.Millisecond) 645 646 _, err = nsq.Finish(nsq.MessageID(msg.ID)).WriteTo(conn) 647 test.Nil(t, err) 648 649 test.Equal(t, uint64(0), channel.timeoutCount) 650 } 651 652 func TestMaxRdyCount(t *testing.T) { 653 opts := NewOptions() 654 opts.Logger = test.NewTestLogger(t) 655 opts.LogLevel = LOG_DEBUG 656 opts.MaxRdyCount = 50 657 tcpAddr, _, nsqd := mustStartNSQD(opts) 658 defer os.RemoveAll(opts.DataPath) 659 defer nsqd.Exit() 660 661 topicName := "test_max_rdy_count" + strconv.Itoa(int(time.Now().Unix())) 662 663 conn, err := mustConnectNSQD(tcpAddr) 664 test.Nil(t, err) 665 defer conn.Close() 666 667 topic := nsqd.GetTopic(topicName) 668 msg := NewMessage(topic.GenerateID(), []byte("test body")) 669 topic.PutMessage(msg) 670 671 data := identify(t, conn, nil, frameTypeResponse) 672 r := struct { 673 MaxRdyCount int64 `json:"max_rdy_count"` 674 }{} 675 err = json.Unmarshal(data, &r) 676 test.Nil(t, err) 677 test.Equal(t, int64(50), r.MaxRdyCount) 678 sub(t, conn, topicName, "ch") 679 680 _, err = nsq.Ready(int(opts.MaxRdyCount)).WriteTo(conn) 681 test.Nil(t, err) 682 683 resp, err := nsq.ReadResponse(conn) 684 test.Nil(t, err) 685 frameType, data, _ := nsq.UnpackResponse(resp) 686 msgOut, _ := decodeMessage(data) 687 test.Equal(t, frameTypeMessage, frameType) 688 test.Equal(t, msg.ID, msgOut.ID) 689 690 _, err = nsq.Ready(int(opts.MaxRdyCount) + 1).WriteTo(conn) 691 test.Nil(t, err) 692 693 resp, err = nsq.ReadResponse(conn) 694 test.Nil(t, err) 695 frameType, data, _ = nsq.UnpackResponse(resp) 696 test.Equal(t, int32(1), frameType) 697 test.Equal(t, "E_INVALID RDY count 51 out of range 0-50", string(data)) 698 } 699 700 func TestFatalError(t *testing.T) { 701 opts := NewOptions() 702 opts.Logger = test.NewTestLogger(t) 703 tcpAddr, _, nsqd := mustStartNSQD(opts) 704 defer os.RemoveAll(opts.DataPath) 705 defer nsqd.Exit() 706 707 conn, err := mustConnectNSQD(tcpAddr) 708 test.Nil(t, err) 709 defer conn.Close() 710 711 _, err = conn.Write([]byte("ASDF\n")) 712 test.Nil(t, err) 713 714 resp, err := nsq.ReadResponse(conn) 715 test.Nil(t, err) 716 frameType, data, _ := nsq.UnpackResponse(resp) 717 test.Equal(t, int32(1), frameType) 718 test.Equal(t, "E_INVALID invalid command ASDF", string(data)) 719 720 _, err = nsq.ReadResponse(conn) 721 test.NotNil(t, err) 722 } 723 724 func TestOutputBuffering(t *testing.T) { 725 opts := NewOptions() 726 opts.Logger = test.NewTestLogger(t) 727 opts.LogLevel = LOG_DEBUG 728 opts.MaxOutputBufferSize = 512 * 1024 729 opts.MaxOutputBufferTimeout = time.Second 730 tcpAddr, _, nsqd := mustStartNSQD(opts) 731 defer os.RemoveAll(opts.DataPath) 732 defer nsqd.Exit() 733 734 topicName := "test_output_buffering" + strconv.Itoa(int(time.Now().Unix())) 735 736 conn, err := mustConnectNSQD(tcpAddr) 737 test.Nil(t, err) 738 defer conn.Close() 739 740 outputBufferSize := 256 * 1024 741 outputBufferTimeout := 500 742 743 topic := nsqd.GetTopic(topicName) 744 msg := NewMessage(topic.GenerateID(), make([]byte, outputBufferSize-1024)) 745 topic.PutMessage(msg) 746 747 start := time.Now() 748 data := identify(t, conn, map[string]interface{}{ 749 "output_buffer_size": outputBufferSize, 750 "output_buffer_timeout": outputBufferTimeout, 751 }, frameTypeResponse) 752 var decoded map[string]interface{} 753 json.Unmarshal(data, &decoded) 754 v, ok := decoded["output_buffer_size"] 755 test.Equal(t, true, ok) 756 test.Equal(t, outputBufferSize, int(v.(float64))) 757 v = decoded["output_buffer_timeout"] 758 test.Equal(t, outputBufferTimeout, int(v.(float64))) 759 sub(t, conn, topicName, "ch") 760 761 _, err = nsq.Ready(10).WriteTo(conn) 762 test.Nil(t, err) 763 764 resp, err := nsq.ReadResponse(conn) 765 test.Nil(t, err) 766 end := time.Now() 767 768 test.Equal(t, true, int(end.Sub(start)/time.Millisecond) >= outputBufferTimeout) 769 770 frameType, data, _ := nsq.UnpackResponse(resp) 771 msgOut, _ := decodeMessage(data) 772 test.Equal(t, frameTypeMessage, frameType) 773 test.Equal(t, msg.ID, msgOut.ID) 774 } 775 776 func TestOutputBufferingValidity(t *testing.T) { 777 opts := NewOptions() 778 opts.Logger = test.NewTestLogger(t) 779 opts.LogLevel = LOG_DEBUG 780 opts.MaxOutputBufferSize = 512 * 1024 781 opts.MaxOutputBufferTimeout = time.Second 782 tcpAddr, _, nsqd := mustStartNSQD(opts) 783 defer os.RemoveAll(opts.DataPath) 784 defer nsqd.Exit() 785 786 conn, err := mustConnectNSQD(tcpAddr) 787 test.Nil(t, err) 788 defer conn.Close() 789 790 identify(t, conn, map[string]interface{}{ 791 "output_buffer_size": 512 * 1024, 792 "output_buffer_timeout": 1000, 793 }, frameTypeResponse) 794 identify(t, conn, map[string]interface{}{ 795 "output_buffer_size": -1, 796 "output_buffer_timeout": -1, 797 }, frameTypeResponse) 798 identify(t, conn, map[string]interface{}{ 799 "output_buffer_size": 0, 800 "output_buffer_timeout": 0, 801 }, frameTypeResponse) 802 data := identify(t, conn, map[string]interface{}{ 803 "output_buffer_size": 512*1024 + 1, 804 "output_buffer_timeout": 0, 805 }, frameTypeError) 806 test.Equal(t, fmt.Sprintf("E_BAD_BODY IDENTIFY output buffer size (%d) is invalid", 512*1024+1), string(data)) 807 808 conn, err = mustConnectNSQD(tcpAddr) 809 test.Nil(t, err) 810 defer conn.Close() 811 812 data = identify(t, conn, map[string]interface{}{ 813 "output_buffer_size": 0, 814 "output_buffer_timeout": 1001, 815 }, frameTypeError) 816 test.Equal(t, "E_BAD_BODY IDENTIFY output buffer timeout (1001) is invalid", string(data)) 817 } 818 819 func TestTLS(t *testing.T) { 820 opts := NewOptions() 821 opts.Logger = test.NewTestLogger(t) 822 opts.LogLevel = LOG_DEBUG 823 opts.TLSCert = "./test/certs/server.pem" 824 opts.TLSKey = "./test/certs/server.key" 825 tcpAddr, _, nsqd := mustStartNSQD(opts) 826 defer os.RemoveAll(opts.DataPath) 827 defer nsqd.Exit() 828 829 conn, err := mustConnectNSQD(tcpAddr) 830 test.Nil(t, err) 831 defer conn.Close() 832 833 data := identify(t, conn, map[string]interface{}{ 834 "tls_v1": true, 835 }, frameTypeResponse) 836 r := struct { 837 TLSv1 bool `json:"tls_v1"` 838 }{} 839 err = json.Unmarshal(data, &r) 840 test.Nil(t, err) 841 test.Equal(t, true, r.TLSv1) 842 843 tlsConfig := &tls.Config{ 844 InsecureSkipVerify: true, 845 } 846 tlsConn := tls.Client(conn, tlsConfig) 847 848 err = tlsConn.Handshake() 849 test.Nil(t, err) 850 851 resp, _ := nsq.ReadResponse(tlsConn) 852 frameType, data, _ := nsq.UnpackResponse(resp) 853 t.Logf("frameType: %d, data: %s", frameType, data) 854 test.Equal(t, frameTypeResponse, frameType) 855 test.Equal(t, []byte("OK"), data) 856 } 857 858 func TestTLSRequired(t *testing.T) { 859 opts := NewOptions() 860 opts.Logger = test.NewTestLogger(t) 861 opts.LogLevel = LOG_DEBUG 862 opts.TLSCert = "./test/certs/server.pem" 863 opts.TLSKey = "./test/certs/server.key" 864 opts.TLSRequired = TLSRequiredExceptHTTP 865 866 tcpAddr, _, nsqd := mustStartNSQD(opts) 867 defer os.RemoveAll(opts.DataPath) 868 defer nsqd.Exit() 869 870 topicName := "test_tls_required" + strconv.Itoa(int(time.Now().Unix())) 871 872 conn, err := mustConnectNSQD(tcpAddr) 873 test.Nil(t, err) 874 defer conn.Close() 875 876 subFail(t, conn, topicName, "ch") 877 878 conn, err = mustConnectNSQD(tcpAddr) 879 test.Nil(t, err) 880 defer conn.Close() 881 882 data := identify(t, conn, map[string]interface{}{ 883 "tls_v1": true, 884 }, frameTypeResponse) 885 r := struct { 886 TLSv1 bool `json:"tls_v1"` 887 }{} 888 err = json.Unmarshal(data, &r) 889 test.Nil(t, err) 890 test.Equal(t, true, r.TLSv1) 891 892 tlsConfig := &tls.Config{ 893 InsecureSkipVerify: true, 894 } 895 tlsConn := tls.Client(conn, tlsConfig) 896 897 err = tlsConn.Handshake() 898 test.Nil(t, err) 899 900 resp, _ := nsq.ReadResponse(tlsConn) 901 frameType, data, _ := nsq.UnpackResponse(resp) 902 t.Logf("frameType: %d, data: %s", frameType, data) 903 test.Equal(t, frameTypeResponse, frameType) 904 test.Equal(t, []byte("OK"), data) 905 } 906 907 func TestTLSAuthRequire(t *testing.T) { 908 opts := NewOptions() 909 opts.Logger = test.NewTestLogger(t) 910 opts.LogLevel = LOG_DEBUG 911 opts.TLSCert = "./test/certs/server.pem" 912 opts.TLSKey = "./test/certs/server.key" 913 opts.TLSClientAuthPolicy = "require" 914 915 tcpAddr, _, nsqd := mustStartNSQD(opts) 916 defer os.RemoveAll(opts.DataPath) 917 defer nsqd.Exit() 918 919 // No Certs 920 conn, err := mustConnectNSQD(tcpAddr) 921 test.Nil(t, err) 922 defer conn.Close() 923 924 data := identify(t, conn, map[string]interface{}{ 925 "tls_v1": true, 926 }, frameTypeResponse) 927 r := struct { 928 TLSv1 bool `json:"tls_v1"` 929 }{} 930 err = json.Unmarshal(data, &r) 931 test.Nil(t, err) 932 test.Equal(t, true, r.TLSv1) 933 tlsConfig := &tls.Config{ 934 InsecureSkipVerify: true, 935 } 936 tlsConn := tls.Client(conn, tlsConfig) 937 _, err = nsq.ReadResponse(tlsConn) 938 test.NotNil(t, err) 939 940 // With Unsigned Cert 941 conn, err = mustConnectNSQD(tcpAddr) 942 test.Nil(t, err) 943 defer conn.Close() 944 945 data = identify(t, conn, map[string]interface{}{ 946 "tls_v1": true, 947 }, frameTypeResponse) 948 r = struct { 949 TLSv1 bool `json:"tls_v1"` 950 }{} 951 err = json.Unmarshal(data, &r) 952 test.Nil(t, err) 953 test.Equal(t, true, r.TLSv1) 954 955 cert, err := tls.LoadX509KeyPair("./test/certs/cert.pem", "./test/certs/key.pem") 956 test.Nil(t, err) 957 tlsConfig = &tls.Config{ 958 Certificates: []tls.Certificate{cert}, 959 InsecureSkipVerify: true, 960 } 961 tlsConn = tls.Client(conn, tlsConfig) 962 err = tlsConn.Handshake() 963 test.Nil(t, err) 964 965 resp, _ := nsq.ReadResponse(tlsConn) 966 frameType, data, _ := nsq.UnpackResponse(resp) 967 t.Logf("frameType: %d, data: %s", frameType, data) 968 test.Equal(t, frameTypeResponse, frameType) 969 test.Equal(t, []byte("OK"), data) 970 971 } 972 973 func TestTLSAuthRequireVerify(t *testing.T) { 974 opts := NewOptions() 975 opts.Logger = test.NewTestLogger(t) 976 opts.LogLevel = LOG_DEBUG 977 opts.TLSCert = "./test/certs/server.pem" 978 opts.TLSKey = "./test/certs/server.key" 979 opts.TLSRootCAFile = "./test/certs/ca.pem" 980 opts.TLSClientAuthPolicy = "require-verify" 981 982 tcpAddr, _, nsqd := mustStartNSQD(opts) 983 defer os.RemoveAll(opts.DataPath) 984 defer nsqd.Exit() 985 986 // with no cert 987 conn, err := mustConnectNSQD(tcpAddr) 988 test.Nil(t, err) 989 defer conn.Close() 990 991 data := identify(t, conn, map[string]interface{}{ 992 "tls_v1": true, 993 }, frameTypeResponse) 994 r := struct { 995 TLSv1 bool `json:"tls_v1"` 996 }{} 997 err = json.Unmarshal(data, &r) 998 test.Nil(t, err) 999 test.Equal(t, true, r.TLSv1) 1000 tlsConfig := &tls.Config{ 1001 InsecureSkipVerify: true, 1002 } 1003 tlsConn := tls.Client(conn, tlsConfig) 1004 _, err = nsq.ReadResponse(tlsConn) 1005 test.NotNil(t, err) 1006 1007 // with invalid cert 1008 conn, err = mustConnectNSQD(tcpAddr) 1009 test.Nil(t, err) 1010 defer conn.Close() 1011 1012 data = identify(t, conn, map[string]interface{}{ 1013 "tls_v1": true, 1014 }, frameTypeResponse) 1015 r = struct { 1016 TLSv1 bool `json:"tls_v1"` 1017 }{} 1018 err = json.Unmarshal(data, &r) 1019 test.Nil(t, err) 1020 test.Equal(t, true, r.TLSv1) 1021 cert, err := tls.LoadX509KeyPair("./test/certs/cert.pem", "./test/certs/key.pem") 1022 test.Nil(t, err) 1023 tlsConfig = &tls.Config{ 1024 Certificates: []tls.Certificate{cert}, 1025 InsecureSkipVerify: true, 1026 } 1027 tlsConn = tls.Client(conn, tlsConfig) 1028 _, err = nsq.ReadResponse(tlsConn) 1029 test.NotNil(t, err) 1030 1031 // with valid cert 1032 conn, err = mustConnectNSQD(tcpAddr) 1033 test.Nil(t, err) 1034 defer conn.Close() 1035 1036 data = identify(t, conn, map[string]interface{}{ 1037 "tls_v1": true, 1038 }, frameTypeResponse) 1039 r = struct { 1040 TLSv1 bool `json:"tls_v1"` 1041 }{} 1042 err = json.Unmarshal(data, &r) 1043 test.Nil(t, err) 1044 test.Equal(t, true, r.TLSv1) 1045 cert, err = tls.LoadX509KeyPair("./test/certs/client.pem", "./test/certs/client.key") 1046 test.Nil(t, err) 1047 tlsConfig = &tls.Config{ 1048 Certificates: []tls.Certificate{cert}, 1049 InsecureSkipVerify: true, 1050 } 1051 tlsConn = tls.Client(conn, tlsConfig) 1052 err = tlsConn.Handshake() 1053 test.Nil(t, err) 1054 1055 resp, _ := nsq.ReadResponse(tlsConn) 1056 frameType, data, _ := nsq.UnpackResponse(resp) 1057 t.Logf("frameType: %d, data: %s", frameType, data) 1058 test.Equal(t, frameTypeResponse, frameType) 1059 test.Equal(t, []byte("OK"), data) 1060 } 1061 1062 func TestDeflate(t *testing.T) { 1063 opts := NewOptions() 1064 opts.Logger = test.NewTestLogger(t) 1065 opts.LogLevel = LOG_DEBUG 1066 opts.DeflateEnabled = true 1067 tcpAddr, _, nsqd := mustStartNSQD(opts) 1068 defer os.RemoveAll(opts.DataPath) 1069 defer nsqd.Exit() 1070 1071 conn, err := mustConnectNSQD(tcpAddr) 1072 test.Nil(t, err) 1073 defer conn.Close() 1074 1075 data := identify(t, conn, map[string]interface{}{ 1076 "deflate": true, 1077 }, frameTypeResponse) 1078 r := struct { 1079 Deflate bool `json:"deflate"` 1080 }{} 1081 err = json.Unmarshal(data, &r) 1082 test.Nil(t, err) 1083 test.Equal(t, true, r.Deflate) 1084 1085 compressConn := flate.NewReader(conn) 1086 resp, _ := nsq.ReadResponse(compressConn) 1087 frameType, data, _ := nsq.UnpackResponse(resp) 1088 t.Logf("frameType: %d, data: %s", frameType, data) 1089 test.Equal(t, frameTypeResponse, frameType) 1090 test.Equal(t, []byte("OK"), data) 1091 } 1092 1093 type readWriter struct { 1094 io.Reader 1095 io.Writer 1096 } 1097 1098 func TestSnappy(t *testing.T) { 1099 opts := NewOptions() 1100 opts.Logger = test.NewTestLogger(t) 1101 opts.LogLevel = LOG_DEBUG 1102 opts.SnappyEnabled = true 1103 tcpAddr, _, nsqd := mustStartNSQD(opts) 1104 defer os.RemoveAll(opts.DataPath) 1105 defer nsqd.Exit() 1106 1107 conn, err := mustConnectNSQD(tcpAddr) 1108 test.Nil(t, err) 1109 defer conn.Close() 1110 1111 data := identify(t, conn, map[string]interface{}{ 1112 "snappy": true, 1113 }, frameTypeResponse) 1114 r := struct { 1115 Snappy bool `json:"snappy"` 1116 }{} 1117 err = json.Unmarshal(data, &r) 1118 test.Nil(t, err) 1119 test.Equal(t, true, r.Snappy) 1120 1121 compressConn := snappy.NewReader(conn) 1122 resp, _ := nsq.ReadResponse(compressConn) 1123 frameType, data, _ := nsq.UnpackResponse(resp) 1124 t.Logf("frameType: %d, data: %s", frameType, data) 1125 test.Equal(t, frameTypeResponse, frameType) 1126 test.Equal(t, []byte("OK"), data) 1127 1128 msgBody := make([]byte, 128000) 1129 //lint:ignore SA1019 NewWriter is deprecated by NewBufferedWriter, but we don't want to buffer 1130 w := snappy.NewWriter(conn) 1131 1132 rw := readWriter{compressConn, w} 1133 1134 topicName := "test_snappy" + strconv.Itoa(int(time.Now().Unix())) 1135 sub(t, rw, topicName, "ch") 1136 1137 _, err = nsq.Ready(1).WriteTo(rw) 1138 test.Nil(t, err) 1139 1140 topic := nsqd.GetTopic(topicName) 1141 msg := NewMessage(topic.GenerateID(), msgBody) 1142 topic.PutMessage(msg) 1143 1144 resp, _ = nsq.ReadResponse(compressConn) 1145 frameType, data, _ = nsq.UnpackResponse(resp) 1146 msgOut, _ := decodeMessage(data) 1147 test.Equal(t, frameTypeMessage, frameType) 1148 test.Equal(t, msg.ID, msgOut.ID) 1149 test.Equal(t, msg.Body, msgOut.Body) 1150 } 1151 1152 func TestTLSDeflate(t *testing.T) { 1153 opts := NewOptions() 1154 opts.Logger = test.NewTestLogger(t) 1155 opts.LogLevel = LOG_DEBUG 1156 opts.DeflateEnabled = true 1157 opts.TLSCert = "./test/certs/cert.pem" 1158 opts.TLSKey = "./test/certs/key.pem" 1159 tcpAddr, _, nsqd := mustStartNSQD(opts) 1160 defer os.RemoveAll(opts.DataPath) 1161 defer nsqd.Exit() 1162 1163 conn, err := mustConnectNSQD(tcpAddr) 1164 test.Nil(t, err) 1165 defer conn.Close() 1166 1167 data := identify(t, conn, map[string]interface{}{ 1168 "tls_v1": true, 1169 "deflate": true, 1170 }, frameTypeResponse) 1171 r := struct { 1172 TLSv1 bool `json:"tls_v1"` 1173 Deflate bool `json:"deflate"` 1174 }{} 1175 err = json.Unmarshal(data, &r) 1176 test.Nil(t, err) 1177 test.Equal(t, true, r.TLSv1) 1178 test.Equal(t, true, r.Deflate) 1179 1180 tlsConfig := &tls.Config{ 1181 InsecureSkipVerify: true, 1182 } 1183 tlsConn := tls.Client(conn, tlsConfig) 1184 1185 err = tlsConn.Handshake() 1186 test.Nil(t, err) 1187 1188 resp, _ := nsq.ReadResponse(tlsConn) 1189 frameType, data, _ := nsq.UnpackResponse(resp) 1190 t.Logf("frameType: %d, data: %s", frameType, data) 1191 test.Equal(t, frameTypeResponse, frameType) 1192 test.Equal(t, []byte("OK"), data) 1193 1194 compressConn := flate.NewReader(tlsConn) 1195 1196 resp, _ = nsq.ReadResponse(compressConn) 1197 frameType, data, _ = nsq.UnpackResponse(resp) 1198 t.Logf("frameType: %d, data: %s", frameType, data) 1199 test.Equal(t, frameTypeResponse, frameType) 1200 test.Equal(t, []byte("OK"), data) 1201 } 1202 1203 func TestSampling(t *testing.T) { 1204 rand.Seed(time.Now().UTC().UnixNano()) 1205 1206 num := 10000 1207 sampleRate := 42 1208 slack := 5 1209 1210 opts := NewOptions() 1211 opts.Logger = test.NewTestLogger(t) 1212 opts.LogLevel = LOG_DEBUG 1213 opts.MaxRdyCount = int64(num) 1214 tcpAddr, _, nsqd := mustStartNSQD(opts) 1215 defer os.RemoveAll(opts.DataPath) 1216 defer nsqd.Exit() 1217 1218 conn, err := mustConnectNSQD(tcpAddr) 1219 test.Nil(t, err) 1220 defer conn.Close() 1221 1222 data := identify(t, conn, map[string]interface{}{ 1223 "sample_rate": int32(sampleRate), 1224 }, frameTypeResponse) 1225 r := struct { 1226 SampleRate int32 `json:"sample_rate"` 1227 }{} 1228 err = json.Unmarshal(data, &r) 1229 test.Nil(t, err) 1230 test.Equal(t, int32(sampleRate), r.SampleRate) 1231 1232 topicName := "test_sampling" + strconv.Itoa(int(time.Now().Unix())) 1233 topic := nsqd.GetTopic(topicName) 1234 for i := 0; i < num; i++ { 1235 msg := NewMessage(topic.GenerateID(), []byte("test body")) 1236 topic.PutMessage(msg) 1237 } 1238 channel := topic.GetChannel("ch") 1239 1240 // let the topic drain into the channel 1241 time.Sleep(50 * time.Millisecond) 1242 1243 sub(t, conn, topicName, "ch") 1244 _, err = nsq.Ready(num).WriteTo(conn) 1245 test.Nil(t, err) 1246 1247 go func() { 1248 for { 1249 _, err := nsq.ReadResponse(conn) 1250 if err != nil { 1251 return 1252 } 1253 } 1254 }() 1255 1256 doneChan := make(chan int) 1257 go func() { 1258 for { 1259 if channel.Depth() == 0 { 1260 close(doneChan) 1261 return 1262 } 1263 time.Sleep(5 * time.Millisecond) 1264 } 1265 }() 1266 <-doneChan 1267 1268 channel.inFlightMutex.Lock() 1269 numInFlight := len(channel.inFlightMessages) 1270 channel.inFlightMutex.Unlock() 1271 1272 test.Equal(t, true, numInFlight <= int(float64(num)*float64(sampleRate+slack)/100.0)) 1273 test.Equal(t, true, numInFlight >= int(float64(num)*float64(sampleRate-slack)/100.0)) 1274 } 1275 1276 func TestTLSSnappy(t *testing.T) { 1277 opts := NewOptions() 1278 opts.Logger = test.NewTestLogger(t) 1279 opts.LogLevel = LOG_DEBUG 1280 opts.SnappyEnabled = true 1281 opts.TLSCert = "./test/certs/cert.pem" 1282 opts.TLSKey = "./test/certs/key.pem" 1283 tcpAddr, _, nsqd := mustStartNSQD(opts) 1284 defer os.RemoveAll(opts.DataPath) 1285 defer nsqd.Exit() 1286 1287 conn, err := mustConnectNSQD(tcpAddr) 1288 test.Nil(t, err) 1289 defer conn.Close() 1290 1291 data := identify(t, conn, map[string]interface{}{ 1292 "tls_v1": true, 1293 "snappy": true, 1294 }, frameTypeResponse) 1295 r := struct { 1296 TLSv1 bool `json:"tls_v1"` 1297 Snappy bool `json:"snappy"` 1298 }{} 1299 err = json.Unmarshal(data, &r) 1300 test.Nil(t, err) 1301 test.Equal(t, true, r.TLSv1) 1302 test.Equal(t, true, r.Snappy) 1303 1304 tlsConfig := &tls.Config{ 1305 InsecureSkipVerify: true, 1306 } 1307 tlsConn := tls.Client(conn, tlsConfig) 1308 1309 err = tlsConn.Handshake() 1310 test.Nil(t, err) 1311 1312 resp, _ := nsq.ReadResponse(tlsConn) 1313 frameType, data, _ := nsq.UnpackResponse(resp) 1314 t.Logf("frameType: %d, data: %s", frameType, data) 1315 test.Equal(t, frameTypeResponse, frameType) 1316 test.Equal(t, []byte("OK"), data) 1317 1318 compressConn := snappy.NewReader(tlsConn) 1319 1320 resp, _ = nsq.ReadResponse(compressConn) 1321 frameType, data, _ = nsq.UnpackResponse(resp) 1322 t.Logf("frameType: %d, data: %s", frameType, data) 1323 test.Equal(t, frameTypeResponse, frameType) 1324 test.Equal(t, []byte("OK"), data) 1325 } 1326 1327 func TestClientMsgTimeout(t *testing.T) { 1328 opts := NewOptions() 1329 opts.Logger = test.NewTestLogger(t) 1330 opts.LogLevel = LOG_DEBUG 1331 opts.QueueScanRefreshInterval = 100 * time.Millisecond 1332 tcpAddr, _, nsqd := mustStartNSQD(opts) 1333 defer os.RemoveAll(opts.DataPath) 1334 defer nsqd.Exit() 1335 1336 topicName := "test_cmsg_timeout" + strconv.Itoa(int(time.Now().Unix())) 1337 topic := nsqd.GetTopic(topicName) 1338 ch := topic.GetChannel("ch") 1339 msg := NewMessage(topic.GenerateID(), make([]byte, 100)) 1340 topic.PutMessage(msg) 1341 1342 // without this the race detector thinks there's a write 1343 // to msg.Attempts that races with the read in the protocol's messagePump... 1344 // it does not reflect a realistically possible condition 1345 topic.PutMessage(NewMessage(topic.GenerateID(), make([]byte, 100))) 1346 1347 conn, err := mustConnectNSQD(tcpAddr) 1348 test.Nil(t, err) 1349 defer conn.Close() 1350 1351 identify(t, conn, map[string]interface{}{ 1352 "msg_timeout": 1000, 1353 }, frameTypeResponse) 1354 sub(t, conn, topicName, "ch") 1355 1356 test.Equal(t, 0, int(atomic.LoadUint64(&ch.timeoutCount))) 1357 test.Equal(t, 0, int(atomic.LoadUint64(&ch.requeueCount))) 1358 1359 _, err = nsq.Ready(1).WriteTo(conn) 1360 test.Nil(t, err) 1361 1362 resp, _ := nsq.ReadResponse(conn) 1363 _, data, _ := nsq.UnpackResponse(resp) 1364 msgOut, _ := decodeMessage(data) 1365 test.Equal(t, msg.ID, msgOut.ID) 1366 test.Equal(t, msg.Body, msgOut.Body) 1367 1368 _, err = nsq.Ready(0).WriteTo(conn) 1369 test.Nil(t, err) 1370 1371 time.Sleep(1150 * time.Millisecond) 1372 1373 test.Equal(t, 1, int(atomic.LoadUint64(&ch.timeoutCount))) 1374 test.Equal(t, 0, int(atomic.LoadUint64(&ch.requeueCount))) 1375 1376 _, err = nsq.Finish(nsq.MessageID(msgOut.ID)).WriteTo(conn) 1377 test.Nil(t, err) 1378 1379 resp, _ = nsq.ReadResponse(conn) 1380 frameType, data, _ := nsq.UnpackResponse(resp) 1381 test.Equal(t, frameTypeError, frameType) 1382 test.Equal(t, fmt.Sprintf("E_FIN_FAILED FIN %s failed ID not in flight", msgOut.ID), 1383 string(data)) 1384 } 1385 1386 func TestBadFin(t *testing.T) { 1387 opts := NewOptions() 1388 opts.Logger = test.NewTestLogger(t) 1389 opts.LogLevel = LOG_DEBUG 1390 tcpAddr, _, nsqd := mustStartNSQD(opts) 1391 defer os.RemoveAll(opts.DataPath) 1392 defer nsqd.Exit() 1393 1394 conn, err := mustConnectNSQD(tcpAddr) 1395 test.Nil(t, err) 1396 defer conn.Close() 1397 1398 identify(t, conn, map[string]interface{}{}, frameTypeResponse) 1399 sub(t, conn, "test_fin", "ch") 1400 1401 fin := nsq.Finish(nsq.MessageID{}) 1402 fin.Params[0] = []byte("") 1403 _, err = fin.WriteTo(conn) 1404 test.Nil(t, err) 1405 1406 resp, _ := nsq.ReadResponse(conn) 1407 frameType, data, _ := nsq.UnpackResponse(resp) 1408 test.Equal(t, frameTypeError, frameType) 1409 test.Equal(t, "E_INVALID invalid message ID", string(data)) 1410 } 1411 1412 func TestReqTimeoutRange(t *testing.T) { 1413 opts := NewOptions() 1414 opts.Logger = test.NewTestLogger(t) 1415 opts.LogLevel = LOG_DEBUG 1416 opts.MaxReqTimeout = 1 * time.Minute 1417 tcpAddr, _, nsqd := mustStartNSQD(opts) 1418 defer os.RemoveAll(opts.DataPath) 1419 defer nsqd.Exit() 1420 1421 topicName := "test_req" + strconv.Itoa(int(time.Now().Unix())) 1422 1423 conn, err := mustConnectNSQD(tcpAddr) 1424 test.Nil(t, err) 1425 defer conn.Close() 1426 1427 identify(t, conn, nil, frameTypeResponse) 1428 sub(t, conn, topicName, "ch") 1429 1430 topic := nsqd.GetTopic(topicName) 1431 channel := topic.GetChannel("ch") 1432 msg := NewMessage(topic.GenerateID(), []byte("test body")) 1433 topic.PutMessage(msg) 1434 1435 _, err = nsq.Ready(1).WriteTo(conn) 1436 test.Nil(t, err) 1437 1438 resp, err := nsq.ReadResponse(conn) 1439 test.Nil(t, err) 1440 frameType, data, _ := nsq.UnpackResponse(resp) 1441 msgOut, _ := decodeMessage(data) 1442 test.Equal(t, frameTypeMessage, frameType) 1443 test.Equal(t, msg.ID, msgOut.ID) 1444 1445 _, err = nsq.Requeue(nsq.MessageID(msg.ID), -1).WriteTo(conn) 1446 test.Nil(t, err) 1447 1448 // It should be immediately available for another attempt 1449 resp, err = nsq.ReadResponse(conn) 1450 test.Nil(t, err) 1451 frameType, data, _ = nsq.UnpackResponse(resp) 1452 msgOut, _ = decodeMessage(data) 1453 test.Equal(t, frameTypeMessage, frameType) 1454 test.Equal(t, msg.ID, msgOut.ID) 1455 1456 // The priority (processing time) should be >= this 1457 minTs := time.Now().Add(opts.MaxReqTimeout).UnixNano() 1458 1459 _, err = nsq.Requeue(nsq.MessageID(msg.ID), opts.MaxReqTimeout*2).WriteTo(conn) 1460 test.Nil(t, err) 1461 1462 time.Sleep(100 * time.Millisecond) 1463 1464 channel.deferredMutex.Lock() 1465 pqItem := channel.deferredMessages[msg.ID] 1466 channel.deferredMutex.Unlock() 1467 1468 test.NotNil(t, pqItem) 1469 test.Equal(t, true, pqItem.Priority >= minTs) 1470 } 1471 1472 func TestClientAuth(t *testing.T) { 1473 authResponse := `{"ttl":1, "authorizations":[]}` 1474 authSecret := "testsecret" 1475 authError := "E_UNAUTHORIZED AUTH no authorizations found" 1476 authSuccess := "" 1477 tlsEnabled := false 1478 commonName := "" 1479 runAuthTest(t, authResponse, authSecret, authError, authSuccess, tlsEnabled, commonName) 1480 1481 // now one that will succeed 1482 authResponse = `{"ttl":10, "authorizations": 1483 [{"topic":"test", "channels":[".*"], "permissions":["subscribe","publish"]}] 1484 }` 1485 authError = "" 1486 authSuccess = `{"identity":"","identity_url":"","permission_count":1}` 1487 runAuthTest(t, authResponse, authSecret, authError, authSuccess, tlsEnabled, commonName) 1488 1489 // one with TLS enabled 1490 tlsEnabled = true 1491 commonName = "test.local" 1492 runAuthTest(t, authResponse, authSecret, authError, authSuccess, tlsEnabled, commonName) 1493 } 1494 1495 func runAuthTest(t *testing.T, authResponse string, authSecret string, authError string, 1496 authSuccess string, tlsEnabled bool, commonName string) { 1497 var err error 1498 var expectedRemoteIP string 1499 expectedTLS := "false" 1500 if tlsEnabled { 1501 expectedTLS = "true" 1502 } 1503 1504 authd := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 1505 t.Logf("in test auth handler %s", r.RequestURI) 1506 r.ParseForm() 1507 test.Equal(t, expectedRemoteIP, r.Form.Get("remote_ip")) 1508 test.Equal(t, expectedTLS, r.Form.Get("tls")) 1509 test.Equal(t, commonName, r.Form.Get("common_name")) 1510 test.Equal(t, authSecret, r.Form.Get("secret")) 1511 fmt.Fprint(w, authResponse) 1512 })) 1513 defer authd.Close() 1514 1515 addr, err := url.Parse(authd.URL) 1516 test.Nil(t, err) 1517 1518 opts := NewOptions() 1519 opts.Logger = test.NewTestLogger(t) 1520 opts.LogLevel = LOG_DEBUG 1521 opts.AuthHTTPAddresses = []string{addr.Host} 1522 if tlsEnabled { 1523 opts.TLSCert = "./test/certs/server.pem" 1524 opts.TLSKey = "./test/certs/server.key" 1525 opts.TLSClientAuthPolicy = "require" 1526 } 1527 tcpAddr, _, nsqd := mustStartNSQD(opts) 1528 defer os.RemoveAll(opts.DataPath) 1529 defer nsqd.Exit() 1530 1531 conn, err := mustConnectNSQD(tcpAddr) 1532 test.Nil(t, err) 1533 defer conn.Close() 1534 1535 data := identify(t, conn, map[string]interface{}{ 1536 "tls_v1": tlsEnabled, 1537 }, frameTypeResponse) 1538 r := struct { 1539 TLSv1 bool `json:"tls_v1"` 1540 }{} 1541 err = json.Unmarshal(data, &r) 1542 test.Nil(t, err) 1543 test.Equal(t, tlsEnabled, r.TLSv1) 1544 1545 var c io.ReadWriter 1546 var tlsConn *tls.Conn 1547 c = conn 1548 if tlsEnabled { 1549 cert, err := tls.LoadX509KeyPair("./test/certs/cert.pem", "./test/certs/key.pem") 1550 test.Nil(t, err) 1551 tlsConfig := &tls.Config{ 1552 Certificates: []tls.Certificate{cert}, 1553 InsecureSkipVerify: true, 1554 } 1555 tlsConn = tls.Client(conn, tlsConfig) 1556 err = tlsConn.Handshake() 1557 test.Nil(t, err) 1558 c = tlsConn 1559 1560 resp, _ := nsq.ReadResponse(tlsConn) 1561 frameType, data, _ := nsq.UnpackResponse(resp) 1562 t.Logf("frameType: %d, data: %s", frameType, data) 1563 test.Equal(t, frameTypeResponse, frameType) 1564 test.Equal(t, []byte("OK"), data) 1565 } 1566 1567 expectedRemoteIP, _, _ = net.SplitHostPort(conn.LocalAddr().String()) 1568 1569 authCmd(t, c, authSecret, authSuccess) 1570 if authError != "" { 1571 readValidate(t, c, frameTypeError, authError) 1572 } else { 1573 sub(t, c, "test", "ch") 1574 } 1575 } 1576 1577 func TestIOLoopReturnsClientErrWhenSendFails(t *testing.T) { 1578 fakeConn := test.NewFakeNetConn() 1579 fakeConn.WriteFunc = func(b []byte) (int, error) { 1580 return 0, errors.New("write error") 1581 } 1582 1583 testIOLoopReturnsClientErr(t, fakeConn) 1584 } 1585 1586 func TestIOLoopReturnsClientErrWhenSendSucceeds(t *testing.T) { 1587 fakeConn := test.NewFakeNetConn() 1588 fakeConn.WriteFunc = func(b []byte) (int, error) { 1589 return len(b), nil 1590 } 1591 1592 testIOLoopReturnsClientErr(t, fakeConn) 1593 } 1594 1595 func testIOLoopReturnsClientErr(t *testing.T, fakeConn test.FakeNetConn) { 1596 fakeConn.ReadFunc = func(b []byte) (int, error) { 1597 return copy(b, []byte("INVALID_COMMAND\n")), nil 1598 } 1599 1600 opts := NewOptions() 1601 opts.Logger = test.NewTestLogger(t) 1602 opts.LogLevel = LOG_DEBUG 1603 1604 nsqd, err := New(opts) 1605 test.Nil(t, err) 1606 prot := &protocolV2{nsqd: nsqd} 1607 defer prot.nsqd.Exit() 1608 1609 client := prot.NewClient(fakeConn) 1610 err = prot.IOLoop(client) 1611 test.NotNil(t, err) 1612 test.Equal(t, "E_INVALID invalid command INVALID_COMMAND", err.Error()) 1613 test.NotNil(t, err.(*protocol.FatalClientErr)) 1614 } 1615 1616 func BenchmarkProtocolV2Exec(b *testing.B) { 1617 b.StopTimer() 1618 opts := NewOptions() 1619 opts.Logger = test.NewTestLogger(b) 1620 nsqd, _ := New(opts) 1621 p := &protocolV2{nsqd} 1622 c := newClientV2(0, nil, nsqd) 1623 params := [][]byte{[]byte("NOP")} 1624 b.StartTimer() 1625 1626 for i := 0; i < b.N; i++ { 1627 p.Exec(c, params) 1628 } 1629 } 1630 1631 func benchmarkProtocolV2PubMultiTopic(b *testing.B, numTopics int) { 1632 var wg sync.WaitGroup 1633 b.StopTimer() 1634 opts := NewOptions() 1635 size := 200 1636 batchSize := int(opts.MaxBodySize) / (size + 4) 1637 opts.Logger = test.NewTestLogger(b) 1638 opts.MemQueueSize = int64(b.N) 1639 tcpAddr, _, nsqd := mustStartNSQD(opts) 1640 defer os.RemoveAll(opts.DataPath) 1641 msg := make([]byte, size) 1642 batch := make([][]byte, batchSize) 1643 for i := range batch { 1644 batch[i] = msg 1645 } 1646 b.SetBytes(int64(len(msg))) 1647 b.StartTimer() 1648 1649 for j := 0; j < numTopics; j++ { 1650 topicName := fmt.Sprintf("bench_v2_pub_multi_topic_%d_%d", j, time.Now().Unix()) 1651 wg.Add(1) 1652 go func() { 1653 conn, err := mustConnectNSQD(tcpAddr) 1654 if err != nil { 1655 panic(err.Error()) 1656 } 1657 rw := bufio.NewReadWriter(bufio.NewReader(conn), bufio.NewWriter(conn)) 1658 1659 num := b.N / numTopics / batchSize 1660 wg.Add(1) 1661 go func() { 1662 for i := 0; i < num; i++ { 1663 cmd, _ := nsq.MultiPublish(topicName, batch) 1664 _, err := cmd.WriteTo(rw) 1665 if err != nil { 1666 panic(err.Error()) 1667 } 1668 err = rw.Flush() 1669 if err != nil { 1670 panic(err.Error()) 1671 } 1672 } 1673 wg.Done() 1674 }() 1675 wg.Add(1) 1676 go func() { 1677 for i := 0; i < num; i++ { 1678 resp, err := nsq.ReadResponse(rw) 1679 if err != nil { 1680 panic(err.Error()) 1681 } 1682 _, data, _ := nsq.UnpackResponse(resp) 1683 if !bytes.Equal(data, []byte("OK")) { 1684 panic("invalid response") 1685 } 1686 } 1687 wg.Done() 1688 }() 1689 wg.Done() 1690 }() 1691 } 1692 1693 wg.Wait() 1694 1695 b.StopTimer() 1696 nsqd.Exit() 1697 } 1698 1699 func BenchmarkProtocolV2PubMultiTopic1(b *testing.B) { benchmarkProtocolV2PubMultiTopic(b, 1) } 1700 func BenchmarkProtocolV2PubMultiTopic2(b *testing.B) { benchmarkProtocolV2PubMultiTopic(b, 2) } 1701 func BenchmarkProtocolV2PubMultiTopic4(b *testing.B) { benchmarkProtocolV2PubMultiTopic(b, 4) } 1702 func BenchmarkProtocolV2PubMultiTopic8(b *testing.B) { benchmarkProtocolV2PubMultiTopic(b, 8) } 1703 func BenchmarkProtocolV2PubMultiTopic16(b *testing.B) { benchmarkProtocolV2PubMultiTopic(b, 16) } 1704 func BenchmarkProtocolV2PubMultiTopic32(b *testing.B) { benchmarkProtocolV2PubMultiTopic(b, 32) } 1705 1706 func benchmarkProtocolV2Pub(b *testing.B, size int) { 1707 var wg sync.WaitGroup 1708 b.StopTimer() 1709 opts := NewOptions() 1710 batchSize := int(opts.MaxBodySize) / (size + 4) 1711 opts.Logger = test.NewTestLogger(b) 1712 opts.MemQueueSize = int64(b.N) 1713 tcpAddr, _, nsqd := mustStartNSQD(opts) 1714 defer os.RemoveAll(opts.DataPath) 1715 msg := make([]byte, size) 1716 batch := make([][]byte, batchSize) 1717 for i := range batch { 1718 batch[i] = msg 1719 } 1720 topicName := "bench_v2_pub" + strconv.Itoa(int(time.Now().Unix())) 1721 b.SetBytes(int64(len(msg))) 1722 b.StartTimer() 1723 1724 for j := 0; j < runtime.GOMAXPROCS(0); j++ { 1725 wg.Add(1) 1726 go func() { 1727 conn, err := mustConnectNSQD(tcpAddr) 1728 if err != nil { 1729 panic(err.Error()) 1730 } 1731 rw := bufio.NewReadWriter(bufio.NewReader(conn), bufio.NewWriter(conn)) 1732 1733 num := b.N / runtime.GOMAXPROCS(0) / batchSize 1734 wg.Add(1) 1735 go func() { 1736 for i := 0; i < num; i++ { 1737 cmd, _ := nsq.MultiPublish(topicName, batch) 1738 _, err := cmd.WriteTo(rw) 1739 if err != nil { 1740 panic(err.Error()) 1741 } 1742 err = rw.Flush() 1743 if err != nil { 1744 panic(err.Error()) 1745 } 1746 } 1747 wg.Done() 1748 }() 1749 wg.Add(1) 1750 go func() { 1751 for i := 0; i < num; i++ { 1752 resp, err := nsq.ReadResponse(rw) 1753 if err != nil { 1754 panic(err.Error()) 1755 } 1756 _, data, _ := nsq.UnpackResponse(resp) 1757 if !bytes.Equal(data, []byte("OK")) { 1758 panic("invalid response") 1759 } 1760 } 1761 wg.Done() 1762 }() 1763 wg.Done() 1764 }() 1765 } 1766 1767 wg.Wait() 1768 1769 b.StopTimer() 1770 nsqd.Exit() 1771 } 1772 1773 func BenchmarkProtocolV2Pub256(b *testing.B) { benchmarkProtocolV2Pub(b, 256) } 1774 func BenchmarkProtocolV2Pub512(b *testing.B) { benchmarkProtocolV2Pub(b, 512) } 1775 func BenchmarkProtocolV2Pub1k(b *testing.B) { benchmarkProtocolV2Pub(b, 1024) } 1776 func BenchmarkProtocolV2Pub2k(b *testing.B) { benchmarkProtocolV2Pub(b, 2*1024) } 1777 func BenchmarkProtocolV2Pub4k(b *testing.B) { benchmarkProtocolV2Pub(b, 4*1024) } 1778 func BenchmarkProtocolV2Pub8k(b *testing.B) { benchmarkProtocolV2Pub(b, 8*1024) } 1779 func BenchmarkProtocolV2Pub16k(b *testing.B) { benchmarkProtocolV2Pub(b, 16*1024) } 1780 func BenchmarkProtocolV2Pub32k(b *testing.B) { benchmarkProtocolV2Pub(b, 32*1024) } 1781 func BenchmarkProtocolV2Pub64k(b *testing.B) { benchmarkProtocolV2Pub(b, 64*1024) } 1782 func BenchmarkProtocolV2Pub128k(b *testing.B) { benchmarkProtocolV2Pub(b, 128*1024) } 1783 func BenchmarkProtocolV2Pub256k(b *testing.B) { benchmarkProtocolV2Pub(b, 256*1024) } 1784 func BenchmarkProtocolV2Pub512k(b *testing.B) { benchmarkProtocolV2Pub(b, 512*1024) } 1785 func BenchmarkProtocolV2Pub1m(b *testing.B) { benchmarkProtocolV2Pub(b, 1024*1024) } 1786 1787 func benchmarkProtocolV2Sub(b *testing.B, size int) { 1788 var wg sync.WaitGroup 1789 b.StopTimer() 1790 opts := NewOptions() 1791 opts.Logger = test.NewTestLogger(b) 1792 opts.MemQueueSize = int64(b.N) 1793 tcpAddr, _, nsqd := mustStartNSQD(opts) 1794 defer os.RemoveAll(opts.DataPath) 1795 msg := make([]byte, size) 1796 topicName := "bench_v2_sub" + strconv.Itoa(b.N) + strconv.Itoa(int(time.Now().Unix())) 1797 topic := nsqd.GetTopic(topicName) 1798 for i := 0; i < b.N; i++ { 1799 msg := NewMessage(topic.GenerateID(), msg) 1800 topic.PutMessage(msg) 1801 } 1802 topic.GetChannel("ch") 1803 b.SetBytes(int64(len(msg))) 1804 goChan := make(chan int) 1805 rdyChan := make(chan int) 1806 workers := runtime.GOMAXPROCS(0) 1807 for j := 0; j < workers; j++ { 1808 wg.Add(1) 1809 go func() { 1810 subWorker(b.N, workers, tcpAddr, topicName, rdyChan, goChan) 1811 wg.Done() 1812 }() 1813 <-rdyChan 1814 } 1815 b.StartTimer() 1816 1817 close(goChan) 1818 wg.Wait() 1819 1820 b.StopTimer() 1821 nsqd.Exit() 1822 } 1823 1824 func subWorker(n int, workers int, tcpAddr net.Addr, topicName string, rdyChan chan int, goChan chan int) { 1825 conn, err := mustConnectNSQD(tcpAddr) 1826 if err != nil { 1827 panic(err.Error()) 1828 } 1829 rw := bufio.NewReadWriter(bufio.NewReader(conn), bufio.NewWriterSize(conn, 65536)) 1830 1831 identify(nil, conn, nil, frameTypeResponse) 1832 sub(nil, conn, topicName, "ch") 1833 1834 rdyCount := int(math.Min(math.Max(float64(n/workers), 1), 2500)) 1835 rdyChan <- 1 1836 <-goChan 1837 nsq.Ready(rdyCount).WriteTo(rw) 1838 rw.Flush() 1839 num := n / workers 1840 for i := 0; i < num; i++ { 1841 resp, err := nsq.ReadResponse(rw) 1842 if err != nil { 1843 panic(err.Error()) 1844 } 1845 frameType, data, err := nsq.UnpackResponse(resp) 1846 if err != nil { 1847 panic(err.Error()) 1848 } 1849 if frameType != frameTypeMessage { 1850 panic("got something else") 1851 } 1852 msg, err := decodeMessage(data) 1853 if err != nil { 1854 panic(err.Error()) 1855 } 1856 nsq.Finish(nsq.MessageID(msg.ID)).WriteTo(rw) 1857 if (i+1)%rdyCount == 0 || i+1 == num { 1858 if i+1 == num { 1859 nsq.Ready(0).WriteTo(conn) 1860 } 1861 rw.Flush() 1862 } 1863 } 1864 } 1865 1866 func BenchmarkProtocolV2Sub256(b *testing.B) { benchmarkProtocolV2Sub(b, 256) } 1867 func BenchmarkProtocolV2Sub512(b *testing.B) { benchmarkProtocolV2Sub(b, 512) } 1868 func BenchmarkProtocolV2Sub1k(b *testing.B) { benchmarkProtocolV2Sub(b, 1024) } 1869 func BenchmarkProtocolV2Sub2k(b *testing.B) { benchmarkProtocolV2Sub(b, 2*1024) } 1870 func BenchmarkProtocolV2Sub4k(b *testing.B) { benchmarkProtocolV2Sub(b, 4*1024) } 1871 func BenchmarkProtocolV2Sub8k(b *testing.B) { benchmarkProtocolV2Sub(b, 8*1024) } 1872 func BenchmarkProtocolV2Sub16k(b *testing.B) { benchmarkProtocolV2Sub(b, 16*1024) } 1873 func BenchmarkProtocolV2Sub32k(b *testing.B) { benchmarkProtocolV2Sub(b, 32*1024) } 1874 func BenchmarkProtocolV2Sub64k(b *testing.B) { benchmarkProtocolV2Sub(b, 64*1024) } 1875 func BenchmarkProtocolV2Sub128k(b *testing.B) { benchmarkProtocolV2Sub(b, 128*1024) } 1876 func BenchmarkProtocolV2Sub256k(b *testing.B) { benchmarkProtocolV2Sub(b, 256*1024) } 1877 func BenchmarkProtocolV2Sub512k(b *testing.B) { benchmarkProtocolV2Sub(b, 512*1024) } 1878 func BenchmarkProtocolV2Sub1m(b *testing.B) { benchmarkProtocolV2Sub(b, 1024*1024) } 1879 1880 func benchmarkProtocolV2MultiSub(b *testing.B, num int) { 1881 var wg sync.WaitGroup 1882 b.StopTimer() 1883 1884 opts := NewOptions() 1885 opts.Logger = test.NewTestLogger(b) 1886 opts.MemQueueSize = int64(b.N) 1887 tcpAddr, _, nsqd := mustStartNSQD(opts) 1888 defer os.RemoveAll(opts.DataPath) 1889 msg := make([]byte, 256) 1890 b.SetBytes(int64(len(msg) * num)) 1891 1892 goChan := make(chan int) 1893 rdyChan := make(chan int) 1894 workers := runtime.GOMAXPROCS(0) 1895 for i := 0; i < num; i++ { 1896 topicName := "bench_v2" + strconv.Itoa(b.N) + "_" + strconv.Itoa(i) + "_" + strconv.Itoa(int(time.Now().Unix())) 1897 topic := nsqd.GetTopic(topicName) 1898 for i := 0; i < b.N; i++ { 1899 msg := NewMessage(topic.GenerateID(), msg) 1900 topic.PutMessage(msg) 1901 } 1902 topic.GetChannel("ch") 1903 1904 for j := 0; j < workers; j++ { 1905 wg.Add(1) 1906 go func() { 1907 subWorker(b.N, workers, tcpAddr, topicName, rdyChan, goChan) 1908 wg.Done() 1909 }() 1910 <-rdyChan 1911 } 1912 } 1913 b.StartTimer() 1914 1915 close(goChan) 1916 wg.Wait() 1917 1918 b.StopTimer() 1919 nsqd.Exit() 1920 } 1921 1922 func BenchmarkProtocolV2MultiSub1(b *testing.B) { benchmarkProtocolV2MultiSub(b, 1) } 1923 func BenchmarkProtocolV2MultiSub2(b *testing.B) { benchmarkProtocolV2MultiSub(b, 2) } 1924 func BenchmarkProtocolV2MultiSub4(b *testing.B) { benchmarkProtocolV2MultiSub(b, 4) } 1925 func BenchmarkProtocolV2MultiSub8(b *testing.B) { benchmarkProtocolV2MultiSub(b, 8) } 1926 func BenchmarkProtocolV2MultiSub16(b *testing.B) { benchmarkProtocolV2MultiSub(b, 16) }