func TestHTTPconfig(t *testing.T) { lopts := nsqlookupd.NewOptions() lopts.Logger = test.NewTestLogger(t) _, _, lookupd1 := mustStartNSQLookupd(lopts) defer lookupd1.Exit() _, _, lookupd2 := mustStartNSQLookupd(lopts) defer lookupd2.Exit() opts := NewOptions() opts.Logger = test.NewTestLogger(t) _, httpAddr, nsqd := mustStartNSQD(opts) defer os.RemoveAll(opts.DataPath) defer nsqd.Exit() url := fmt.Sprintf("http://%s/config/nsqlookupd_tcp_addresses", httpAddr) resp, err := http.Get(url) test.Nil(t, err) defer resp.Body.Close() body, _ := ioutil.ReadAll(resp.Body) test.Equal(t, 200, resp.StatusCode) test.Equal(t, "[]", string(body)) client := http.Client{} addrs := fmt.Sprintf(`["%s","%s"]`, lookupd1.RealTCPAddr().String(), lookupd2.RealTCPAddr().String()) url = fmt.Sprintf("http://%s/config/nsqlookupd_tcp_addresses", httpAddr) req, err := http.NewRequest("PUT", url, bytes.NewBuffer([]byte(addrs))) test.Nil(t, err) resp, err = client.Do(req) test.Nil(t, err) defer resp.Body.Close() body, _ = ioutil.ReadAll(resp.Body) test.Equal(t, 200, resp.StatusCode) test.Equal(t, addrs, string(body)) }
func TestPauseMetadata(t *testing.T) { opts := NewOptions() opts.Logger = test.NewTestLogger(t) _, _, nsqd := mustStartNSQD(opts) defer os.RemoveAll(opts.DataPath) defer nsqd.Exit() // avoid concurrency issue of async PersistMetadata() calls atomic.StoreInt32(&nsqd.isLoading, 1) topicName := "pause_metadata" + strconv.Itoa(int(time.Now().Unix())) topic := nsqd.GetTopic(topicName) channel := topic.GetChannel("ch") atomic.StoreInt32(&nsqd.isLoading, 0) nsqd.PersistMetadata() var isPaused = func(n *NSQD, topicIndex int, channelIndex int) bool { m, _ := getMetadata(n) return m.Topics[topicIndex].Channels[channelIndex].Paused } test.Equal(t, false, isPaused(nsqd, 0, 0)) channel.Pause() test.Equal(t, false, isPaused(nsqd, 0, 0)) nsqd.PersistMetadata() test.Equal(t, true, isPaused(nsqd, 0, 0)) channel.UnPause() test.Equal(t, true, isPaused(nsqd, 0, 0)) nsqd.PersistMetadata() test.Equal(t, false, isPaused(nsqd, 0, 0)) }
func TestInactiveNodes(t *testing.T) { opts := NewOptions() opts.Logger = test.NewTestLogger(t) opts.InactiveProducerTimeout = 200 * time.Millisecond tcpAddr, httpAddr, nsqlookupd := mustStartLookupd(opts) defer nsqlookupd.Exit() lookupdHTTPAddrs := []string{fmt.Sprintf("%s", httpAddr)} topicName := "inactive_nodes" conn := mustConnectLookupd(t, tcpAddr) defer conn.Close() identify(t, conn) nsq.Register(topicName, "channel1").WriteTo(conn) _, err := nsq.ReadResponse(conn) test.Nil(t, err) ci := clusterinfo.New(nil, http_api.NewClient(nil, ConnectTimeout, RequestTimeout)) producers, _ := ci.GetLookupdProducers(lookupdHTTPAddrs) test.Equal(t, 1, len(producers)) test.Equal(t, 1, len(producers[0].Topics)) test.Equal(t, topicName, producers[0].Topics[0].Topic) test.Equal(t, false, producers[0].Topics[0].Tombstoned) time.Sleep(250 * time.Millisecond) producers, _ = ci.GetLookupdProducers(lookupdHTTPAddrs) test.Equal(t, 0, len(producers)) }
func TestChannelEmpty(t *testing.T) { opts := NewOptions() opts.Logger = test.NewTestLogger(t) _, _, nsqd := mustStartNSQD(opts) defer os.RemoveAll(opts.DataPath) defer nsqd.Exit() topicName := "test_channel_empty" + strconv.Itoa(int(time.Now().Unix())) topic := nsqd.GetTopic(topicName) channel := topic.GetChannel("channel") msgs := make([]*Message, 0, 25) for i := 0; i < 25; i++ { msg := NewMessage(<-nsqd.idChan, []byte("test")) channel.StartInFlightTimeout(msg, 0, opts.MsgTimeout) msgs = append(msgs, msg) } channel.RequeueMessage(0, msgs[len(msgs)-1].ID, 100*time.Millisecond) test.Equal(t, 24, len(channel.inFlightMessages)) test.Equal(t, 24, len(channel.inFlightPQ)) test.Equal(t, 1, len(channel.deferredMessages)) test.Equal(t, 1, len(channel.deferredPQ)) channel.Empty() test.Equal(t, 0, len(channel.inFlightMessages)) test.Equal(t, 0, len(channel.inFlightPQ)) test.Equal(t, 0, len(channel.deferredMessages)) test.Equal(t, 0, len(channel.deferredPQ)) test.Equal(t, int64(0), channel.Depth()) }
func TestHTTPpubDefer(t *testing.T) { opts := NewOptions() opts.Logger = test.NewTestLogger(t) _, httpAddr, nsqd := mustStartNSQD(opts) defer os.RemoveAll(opts.DataPath) defer nsqd.Exit() topicName := "test_http_pub_defer" + strconv.Itoa(int(time.Now().Unix())) topic := nsqd.GetTopic(topicName) ch := topic.GetChannel("ch") buf := bytes.NewBuffer([]byte("test message")) url := fmt.Sprintf("http://%s/pub?topic=%s&defer=%d", httpAddr, topicName, 1000) resp, err := http.Post(url, "application/octet-stream", buf) test.Nil(t, err) defer resp.Body.Close() body, _ := ioutil.ReadAll(resp.Body) test.Equal(t, "OK", string(body)) time.Sleep(5 * time.Millisecond) ch.deferredMutex.Lock() numDef := len(ch.deferredMessages) ch.deferredMutex.Unlock() test.Equal(t, 1, numDef) }
func TestHTTPmput(t *testing.T) { opts := NewOptions() opts.Logger = test.NewTestLogger(t) _, httpAddr, nsqd := mustStartNSQD(opts) defer os.RemoveAll(opts.DataPath) defer nsqd.Exit() topicName := "test_http_mput" + strconv.Itoa(int(time.Now().Unix())) topic := nsqd.GetTopic(topicName) msg := []byte("test message") msgs := make([][]byte, 4) for i := range msgs { msgs[i] = msg } buf := bytes.NewBuffer(bytes.Join(msgs, []byte("\n"))) url := fmt.Sprintf("http://%s/mput?topic=%s", httpAddr, topicName) resp, err := http.Post(url, "application/octet-stream", buf) test.Nil(t, err) defer resp.Body.Close() body, _ := ioutil.ReadAll(resp.Body) test.Equal(t, "OK", string(body)) time.Sleep(5 * time.Millisecond) test.Equal(t, int64(4), topic.Depth()) }
func bootstrapNSQCluster(t *testing.T) (string, []*nsqd.NSQD, *NSQLookupd) { lgr := test.NewTestLogger(t) nsqlookupdOpts := NewOptions() nsqlookupdOpts.TCPAddress = "127.0.0.1:0" nsqlookupdOpts.HTTPAddress = "127.0.0.1:0" nsqlookupdOpts.BroadcastAddress = "127.0.0.1" nsqlookupdOpts.Logger = lgr nsqlookupd1 := New(nsqlookupdOpts) go nsqlookupd1.Main() time.Sleep(100 * time.Millisecond) nsqdOpts := nsqd.NewOptions() nsqdOpts.TCPAddress = "127.0.0.1:0" nsqdOpts.HTTPAddress = "127.0.0.1:0" nsqdOpts.BroadcastAddress = "127.0.0.1" nsqdOpts.NSQLookupdTCPAddresses = []string{nsqlookupd1.RealTCPAddr().String()} nsqdOpts.Logger = lgr tmpDir, err := ioutil.TempDir("", fmt.Sprintf("nsq-test-%d", time.Now().UnixNano())) if err != nil { panic(err) } nsqdOpts.DataPath = tmpDir nsqd1 := nsqd.New(nsqdOpts) go nsqd1.Main() time.Sleep(100 * time.Millisecond) return tmpDir, []*nsqd.NSQD{nsqd1}, nsqlookupd1 }
func TestTLSRequireVerifyExceptHTTP(t *testing.T) { opts := NewOptions() opts.Logger = test.NewTestLogger(t) opts.Verbose = true opts.TLSCert = "./test/certs/server.pem" opts.TLSKey = "./test/certs/server.key" opts.TLSRootCAFile = "./test/certs/ca.pem" opts.TLSClientAuthPolicy = "require-verify" opts.TLSRequired = TLSRequiredExceptHTTP _, httpAddr, nsqd := mustStartNSQD(opts) defer os.RemoveAll(opts.DataPath) defer nsqd.Exit() topicName := "test_http_req_verf_except_http" + strconv.Itoa(int(time.Now().Unix())) topic := nsqd.GetTopic(topicName) // no cert buf := bytes.NewBuffer([]byte("test message")) url := fmt.Sprintf("http://%s/put?topic=%s", httpAddr, topicName) resp, err := http.Post(url, "application/octet-stream", buf) test.Nil(t, err) defer resp.Body.Close() body, _ := ioutil.ReadAll(resp.Body) test.Equal(t, "OK", string(body)) time.Sleep(5 * time.Millisecond) test.Equal(t, int64(1), topic.Depth()) }
func TestHTTPconfig(t *testing.T) { dataPath, nsqds, nsqlookupds, nsqadmin1 := bootstrapNSQCluster(t) defer os.RemoveAll(dataPath) defer nsqds[0].Exit() defer nsqlookupds[0].Exit() defer nsqadmin1.Exit() lopts := nsqlookupd.NewOptions() lopts.Logger = test.NewTestLogger(t) _, _, lookupd1 := mustStartNSQLookupd(lopts) defer lookupd1.Exit() _, _, lookupd2 := mustStartNSQLookupd(lopts) defer lookupd2.Exit() url := fmt.Sprintf("http://%s/config/nsqlookupd_http_addresses", nsqadmin1.RealHTTPAddr()) resp, err := http.Get(url) test.Nil(t, err) defer resp.Body.Close() body, _ := ioutil.ReadAll(resp.Body) test.Equal(t, 200, resp.StatusCode) origaddrs := fmt.Sprintf(`["%s"]`, nsqlookupds[0].RealHTTPAddr().String()) test.Equal(t, origaddrs, string(body)) client := http.Client{} addrs := fmt.Sprintf(`["%s","%s"]`, lookupd1.RealHTTPAddr().String(), lookupd2.RealHTTPAddr().String()) url = fmt.Sprintf("http://%s/config/nsqlookupd_http_addresses", nsqadmin1.RealHTTPAddr()) req, err := http.NewRequest("PUT", url, bytes.NewBuffer([]byte(addrs))) test.Nil(t, err) resp, err = client.Do(req) test.Nil(t, err) defer resp.Body.Close() body, _ = ioutil.ReadAll(resp.Body) test.Equal(t, 200, resp.StatusCode) test.Equal(t, addrs, string(body)) }
func testIOLoopReturnsClientErr(t *testing.T, fakeConn test.FakeNetConn) { fakeConn.ReadFunc = func(b []byte) (int, error) { return copy(b, []byte("INVALID_COMMAND\n")), nil } opts := NewOptions() opts.Logger = test.NewTestLogger(t) opts.Verbose = true prot := &LookupProtocolV1{ctx: &Context{nsqlookupd: New(opts)}} errChan := make(chan error) testIOLoop := func() { errChan <- prot.IOLoop(fakeConn) defer prot.ctx.nsqlookupd.Exit() } go testIOLoop() var err error var timeout bool select { case err = <-errChan: case <-time.After(2 * time.Second): timeout = true } test.Equal(t, false, timeout) test.NotNil(t, err) test.Equal(t, "E_INVALID invalid command INVALID_COMMAND", err.Error()) test.NotNil(t, err.(*protocol.FatalClientErr)) }
func TestChannelEmptyConsumer(t *testing.T) { opts := NewOptions() opts.Logger = test.NewTestLogger(t) tcpAddr, _, nsqd := mustStartNSQD(opts) defer os.RemoveAll(opts.DataPath) defer nsqd.Exit() conn, _ := mustConnectNSQD(tcpAddr) defer conn.Close() topicName := "test_channel_empty" + strconv.Itoa(int(time.Now().Unix())) topic := nsqd.GetTopic(topicName) channel := topic.GetChannel("channel") client := newClientV2(0, conn, &context{nsqd}) client.SetReadyCount(25) channel.AddClient(client.ID, client) for i := 0; i < 25; i++ { msg := NewMessage(<-nsqd.idChan, []byte("test")) channel.StartInFlightTimeout(msg, 0, opts.MsgTimeout) client.SendingMessage() } for _, cl := range channel.clients { stats := cl.Stats() test.Equal(t, int64(25), stats.InFlightCount) } channel.Empty() for _, cl := range channel.clients { stats := cl.Stats() test.Equal(t, int64(0), stats.InFlightCount) } }
func TestHTTPmputBinary(t *testing.T) { opts := NewOptions() opts.Logger = test.NewTestLogger(t) _, httpAddr, nsqd := mustStartNSQD(opts) defer os.RemoveAll(opts.DataPath) defer nsqd.Exit() topicName := "test_http_mput_bin" + strconv.Itoa(int(time.Now().Unix())) topic := nsqd.GetTopic(topicName) mpub := make([][]byte, 5) for i := range mpub { mpub[i] = make([]byte, 100) } cmd, _ := nsq.MultiPublish(topicName, mpub) buf := bytes.NewBuffer(cmd.Body) url := fmt.Sprintf("http://%s/mput?topic=%s&binary=true", httpAddr, topicName) resp, err := http.Post(url, "application/octet-stream", buf) test.Nil(t, err) defer resp.Body.Close() body, _ := ioutil.ReadAll(resp.Body) test.Equal(t, "OK", string(body)) time.Sleep(5 * time.Millisecond) test.Equal(t, int64(5), topic.Depth()) }
func TestStats(t *testing.T) { opts := NewOptions() opts.Logger = test.NewTestLogger(t) tcpAddr, _, nsqd := mustStartNSQD(opts) defer os.RemoveAll(opts.DataPath) defer nsqd.Exit() topicName := "test_stats" + strconv.Itoa(int(time.Now().Unix())) topic := nsqd.GetTopic(topicName) msg := NewMessage(<-nsqd.idChan, []byte("test body")) topic.PutMessage(msg) conn, err := mustConnectNSQD(tcpAddr) test.Nil(t, err) defer conn.Close() identify(t, conn, nil, frameTypeResponse) sub(t, conn, topicName, "ch") stats := nsqd.GetStats() t.Logf("stats: %+v", stats) test.Equal(t, 1, len(stats)) test.Equal(t, 1, len(stats[0].Channels)) test.Equal(t, 1, len(stats[0].Channels[0].Clients)) }
// exercise the basic operations of the V2 protocol func TestBasicV2(t *testing.T) { opts := NewOptions() opts.Logger = test.NewTestLogger(t) opts.ClientTimeout = 60 * time.Second tcpAddr, _, nsqd := mustStartNSQD(opts) defer os.RemoveAll(opts.DataPath) defer nsqd.Exit() topicName := "test_v2" + strconv.Itoa(int(time.Now().Unix())) topic := nsqd.GetTopic(topicName) msg := NewMessage(<-nsqd.idChan, []byte("test body")) topic.PutMessage(msg) conn, err := mustConnectNSQD(tcpAddr) test.Nil(t, err) defer conn.Close() identify(t, conn, nil, frameTypeResponse) sub(t, conn, topicName, "ch") _, err = nsq.Ready(1).WriteTo(conn) test.Nil(t, err) resp, err := nsq.ReadResponse(conn) test.Nil(t, err) frameType, data, err := nsq.UnpackResponse(resp) msgOut, _ := decodeMessage(data) test.Equal(t, frameTypeMessage, frameType) test.Equal(t, msg.ID, msgOut.ID) test.Equal(t, msg.Body, msgOut.Body) test.Equal(t, uint16(1), msgOut.Attempts) }
func TestReconfigure(t *testing.T) { lopts := nsqlookupd.NewOptions() lopts.Logger = test.NewTestLogger(t) _, _, lookupd1 := mustStartNSQLookupd(lopts) defer lookupd1.Exit() _, _, lookupd2 := mustStartNSQLookupd(lopts) defer lookupd2.Exit() _, _, lookupd3 := mustStartNSQLookupd(lopts) defer lookupd3.Exit() opts := NewOptions() opts.Logger = test.NewTestLogger(t) _, _, nsqd := mustStartNSQD(opts) defer os.RemoveAll(opts.DataPath) defer nsqd.Exit() time.Sleep(50 * time.Millisecond) newOpts := *opts newOpts.NSQLookupdTCPAddresses = []string{lookupd1.RealTCPAddr().String()} nsqd.swapOpts(&newOpts) nsqd.triggerOptsNotification() test.Equal(t, 1, len(nsqd.getOpts().NSQLookupdTCPAddresses)) time.Sleep(50 * time.Millisecond) numLookupPeers := len(nsqd.lookupPeers.Load().([]*lookupPeer)) test.Equal(t, 1, numLookupPeers) newOpts = *opts newOpts.NSQLookupdTCPAddresses = []string{lookupd2.RealTCPAddr().String(), lookupd3.RealTCPAddr().String()} nsqd.swapOpts(&newOpts) nsqd.triggerOptsNotification() test.Equal(t, 2, len(nsqd.getOpts().NSQLookupdTCPAddresses)) time.Sleep(50 * time.Millisecond) var lookupPeers []string for _, lp := range nsqd.lookupPeers.Load().([]*lookupPeer) { lookupPeers = append(lookupPeers, lp.addr) } test.Equal(t, 2, len(lookupPeers)) test.Equal(t, newOpts.NSQLookupdTCPAddresses, lookupPeers) }
func TestClientAttributes(t *testing.T) { userAgent := "Test User Agent" opts := NewOptions() opts.Logger = test.NewTestLogger(t) opts.Verbose = true opts.SnappyEnabled = true tcpAddr, httpAddr, nsqd := mustStartNSQD(opts) defer os.RemoveAll(opts.DataPath) defer nsqd.Exit() conn, err := mustConnectNSQD(tcpAddr) test.Nil(t, err) defer conn.Close() data := identify(t, conn, map[string]interface{}{ "snappy": true, "user_agent": userAgent, }, frameTypeResponse) resp := struct { Snappy bool `json:"snappy"` UserAgent string `json:"user_agent"` }{} err = json.Unmarshal(data, &resp) test.Nil(t, err) test.Equal(t, true, resp.Snappy) r := snappystream.NewReader(conn, snappystream.SkipVerifyChecksum) w := snappystream.NewWriter(conn) readValidate(t, r, frameTypeResponse, "OK") topicName := "test_client_attributes" + strconv.Itoa(int(time.Now().Unix())) sub(t, readWriter{r, w}, topicName, "ch") var d struct { Topics []struct { Channels []struct { Clients []struct { UserAgent string `json:"user_agent"` Snappy bool `json:"snappy"` } `json:"clients"` } `json:"channels"` } `json:"topics"` } endpoint := fmt.Sprintf("http://127.0.0.1:%d/stats?format=json", httpAddr.Port) err = http_api.NewClient(nil, ConnectTimeout, RequestTimeout).GETV1(endpoint, &d) test.Nil(t, err) test.Equal(t, userAgent, d.Topics[0].Channels[0].Clients[0].UserAgent) test.Equal(t, true, d.Topics[0].Channels[0].Clients[0].Snappy) }
func TestChannelBackendMaxMsgSize(t *testing.T) { opts := NewOptions() opts.Logger = test.NewTestLogger(t) _, _, nsqd := mustStartNSQD(opts) defer os.RemoveAll(opts.DataPath) defer nsqd.Exit() topicName := "test_channel_backend_maxmsgsize" + strconv.Itoa(int(time.Now().Unix())) topic := nsqd.GetTopic(topicName) ch := topic.GetChannel("ch") test.Equal(t, int32(opts.MaxMsgSize+minValidMsgLength), ch.backend.(*diskQueue).maxMsgSize) }
func TestChannelHealth(t *testing.T) { opts := NewOptions() opts.Logger = test.NewTestLogger(t) opts.MemQueueSize = 2 _, httpAddr, nsqd := mustStartNSQD(opts) defer os.RemoveAll(opts.DataPath) defer nsqd.Exit() topic := nsqd.GetTopic("test") channel := topic.GetChannel("channel") channel.backend = &errorBackendQueue{} msg := NewMessage(<-nsqd.idChan, make([]byte, 100)) err := channel.PutMessage(msg) test.Nil(t, err) msg = NewMessage(<-nsqd.idChan, make([]byte, 100)) err = channel.PutMessage(msg) test.Nil(t, err) msg = NewMessage(<-nsqd.idChan, make([]byte, 100)) err = channel.PutMessage(msg) test.NotNil(t, err) url := fmt.Sprintf("http://%s/ping", httpAddr) resp, err := http.Get(url) test.Nil(t, err) test.Equal(t, 500, resp.StatusCode) body, _ := ioutil.ReadAll(resp.Body) resp.Body.Close() test.Equal(t, "NOK - never gonna happen", string(body)) channel.backend = &errorRecoveredBackendQueue{} msg = NewMessage(<-nsqd.idChan, make([]byte, 100)) err = channel.PutMessage(msg) test.Nil(t, err) resp, err = http.Get(url) test.Nil(t, err) test.Equal(t, 200, resp.StatusCode) body, _ = ioutil.ReadAll(resp.Body) resp.Body.Close() test.Equal(t, "OK", string(body)) }
func TestDeleteTopic(t *testing.T) { opts := NewOptions() opts.Logger = test.NewTestLogger(t) _, httpAddr, nsqd := mustStartNSQD(opts) defer os.RemoveAll(opts.DataPath) defer nsqd.Exit() em := ErrMessage{} url := fmt.Sprintf("http://%s/topic/delete", httpAddr) resp, err := http.Post(url, "application/json", nil) test.Nil(t, err) test.Equal(t, 400, resp.StatusCode) test.Equal(t, "Bad Request", http.StatusText(resp.StatusCode)) body, _ := ioutil.ReadAll(resp.Body) resp.Body.Close() t.Logf("%s", body) err = json.Unmarshal(body, &em) test.Nil(t, err) test.Equal(t, "MISSING_ARG_TOPIC", em.Message) topicName := "test_http_delete_topic" + strconv.Itoa(int(time.Now().Unix())) url = fmt.Sprintf("http://%s/topic/delete?topic=%s", httpAddr, topicName) resp, err = http.Post(url, "application/json", nil) test.Nil(t, err) test.Equal(t, 404, resp.StatusCode) test.Equal(t, "Not Found", http.StatusText(resp.StatusCode)) body, _ = ioutil.ReadAll(resp.Body) resp.Body.Close() t.Logf("%s", body) err = json.Unmarshal(body, &em) test.Nil(t, err) test.Equal(t, "TOPIC_NOT_FOUND", em.Message) nsqd.GetTopic(topicName) resp, err = http.Post(url, "application/json", nil) test.Nil(t, err) test.Equal(t, 200, resp.StatusCode) body, _ = ioutil.ReadAll(resp.Body) resp.Body.Close() t.Logf("%s", body) test.Equal(t, []byte(""), body) }
func TestMultipleConsumerV2(t *testing.T) { msgChan := make(chan *Message) opts := NewOptions() opts.Logger = test.NewTestLogger(t) opts.ClientTimeout = 60 * time.Second tcpAddr, _, nsqd := mustStartNSQD(opts) defer os.RemoveAll(opts.DataPath) defer nsqd.Exit() topicName := "test_multiple_v2" + strconv.Itoa(int(time.Now().Unix())) topic := nsqd.GetTopic(topicName) msg := NewMessage(<-nsqd.idChan, []byte("test body")) topic.GetChannel("ch1") topic.GetChannel("ch2") topic.PutMessage(msg) for _, i := range []string{"1", "2"} { conn, err := mustConnectNSQD(tcpAddr) test.Nil(t, err) defer conn.Close() identify(t, conn, nil, frameTypeResponse) sub(t, conn, topicName, "ch"+i) _, err = nsq.Ready(1).WriteTo(conn) test.Nil(t, err) go func(c net.Conn) { resp, err := nsq.ReadResponse(c) test.Nil(t, err) _, data, err := nsq.UnpackResponse(resp) test.Nil(t, err) msg, err := decodeMessage(data) test.Nil(t, err) msgChan <- msg }(conn) } msgOut := <-msgChan test.Equal(t, msg.ID, msgOut.ID) test.Equal(t, msg.Body, msgOut.Body) test.Equal(t, uint16(1), msgOut.Attempts) msgOut = <-msgChan test.Equal(t, msg.ID, msgOut.ID) test.Equal(t, msg.Body, msgOut.Body) test.Equal(t, uint16(1), msgOut.Attempts) }
func TestTombstoneRecover(t *testing.T) { opts := NewOptions() opts.Logger = test.NewTestLogger(t) opts.TombstoneLifetime = 50 * time.Millisecond tcpAddr, httpAddr, nsqlookupd := mustStartLookupd(opts) defer nsqlookupd.Exit() topicName := "tombstone_recover" topicName2 := topicName + "2" conn := mustConnectLookupd(t, tcpAddr) defer conn.Close() identify(t, conn) nsq.Register(topicName, "channel1").WriteTo(conn) _, err := nsq.ReadResponse(conn) test.Nil(t, err) nsq.Register(topicName2, "channel2").WriteTo(conn) _, err = nsq.ReadResponse(conn) test.Nil(t, err) endpoint := fmt.Sprintf("http://%s/topic/tombstone?topic=%s&node=%s:%d", httpAddr, topicName, HostAddr, HTTPPort) err = http_api.NewClient(nil, ConnectTimeout, RequestTimeout).POSTV1(endpoint) test.Nil(t, err) pr := ProducersDoc{} endpoint = fmt.Sprintf("http://%s/lookup?topic=%s", httpAddr, topicName) err = http_api.NewClient(nil, ConnectTimeout, RequestTimeout).NegotiateV1(endpoint, &pr) test.Nil(t, err) test.Equal(t, 0, len(pr.Producers)) endpoint = fmt.Sprintf("http://%s/lookup?topic=%s", httpAddr, topicName2) err = http_api.NewClient(nil, ConnectTimeout, RequestTimeout).NegotiateV1(endpoint, &pr) test.Nil(t, err) test.Equal(t, 1, len(pr.Producers)) time.Sleep(75 * time.Millisecond) endpoint = fmt.Sprintf("http://%s/lookup?topic=%s", httpAddr, topicName) err = http_api.NewClient(nil, ConnectTimeout, RequestTimeout).NegotiateV1(endpoint, &pr) test.Nil(t, err) test.Equal(t, 1, len(pr.Producers)) }
func TestChannelUnregister(t *testing.T) { opts := NewOptions() opts.Logger = test.NewTestLogger(t) tcpAddr, httpAddr, nsqlookupd := mustStartLookupd(opts) defer nsqlookupd.Exit() topics := nsqlookupd.DB.FindRegistrations("topic", "*", "*") test.Equal(t, 0, len(topics)) topicName := "channel_unregister" conn := mustConnectLookupd(t, tcpAddr) defer conn.Close() identify(t, conn) nsq.Register(topicName, "ch1").WriteTo(conn) v, err := nsq.ReadResponse(conn) test.Nil(t, err) test.Equal(t, []byte("OK"), v) topics = nsqlookupd.DB.FindRegistrations("topic", topicName, "") test.Equal(t, 1, len(topics)) channels := nsqlookupd.DB.FindRegistrations("channel", topicName, "*") test.Equal(t, 1, len(channels)) nsq.UnRegister(topicName, "ch1").WriteTo(conn) v, err = nsq.ReadResponse(conn) test.Nil(t, err) test.Equal(t, []byte("OK"), v) topics = nsqlookupd.DB.FindRegistrations("topic", topicName, "") test.Equal(t, 1, len(topics)) // we should still have mention of the topic even though there is no producer // (ie. we haven't *deleted* the channel, just unregistered as a producer) channels = nsqlookupd.DB.FindRegistrations("channel", topicName, "*") test.Equal(t, 1, len(channels)) pr := ProducersDoc{} endpoint := fmt.Sprintf("http://%s/lookup?topic=%s", httpAddr, topicName) err = http_api.NewClient(nil, ConnectTimeout, RequestTimeout).NegotiateV1(endpoint, &pr) test.Nil(t, err) t.Logf("got %v", pr) test.Equal(t, 1, len(pr.Producers)) }
func TestEphemeralTopicsAndChannels(t *testing.T) { // ephemeral topics/channels are lazily removed after the last channel/client is removed opts := NewOptions() opts.Logger = test.NewTestLogger(t) opts.MemQueueSize = 100 _, _, nsqd := mustStartNSQD(opts) defer os.RemoveAll(opts.DataPath) topicName := "ephemeral_topic" + strconv.Itoa(int(time.Now().Unix())) + "#ephemeral" doneExitChan := make(chan int) exitChan := make(chan int) go func() { <-exitChan nsqd.Exit() doneExitChan <- 1 }() body := []byte("an_ephemeral_message") topic := nsqd.GetTopic(topicName) ephemeralChannel := topic.GetChannel("ch1#ephemeral") client := newClientV2(0, nil, &context{nsqd}) ephemeralChannel.AddClient(client.ID, client) msg := NewMessage(<-nsqd.idChan, body) topic.PutMessage(msg) msg = <-ephemeralChannel.memoryMsgChan test.Equal(t, body, msg.Body) ephemeralChannel.RemoveClient(client.ID) time.Sleep(100 * time.Millisecond) topic.Lock() numChannels := len(topic.channelMap) topic.Unlock() test.Equal(t, 0, numChannels) nsqd.Lock() numTopics := len(nsqd.topicMap) nsqd.Unlock() test.Equal(t, 0, numTopics) exitChan <- 1 <-doneExitChan }
func TestHTTPgetStatusText(t *testing.T) { testTime := time.Now() opts := NewOptions() opts.Logger = test.NewTestLogger(t) _, httpAddr, nsqd := mustStartNSQD(opts) defer os.RemoveAll(opts.DataPath) defer nsqd.Exit() nsqd.startTime = testTime url := fmt.Sprintf("http://%s/stats?format=text", httpAddr) resp, err := http.Get(url) test.Nil(t, err) defer resp.Body.Close() body, _ := ioutil.ReadAll(resp.Body) test.Equal(t, 200, resp.StatusCode) test.NotNil(t, body) }
func TestInFlightWorker(t *testing.T) { count := 250 opts := NewOptions() opts.Logger = test.NewTestLogger(t) opts.MsgTimeout = 100 * time.Millisecond opts.QueueScanRefreshInterval = 100 * time.Millisecond _, _, nsqd := mustStartNSQD(opts) defer os.RemoveAll(opts.DataPath) defer nsqd.Exit() topicName := "test_in_flight_worker" + strconv.Itoa(int(time.Now().Unix())) topic := nsqd.GetTopic(topicName) channel := topic.GetChannel("channel") for i := 0; i < count; i++ { msg := NewMessage(<-nsqd.idChan, []byte("test")) channel.StartInFlightTimeout(msg, 0, opts.MsgTimeout) } channel.Lock() inFlightMsgs := len(channel.inFlightMessages) channel.Unlock() test.Equal(t, count, inFlightMsgs) channel.inFlightMutex.Lock() inFlightPQMsgs := len(channel.inFlightPQ) channel.inFlightMutex.Unlock() test.Equal(t, count, inFlightPQMsgs) // the in flight worker has a resolution of 100ms so we need to wait // at least that much longer than our msgTimeout (in worst case) time.Sleep(4 * opts.MsgTimeout) channel.Lock() inFlightMsgs = len(channel.inFlightMessages) channel.Unlock() test.Equal(t, 0, inFlightMsgs) channel.inFlightMutex.Lock() inFlightPQMsgs = len(channel.inFlightPQ) channel.inFlightMutex.Unlock() test.Equal(t, 0, inFlightPQMsgs) }
func TestDiskQueueCorruption(t *testing.T) { l := test.NewTestLogger(t) dqName := "test_disk_queue_corruption" + strconv.Itoa(int(time.Now().Unix())) tmpDir, err := ioutil.TempDir("", fmt.Sprintf("nsq-test-%d", time.Now().UnixNano())) if err != nil { panic(err) } defer os.RemoveAll(tmpDir) // require a non-zero message length for the corrupt (len 0) test below dq := newDiskQueue(dqName, tmpDir, 1000, 10, 1<<10, 5, 2*time.Second, l) defer dq.Close() msg := make([]byte, 123) // 127 bytes per message, 8 (1016 bytes) messages per file for i := 0; i < 25; i++ { dq.Put(msg) } test.Equal(t, int64(25), dq.Depth()) // corrupt the 2nd file dqFn := dq.(*diskQueue).fileName(1) os.Truncate(dqFn, 500) // 3 valid messages, 5 corrupted for i := 0; i < 19; i++ { // 1 message leftover in 4th file test.Equal(t, msg, <-dq.ReadChan()) } // corrupt the 4th (current) file dqFn = dq.(*diskQueue).fileName(3) os.Truncate(dqFn, 100) dq.Put(msg) // in 5th file test.Equal(t, msg, <-dq.ReadChan()) // write a corrupt (len 0) message at the 5th (current) file dq.(*diskQueue).writeFile.Write([]byte{0, 0, 0, 0}) // force a new 6th file - put into 5th, then readOne errors, then put into 6th dq.Put(msg) dq.Put(msg) test.Equal(t, msg, <-dq.ReadChan()) }
func TestHTTPSRequire(t *testing.T) { opts := NewOptions() opts.Logger = test.NewTestLogger(t) opts.Verbose = true opts.TLSCert = "./test/certs/server.pem" opts.TLSKey = "./test/certs/server.key" opts.TLSClientAuthPolicy = "require" _, httpAddr, nsqd := mustStartNSQD(opts) defer os.RemoveAll(opts.DataPath) defer nsqd.Exit() topicName := "test_http_put_req" + strconv.Itoa(int(time.Now().Unix())) topic := nsqd.GetTopic(topicName) buf := bytes.NewBuffer([]byte("test message")) url := fmt.Sprintf("http://%s/put?topic=%s", httpAddr, topicName) resp, err := http.Post(url, "application/octet-stream", buf) test.Equal(t, 403, resp.StatusCode) httpsAddr := nsqd.httpsListener.Addr().(*net.TCPAddr) cert, err := tls.LoadX509KeyPair("./test/certs/cert.pem", "./test/certs/key.pem") test.Nil(t, err) tlsConfig := &tls.Config{ Certificates: []tls.Certificate{cert}, InsecureSkipVerify: true, MinVersion: 0, } transport := &http.Transport{ TLSClientConfig: tlsConfig, } client := &http.Client{Transport: transport} buf = bytes.NewBuffer([]byte("test message")) url = fmt.Sprintf("https://%s/put?topic=%s", httpsAddr, topicName) resp, err = client.Post(url, "application/octet-stream", buf) test.Nil(t, err) defer resp.Body.Close() body, _ := ioutil.ReadAll(resp.Body) test.Equal(t, "OK", string(body)) time.Sleep(5 * time.Millisecond) test.Equal(t, int64(1), topic.Depth()) }
// ensure that we can push a message through a topic and get it out of a channel func TestPutMessage(t *testing.T) { opts := NewOptions() opts.Logger = test.NewTestLogger(t) _, _, nsqd := mustStartNSQD(opts) defer os.RemoveAll(opts.DataPath) defer nsqd.Exit() topicName := "test_put_message" + strconv.Itoa(int(time.Now().Unix())) topic := nsqd.GetTopic(topicName) channel1 := topic.GetChannel("ch") var id MessageID msg := NewMessage(id, []byte("test")) topic.PutMessage(msg) outputMsg := <-channel1.memoryMsgChan test.Equal(t, msg.ID, outputMsg.ID) test.Equal(t, msg.Body, outputMsg.Body) }
func TestHTTPgetStatusJSON(t *testing.T) { testTime := time.Now() opts := NewOptions() opts.Logger = test.NewTestLogger(t) _, httpAddr, nsqd := mustStartNSQD(opts) defer os.RemoveAll(opts.DataPath) defer nsqd.Exit() nsqd.startTime = testTime expectedJSON := fmt.Sprintf(`{"status_code":200,"status_txt":"OK","data":{"version":"%v","health":"OK","start_time":%v,"topics":[]}}`, version.Binary, testTime.Unix()) url := fmt.Sprintf("http://%s/stats?format=json", httpAddr) resp, err := http.Get(url) test.Nil(t, err) defer resp.Body.Close() body, _ := ioutil.ReadAll(resp.Body) test.Equal(t, 200, resp.StatusCode) test.Equal(t, expectedJSON, string(body)) }
func TestDiskQueueSyncAfterRead(t *testing.T) { l := test.NewTestLogger(t) dqName := "test_disk_queue_read_after_sync" + strconv.Itoa(int(time.Now().Unix())) tmpDir, err := ioutil.TempDir("", fmt.Sprintf("nsq-test-%d", time.Now().UnixNano())) if err != nil { panic(err) } defer os.RemoveAll(tmpDir) dq := newDiskQueue(dqName, tmpDir, 1<<11, 0, 1<<10, 2500, 50*time.Millisecond, l) defer dq.Close() msg := make([]byte, 1000) dq.Put(msg) // sync loop is every 50ms so wait 3x to make sure the file has time // to actually get written prior to attempting to read it. time.Sleep(150 * time.Millisecond) // attempt to read and load metadata of the file; initialize the number // of retry attempts to 0; the max retries is 9 with a delay of 50ms each // meaning that a total of 650ms between message put and message metadata // read should be sufficient for heavy write disks on the travis servers. d := readMetaDataFile(dq.(*diskQueue).metaDataFileName(), 0) t.Logf("%s", d) test.Equal(t, int64(1), d.depth) test.Equal(t, int64(0), d.readFileNum) test.Equal(t, int64(0), d.writeFileNum) test.Equal(t, int64(0), d.readPos) test.Equal(t, int64(1004), d.writePos) dq.Put(msg) <-dq.ReadChan() time.Sleep(150 * time.Millisecond) d = readMetaDataFile(dq.(*diskQueue).metaDataFileName(), 0) t.Logf("%s", d) test.Equal(t, int64(1), d.depth) test.Equal(t, int64(0), d.readFileNum) test.Equal(t, int64(0), d.writeFileNum) test.Equal(t, int64(1004), d.readPos) test.Equal(t, int64(2008), d.writePos) }