Beispiel #1
0
func TestQStatus(t *T) {
	client := newClient()
	queues := []string{
		clients.RandQueueName(),
		clients.RandQueueName(),
	}

	Dispatch(client, "qstatus", queues)
	readAndAssertQStatus(t, client, []queueInfo{
		queueInfo{queues[0], 0, 0, 0},
		queueInfo{queues[1], 0, 0, 0},
	})

	// Make sure that when a client is registered to a queue that it shows up in
	// the full list of queues, even if it doesn't have any items
	emptyQueue := clients.RandQueueName()
	Dispatch(client, "qregister", []string{emptyQueue})
	readAndAssertStr(t, client, "OK")
	Dispatch(client, "qstatus", []string{})
	infos, err := read(t, client).Array()
	require.Nil(t, err)
	found := 0
	for _, infoM := range infos {
		a, err := infoM.Array()
		require.Nil(t, err)
		require.True(t, len(a) == 4)
		queueName, err := a[0].Str()
		require.Nil(t, err)
		if queueName == emptyQueue {
			found++
		}
	}
	assert.Equal(t, 1, found)
}
Beispiel #2
0
func TestQRegister(t *T) {
	client := newClient()
	queues := []string{
		clients.RandQueueName(),
		clients.RandQueueName(),
	}
	Dispatch(client, "qregister", queues)
	readAndAssertStr(t, client, "OK")
}
Beispiel #3
0
func TestPeeks(t *T) {
	client := newClient()
	queue := clients.RandQueueName()
	events := []struct{ eventID, event string }{
		{"0", "foo"},
		{"1", "bar"},
		{"2", "baz"},
	}
	eventFirst := events[0]
	eventLast := events[len(events)-1]

	Dispatch(client, "qrpeek", []string{queue})
	readAndAssertNil(t, client)

	Dispatch(client, "qlpeek", []string{queue})
	readAndAssertNil(t, client)

	for i := range events {
		Dispatch(client, "qlpush", []string{queue, events[i].eventID, events[i].event})
		readAndAssertStr(t, client, "OK")
	}

	Dispatch(client, "qrpeek", []string{queue})
	readAndAssertArr(t, client, []string{eventFirst.eventID, eventFirst.event})

	Dispatch(client, "qlpeek", []string{queue})
	readAndAssertArr(t, client, []string{eventLast.eventID, eventLast.event})

	// Make sure the queue hasn't been affected
	Dispatch(client, "qstatus", []string{queue})
	readAndAssertQStatus(t, client, []queueInfo{
		queueInfo{queue, int64(len(events)), 0, 0},
	})
}
Beispiel #4
0
// QINFO is a human readable version of QSTATUS, so the testing of it is not
// nearly as strenuous
func TestQInfo(t *T) {
	client := newClient()

	// We register a queue to make sure at least one queue shows up in the
	// results when doing a QINFO with no arguments
	emptyQueue := clients.RandQueueName()
	Dispatch(client, "qregister", []string{emptyQueue})
	readAndAssertStr(t, client, "OK")
	Dispatch(client, "qinfo", []string{})
	infos, err := read(t, client).Array()
	require.Nil(t, err)
	found := 0
	for _, infoM := range infos {
		line, err := infoM.Str()
		require.Nil(t, err)
		if strings.HasPrefix(line, emptyQueue) {
			found++
		}
	}
	assert.Equal(t, 1, found)

	// Now we make sure qinfo returns a line starting with the expected queue
	// name when we give it as an argument
	Dispatch(client, "qinfo", []string{emptyQueue})
	infos, err = read(t, client).Array()
	require.Nil(t, err)
	require.Equal(t, 1, len(infos))

	line, err := infos[0].Str()
	require.Nil(t, err)
	assert.True(t, strings.HasPrefix(line, emptyQueue))
}
Beispiel #5
0
// Test adding events and removing them
func TestBasicFunctionality(t *T) {
	client := newClient()
	queue := clients.RandQueueName()
	events := []struct{ eventID, event string }{
		{"0", "foo"},
		{"1", "bar"},
		{"2", "baz"},
	}

	for i := range events {
		Dispatch(client, "qlpush", []string{queue, events[i].eventID, events[i].event})
		readAndAssertStr(t, client, "OK")
	}

	for i := range events {
		Dispatch(client, "qrpop", []string{queue})
		readAndAssertArr(t, client, []string{events[i].eventID, events[i].event})

		Dispatch(client, "qack", []string{queue, events[i].eventID})
		readAndAssertInt(t, client, 1)
	}

	// Make sure qrpop on an empty queue does the right thing
	Dispatch(client, "qrpop", []string{queue})
	readAndAssertNil(t, client)
}
Beispiel #6
0
func TestStaleCleanup(t *T) {
	queue := clients.RandQueueName()

	client := clients.NewClient(clients.NewFakeClientConn())
	err := UpdateQueues(client, []string{queue})
	require.Nil(t, err)

	// Make sure the queue has this clientId as a consumer
	key := db.ConsumersKey(queue)
	res := db.Inst.Cmd("ZRANK", key, client.ID)
	assert.Equal(t, true, res.IsType(redis.Int), "res: %s", res)

	// Remove all knowledge about this client from the consumer state
	callCh <- func(s *state) {
		s.removeClientQueues(client, []string{queue})
	}

	// Wait a little bit and try to remove stale consumers manually
	time.Sleep(2 * time.Second)
	err = removeStaleConsumers(1 * time.Second)
	require.Nil(t, err)

	// Make sure this client is no longer a consumer
	res = db.Inst.Cmd("ZRANK", key, client.ID)
	assert.Equal(t, true, res.IsType(redis.Nil), "key: %s clientId: %s res: %s", key, client.ID, res)
}
Beispiel #7
0
func TestUpdateQueues(t *T) {
	queues := []string{
		clients.RandQueueName(),
		clients.RandQueueName(),
		clients.RandQueueName(),
	}

	client := clients.NewClient(clients.NewFakeClientConn())
	err := UpdateQueues(client, queues)
	require.Nil(t, err)

	// Make sure the client.Id appears in the consumers set for those queues
	for i := range queues {
		key := db.ConsumersKey(queues[i])
		res := db.Inst.Cmd("ZRANK", key, client.ID)
		assert.Equal(t, true, res.IsType(redis.Int), "res: %s", res)
	}

	err = UpdateQueues(client, queues[1:])
	require.Nil(t, err)

	// Make sure the first queue had this clientId removed from it
	key := db.ConsumersKey(queues[0])
	res := db.Inst.Cmd("ZRANK", key, client.ID)
	assert.Equal(t, true, res.IsType(redis.Nil), "res: %s", res)

	// Make sure the rest of the queues still have it
	for i := range queues[1:] {
		key := db.ConsumersKey(queues[1:][i])
		res := db.Inst.Cmd("ZRANK", key, client.ID)
		assert.Equal(t, true, res.IsType(redis.Int), "res: %s", res)
	}

	err = UpdateQueues(client, []string{})
	require.Nil(t, err)

	// Make sure the clientId appears nowhere
	for i := range queues {
		key := db.ConsumersKey(queues[i])
		res := db.Inst.Cmd("ZRANK", key, client.ID)
		assert.Equal(t, true, res.IsType(redis.Nil), "res: %s", res)
	}
}
Beispiel #8
0
func TestPush(t *T) {
	client := newClient()
	queue := clients.RandQueueName()

	Dispatch(client, "qlpush", []string{queue, "0", "foo"})
	readAndAssertStr(t, client, "OK")

	Dispatch(client, "qrpush", []string{queue, "1", "bar"})
	readAndAssertStr(t, client, "OK")

	Dispatch(client, "qrpeek", []string{queue})
	readAndAssertArr(t, client, []string{"1", "bar"})

	Dispatch(client, "qstatus", []string{queue})
	readAndAssertQStatus(t, client, []queueInfo{
		queueInfo{queue, 2, 0, 0},
	})
}
Beispiel #9
0
func TestQNotify(t *T) {
	client := newClient()
	queue := clients.RandQueueName()

	Dispatch(client, "qregister", []string{queue})
	readAndAssertStr(t, client, "OK")

	Dispatch(client, "qnotify", []string{"1"})
	readAndAssertNil(t, client)

	// Spawn a routine which will trigger a notify. We don't need to read the
	// response of the QLPUSH, it'll all just get garbage collected later
	go func() {
		time.Sleep(100 * time.Millisecond)
		Dispatch(newClient(), "qlpush", []string{queue, "0", "foo"})
	}()

	Dispatch(client, "qnotify", []string{"10"})
	readAndAssertStr(t, client, queue)
}
Beispiel #10
0
func TestPushNoBlock(t *T) {
	client := newClient()
	queue := clients.RandQueueName()

	Dispatch(client, "qlpush", []string{queue, "0", "foo", "NOBLOCK"})
	readAndAssertStr(t, client, "OK")
	time.Sleep(50 * time.Millisecond)

	Dispatch(client, "qrpush", []string{queue, "1", "bar", "NOBLOCK"})
	readAndAssertStr(t, client, "OK")
	time.Sleep(50 * time.Millisecond)

	Dispatch(client, "qrpeek", []string{queue})
	readAndAssertArr(t, client, []string{"1", "bar"})

	Dispatch(client, "qstatus", []string{queue})
	readAndAssertQStatus(t, client, []queueInfo{
		queueInfo{queue, 2, 0, 0},
	})
}
Beispiel #11
0
func TestQFlush(t *T) {
	client := newClient()
	queue := clients.RandQueueName()

	// Ensure adding a single event to a queue and then flushing destroys it
	Dispatch(client, "qlpush", []string{queue, "0", "foo"})
	readAndAssertStr(t, client, "OK")
	Dispatch(client, "qflush", []string{queue})
	readAndAssertStr(t, client, "OK")
	Dispatch(client, "qstatus", []string{queue})
	readAndAssertQStatus(t, client, []queueInfo{
		queueInfo{queue, 0, 0, 0},
	})

	// Ensure adding a multiple items, having one in the claimed queue, and then
	// flushing still destroys everything
	Dispatch(client, "qlpush", []string{queue, "0", "foo"})
	readAndAssertStr(t, client, "OK")
	Dispatch(client, "qlpush", []string{queue, "1", "foo"})
	readAndAssertStr(t, client, "OK")
	Dispatch(client, "qrpop", []string{queue})
	readAndAssertArr(t, client, []string{"0", "foo"})
	Dispatch(client, "qflush", []string{queue})
	readAndAssertStr(t, client, "OK")
	Dispatch(client, "qstatus", []string{queue})
	readAndAssertQStatus(t, client, []queueInfo{
		queueInfo{queue, 0, 0, 0},
	})

	// Make sure the actual redis keys are destroyed
	keys := []string{
		db.UnclaimedKey(queue),
		db.ClaimedKey(queue),
		db.ItemsKey(queue),
	}
	for _, key := range keys {
		exists, err := db.Inst.Cmd("EXISTS", key).Int()
		assert.Nil(t, err)
		assert.Equal(t, 0, exists)
	}
}
Beispiel #12
0
// There's a race condition where an item get's ackd just after being found by
// the restore process. The process checks if the item lock exists, it doesn't
// because the ack just deleted it, and then attempts to move the item from the
// claimed to the unclaimed queue. We need to make sure it doesn't appear in the
// unclaimed queue in this case
func TestRestoreRace(t *T) {

	q := clients.RandQueueName()
	unclaimedKey := db.UnclaimedKey(q)
	claimedKey := db.ClaimedKey(q)

	require.Nil(t, db.Inst.Cmd("LPUSH", unclaimedKey, "buz", "boz").Err)
	require.Nil(t, db.Inst.Cmd("LPUSH", claimedKey, "bar", "baz").Err)

	// restore an event which is in the claimed list, and one which is not
	require.Nil(t, restoreEventToQueue(q, "bar"))
	require.Nil(t, restoreEventToQueue(q, "foo"))

	l, err := db.Inst.Cmd("LRANGE", claimedKey, 0, -1).List()
	require.Nil(t, err)
	assert.Equal(t, []string{"baz"}, l)

	l, err = db.Inst.Cmd("LRANGE", unclaimedKey, 0, -1).List()
	require.Nil(t, err)
	assert.Equal(t, []string{"boz", "buz", "bar"}, l)
}
Beispiel #13
0
func TestRestore(t *T) {

	// Add an item to claimed list and call validateClaimedEvents. Since it
	// doesn't have a lock it should be moved to the unclaimed list
	q := clients.RandQueueName()
	unclaimedKey := db.UnclaimedKey(q)
	claimedKey := db.ClaimedKey(q)
	itemsKey := db.ItemsKey(q)
	require.Nil(t, db.Inst.Cmd("HSET", itemsKey, "foo", "bar").Err)
	require.Nil(t, db.Inst.Cmd("LPUSH", claimedKey, "foo").Err)

	validateClaimedEvents()

	l, err := db.Inst.Cmd("LRANGE", claimedKey, 0, -1).List()
	require.Nil(t, err)
	assert.Empty(t, l)

	l, err = db.Inst.Cmd("LRANGE", unclaimedKey, 0, -1).List()
	require.Nil(t, err)
	assert.Equal(t, []string{"foo"}, l)
}