github.com/nsqio/nsq@v1.3.0/nsqd/channel_test.go (about)

     1  package nsqd
     2  
     3  import (
     4  	"fmt"
     5  	"io"
     6  	"net/http"
     7  	"os"
     8  	"strconv"
     9  	"testing"
    10  	"time"
    11  
    12  	"github.com/nsqio/nsq/internal/test"
    13  )
    14  
    15  // ensure that we can push a message through a topic and get it out of a channel
    16  func TestPutMessage(t *testing.T) {
    17  	opts := NewOptions()
    18  	opts.Logger = test.NewTestLogger(t)
    19  	_, _, nsqd := mustStartNSQD(opts)
    20  	defer os.RemoveAll(opts.DataPath)
    21  	defer nsqd.Exit()
    22  
    23  	topicName := "test_put_message" + strconv.Itoa(int(time.Now().Unix()))
    24  	topic := nsqd.GetTopic(topicName)
    25  	channel1 := topic.GetChannel("ch")
    26  
    27  	var id MessageID
    28  	msg := NewMessage(id, []byte("test"))
    29  	topic.PutMessage(msg)
    30  
    31  	outputMsg := <-channel1.memoryMsgChan
    32  	test.Equal(t, msg.ID, outputMsg.ID)
    33  	test.Equal(t, msg.Body, outputMsg.Body)
    34  }
    35  
    36  // ensure that both channels get the same message
    37  func TestPutMessage2Chan(t *testing.T) {
    38  	opts := NewOptions()
    39  	opts.Logger = test.NewTestLogger(t)
    40  	_, _, nsqd := mustStartNSQD(opts)
    41  	defer os.RemoveAll(opts.DataPath)
    42  	defer nsqd.Exit()
    43  
    44  	topicName := "test_put_message_2chan" + strconv.Itoa(int(time.Now().Unix()))
    45  	topic := nsqd.GetTopic(topicName)
    46  	channel1 := topic.GetChannel("ch1")
    47  	channel2 := topic.GetChannel("ch2")
    48  
    49  	var id MessageID
    50  	msg := NewMessage(id, []byte("test"))
    51  	topic.PutMessage(msg)
    52  
    53  	outputMsg1 := <-channel1.memoryMsgChan
    54  	test.Equal(t, msg.ID, outputMsg1.ID)
    55  	test.Equal(t, msg.Body, outputMsg1.Body)
    56  
    57  	outputMsg2 := <-channel2.memoryMsgChan
    58  	test.Equal(t, msg.ID, outputMsg2.ID)
    59  	test.Equal(t, msg.Body, outputMsg2.Body)
    60  }
    61  
    62  func TestInFlightWorker(t *testing.T) {
    63  	count := 250
    64  
    65  	opts := NewOptions()
    66  	opts.Logger = test.NewTestLogger(t)
    67  	opts.MsgTimeout = 100 * time.Millisecond
    68  	opts.QueueScanRefreshInterval = 100 * time.Millisecond
    69  	_, _, nsqd := mustStartNSQD(opts)
    70  	defer os.RemoveAll(opts.DataPath)
    71  	defer nsqd.Exit()
    72  
    73  	topicName := "test_in_flight_worker" + strconv.Itoa(int(time.Now().Unix()))
    74  	topic := nsqd.GetTopic(topicName)
    75  	channel := topic.GetChannel("channel")
    76  
    77  	for i := 0; i < count; i++ {
    78  		msg := NewMessage(topic.GenerateID(), []byte("test"))
    79  		channel.StartInFlightTimeout(msg, 0, opts.MsgTimeout)
    80  	}
    81  
    82  	channel.Lock()
    83  	inFlightMsgs := len(channel.inFlightMessages)
    84  	channel.Unlock()
    85  	test.Equal(t, count, inFlightMsgs)
    86  
    87  	channel.inFlightMutex.Lock()
    88  	inFlightPQMsgs := len(channel.inFlightPQ)
    89  	channel.inFlightMutex.Unlock()
    90  	test.Equal(t, count, inFlightPQMsgs)
    91  
    92  	// the in flight worker has a resolution of 100ms so we need to wait
    93  	// at least that much longer than our msgTimeout (in worst case)
    94  	time.Sleep(4 * opts.MsgTimeout)
    95  
    96  	channel.Lock()
    97  	inFlightMsgs = len(channel.inFlightMessages)
    98  	channel.Unlock()
    99  	test.Equal(t, 0, inFlightMsgs)
   100  
   101  	channel.inFlightMutex.Lock()
   102  	inFlightPQMsgs = len(channel.inFlightPQ)
   103  	channel.inFlightMutex.Unlock()
   104  	test.Equal(t, 0, inFlightPQMsgs)
   105  }
   106  
   107  func TestChannelEmpty(t *testing.T) {
   108  	opts := NewOptions()
   109  	opts.Logger = test.NewTestLogger(t)
   110  	_, _, nsqd := mustStartNSQD(opts)
   111  	defer os.RemoveAll(opts.DataPath)
   112  	defer nsqd.Exit()
   113  
   114  	topicName := "test_channel_empty" + strconv.Itoa(int(time.Now().Unix()))
   115  	topic := nsqd.GetTopic(topicName)
   116  	channel := topic.GetChannel("channel")
   117  
   118  	msgs := make([]*Message, 0, 25)
   119  	for i := 0; i < 25; i++ {
   120  		msg := NewMessage(topic.GenerateID(), []byte("test"))
   121  		channel.StartInFlightTimeout(msg, 0, opts.MsgTimeout)
   122  		msgs = append(msgs, msg)
   123  	}
   124  
   125  	channel.RequeueMessage(0, msgs[len(msgs)-1].ID, 100*time.Millisecond)
   126  	test.Equal(t, 24, len(channel.inFlightMessages))
   127  	test.Equal(t, 24, len(channel.inFlightPQ))
   128  	test.Equal(t, 1, len(channel.deferredMessages))
   129  	test.Equal(t, 1, len(channel.deferredPQ))
   130  
   131  	channel.Empty()
   132  
   133  	test.Equal(t, 0, len(channel.inFlightMessages))
   134  	test.Equal(t, 0, len(channel.inFlightPQ))
   135  	test.Equal(t, 0, len(channel.deferredMessages))
   136  	test.Equal(t, 0, len(channel.deferredPQ))
   137  	test.Equal(t, int64(0), channel.Depth())
   138  }
   139  
   140  func TestChannelEmptyConsumer(t *testing.T) {
   141  	opts := NewOptions()
   142  	opts.Logger = test.NewTestLogger(t)
   143  	tcpAddr, _, nsqd := mustStartNSQD(opts)
   144  	defer os.RemoveAll(opts.DataPath)
   145  	defer nsqd.Exit()
   146  
   147  	conn, _ := mustConnectNSQD(tcpAddr)
   148  	defer conn.Close()
   149  
   150  	topicName := "test_channel_empty" + strconv.Itoa(int(time.Now().Unix()))
   151  	topic := nsqd.GetTopic(topicName)
   152  	channel := topic.GetChannel("channel")
   153  	client := newClientV2(0, conn, nsqd)
   154  	client.SetReadyCount(25)
   155  	err := channel.AddClient(client.ID, client)
   156  	test.Equal(t, err, nil)
   157  
   158  	for i := 0; i < 25; i++ {
   159  		msg := NewMessage(topic.GenerateID(), []byte("test"))
   160  		channel.StartInFlightTimeout(msg, 0, opts.MsgTimeout)
   161  		client.SendingMessage()
   162  	}
   163  
   164  	for _, cl := range channel.clients {
   165  		stats := cl.Stats("").(ClientV2Stats)
   166  		test.Equal(t, int64(25), stats.InFlightCount)
   167  	}
   168  
   169  	channel.Empty()
   170  
   171  	for _, cl := range channel.clients {
   172  		stats := cl.Stats("").(ClientV2Stats)
   173  		test.Equal(t, int64(0), stats.InFlightCount)
   174  	}
   175  }
   176  
   177  func TestMaxChannelConsumers(t *testing.T) {
   178  	opts := NewOptions()
   179  	opts.Logger = test.NewTestLogger(t)
   180  	opts.MaxChannelConsumers = 1
   181  	tcpAddr, _, nsqd := mustStartNSQD(opts)
   182  	defer os.RemoveAll(opts.DataPath)
   183  	defer nsqd.Exit()
   184  
   185  	conn, _ := mustConnectNSQD(tcpAddr)
   186  	defer conn.Close()
   187  
   188  	topicName := "test_max_channel_consumers" + strconv.Itoa(int(time.Now().Unix()))
   189  	topic := nsqd.GetTopic(topicName)
   190  	channel := topic.GetChannel("channel")
   191  
   192  	client1 := newClientV2(1, conn, nsqd)
   193  	client1.SetReadyCount(25)
   194  	err := channel.AddClient(client1.ID, client1)
   195  	test.Equal(t, err, nil)
   196  
   197  	client2 := newClientV2(2, conn, nsqd)
   198  	client2.SetReadyCount(25)
   199  	err = channel.AddClient(client2.ID, client2)
   200  	test.NotEqual(t, err, nil)
   201  }
   202  
   203  func TestChannelHealth(t *testing.T) {
   204  	opts := NewOptions()
   205  	opts.Logger = test.NewTestLogger(t)
   206  	opts.MemQueueSize = 2
   207  
   208  	_, httpAddr, nsqd := mustStartNSQD(opts)
   209  	defer os.RemoveAll(opts.DataPath)
   210  	defer nsqd.Exit()
   211  
   212  	topic := nsqd.GetTopic("test")
   213  
   214  	channel := topic.GetChannel("channel")
   215  
   216  	channel.backend = &errorBackendQueue{}
   217  
   218  	msg := NewMessage(topic.GenerateID(), make([]byte, 100))
   219  	err := channel.PutMessage(msg)
   220  	test.Nil(t, err)
   221  
   222  	msg = NewMessage(topic.GenerateID(), make([]byte, 100))
   223  	err = channel.PutMessage(msg)
   224  	test.Nil(t, err)
   225  
   226  	msg = NewMessage(topic.GenerateID(), make([]byte, 100))
   227  	err = channel.PutMessage(msg)
   228  	test.NotNil(t, err)
   229  
   230  	url := fmt.Sprintf("http://%s/ping", httpAddr)
   231  	resp, err := http.Get(url)
   232  	test.Nil(t, err)
   233  	test.Equal(t, 500, resp.StatusCode)
   234  	body, _ := io.ReadAll(resp.Body)
   235  	resp.Body.Close()
   236  	test.Equal(t, "NOK - never gonna happen", string(body))
   237  
   238  	channel.backend = &errorRecoveredBackendQueue{}
   239  
   240  	msg = NewMessage(topic.GenerateID(), make([]byte, 100))
   241  	err = channel.PutMessage(msg)
   242  	test.Nil(t, err)
   243  
   244  	resp, err = http.Get(url)
   245  	test.Nil(t, err)
   246  	test.Equal(t, 200, resp.StatusCode)
   247  	body, _ = io.ReadAll(resp.Body)
   248  	resp.Body.Close()
   249  	test.Equal(t, "OK", string(body))
   250  }