func Test_Receiver_Fetch_Produces_Correct_Fetch_Requests(t *testing.T) { _, finish := testutil.NewMockCtrl(t) defer finish() a := assert.New(t) testcases := []struct { desc string arg string maxID int expect store.FetchRequest }{ {desc: "simple forward fetch", arg: "/foo 0 20", maxID: -1, expect: store.FetchRequest{Partition: "foo", Direction: 1, StartID: uint64(0), Count: 20}, }, {desc: "forward fetch without bounds", arg: "/foo 0", maxID: -1, expect: store.FetchRequest{Partition: "foo", Direction: 1, StartID: uint64(0), Count: math.MaxInt32}, }, {desc: "backward fetch to top", arg: "/foo -20", maxID: 42, expect: store.FetchRequest{Partition: "foo", Direction: -1, StartID: uint64(42), Count: 20}, }, {desc: "backward fetch with count", arg: "/foo -1 10", maxID: 42, expect: store.FetchRequest{Partition: "foo", Direction: -1, StartID: uint64(42), Count: 10}, }, } for _, test := range testcases { rec, _, _, messageStore, err := aMockedReceiver(test.arg) a.NotNil(rec) a.NoError(err, test.desc) if test.maxID != -1 { messageStore.EXPECT().MaxMessageID(test.expect.Partition). Return(uint64(test.maxID), nil) } done := make(chan bool) messageStore.EXPECT().Fetch(gomock.Any()).Do(func(r *store.FetchRequest) { a.Equal(test.expect.Partition, r.Partition, test.desc) a.Equal(test.expect.Direction, r.Direction, test.desc) a.Equal(test.expect.StartID, r.StartID, test.desc) a.Equal(test.expect.Count, r.Count, test.desc) done <- true }) go rec.fetchOnlyLoop() testutil.ExpectDone(a, done) rec.Stop() } }
func Test_Receiver_Fetch_Returns_Correct_Messages(t *testing.T) { ctrl, finish := testutil.NewMockCtrl(t) defer finish() a := assert.New(t) rec, msgChannel, _, messageStore, err := aMockedReceiver("/foo 0 2") a.NoError(err) messages := []string{"The answer ", "is 42"} done := make(chan bool) messageStore.EXPECT().Fetch(gomock.Any()).Do(func(r *store.FetchRequest) { go func() { r.StartC <- len(messages) for i, m := range messages { r.MessageC <- &store.FetchedMessage{ID: uint64(i + 1), Message: []byte(m)} } close(r.MessageC) done <- true }() }) fetchHasTerminated := make(chan bool) go func() { rec.fetchOnlyLoop() fetchHasTerminated <- true }() testutil.ExpectDone(a, done) expectMessages(a, msgChannel, "#"+protocol.SUCCESS_FETCH_START+" /foo 2") expectMessages(a, msgChannel, messages...) expectMessages(a, msgChannel, "#"+protocol.SUCCESS_FETCH_END+" /foo") testutil.ExpectDone(a, fetchHasTerminated) ctrl.Finish() }
func Test_Receiver_Fetch_Subscribe_Fetch_Subscribe(t *testing.T) { _, finish := testutil.NewMockCtrl(t) defer finish() a := assert.New(t) rec, msgChannel, routerMock, messageStore, err := aMockedReceiver("/foo 0") a.NoError(err) // fetch first, starting at 0 fetchFirst1 := messageStore.EXPECT().Fetch(gomock.Any()).Do(func(r *store.FetchRequest) { go func() { a.Equal("foo", r.Partition) a.Equal(store.DirectionForward, r.Direction) a.Equal(uint64(0), r.StartID) a.Equal(int(math.MaxInt32), r.Count) r.StartC <- 2 r.MessageC <- &store.FetchedMessage{ID: uint64(1), Message: []byte("fetch_first1-a")} r.MessageC <- &store.FetchedMessage{ID: uint64(2), Message: []byte("fetch_first1-b")} close(r.MessageC) }() }) // there is a gap between fetched and max id messageID1 := messageStore.EXPECT().DoInTx(gomock.Any(), gomock.Any()). Do(func(partition string, callback func(maxMessageId uint64) error) { callback(uint64(3)) }).Return(errUnreadMsgsAvailable) messageID1.After(fetchFirst1) // fetch again, starting at 3, because, there is still a gap fetchFirst2 := messageStore.EXPECT().Fetch(gomock.Any()).Do(func(r *store.FetchRequest) { go func() { a.Equal("foo", r.Partition) a.Equal(store.DirectionForward, r.Direction) a.Equal(uint64(3), r.StartID) a.Equal(int(math.MaxInt32), r.Count) r.StartC <- 1 r.MessageC <- &store.FetchedMessage{ID: uint64(3), Message: []byte("fetch_first2-a")} close(r.MessageC) }() }) fetchFirst2.After(messageID1) // the gap is closed messageID2 := messageStore.EXPECT().DoInTx(gomock.Any(), gomock.Any()). Do(func(partition string, callback func(maxMessageId uint64) error) { callback(uint64(3)) }) messageID2.After(fetchFirst2) // subscribe subscribe := routerMock.EXPECT().Subscribe(gomock.Any()).Do(func(r *router.Route) { a.Equal(r.Path, protocol.Path("/foo")) r.Deliver(&protocol.Message{ID: uint64(4), Body: []byte("router-a"), Time: 1405544146}) r.Deliver(&protocol.Message{ID: uint64(5), Body: []byte("router-b"), Time: 1405544146}) r.Close() // emulate router close }) subscribe.After(messageID2) // router closed, so we fetch again, starting at 6 (after meesages from subscribe) fetchAfter := messageStore.EXPECT().Fetch(gomock.Any()).Do(func(r *store.FetchRequest) { go func() { a.Equal(uint64(6), r.StartID) a.Equal(int(math.MaxInt32), r.Count) r.StartC <- 1 r.MessageC <- &store.FetchedMessage{ID: uint64(6), Message: []byte("fetch_after-a")} close(r.MessageC) }() }) fetchAfter.After(subscribe) // no gap messageID3 := messageStore.EXPECT().DoInTx(gomock.Any(), gomock.Any()). Do(func(partition string, callback func(maxMessageId uint64) error) { callback(uint64(6)) }) messageID3.After(fetchAfter) // subscribe and don't send messages, // so the client has to wait until we stop subscribe2 := routerMock.EXPECT().Subscribe(gomock.Any()) subscribe2.After(messageID3) subscriptionLoopDone := make(chan bool) go func() { rec.subscriptionLoop() subscriptionLoopDone <- true }() expectMessages(a, msgChannel, "#"+protocol.SUCCESS_FETCH_START+" /foo 2", "fetch_first1-a", "fetch_first1-b", "#"+protocol.SUCCESS_FETCH_END+" /foo", "#"+protocol.SUCCESS_FETCH_START+" /foo 1", "fetch_first2-a", "#"+protocol.SUCCESS_FETCH_END+" /foo", "#"+protocol.SUCCESS_SUBSCRIBED_TO+" /foo", ",4,,,,1405544146,0\n\nrouter-a", ",5,,,,1405544146,0\n\nrouter-b", "#"+protocol.SUCCESS_FETCH_START+" /foo 1", "fetch_after-a", "#"+protocol.SUCCESS_FETCH_END+" /foo", "#"+protocol.SUCCESS_SUBSCRIBED_TO+" /foo", ) time.Sleep(time.Millisecond) routerMock.EXPECT().Unsubscribe(gomock.Any()) rec.Stop() expectMessages(a, msgChannel, "#"+protocol.SUCCESS_CANCELED+" /foo", ) testutil.ExpectDone(a, subscriptionLoopDone) }