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) }