2
0
mirror of https://github.com/hibiken/asynq.git synced 2024-09-20 11:05:58 +08:00
asynq/client_test.go

869 lines
23 KiB
Go
Raw Normal View History

2020-01-03 10:13:16 +08:00
// Copyright 2020 Kentaro Hibino. All rights reserved.
// Use of this source code is governed by a MIT license
// that can be found in the LICENSE file.
2019-11-30 09:40:31 +08:00
package asynq
import (
"errors"
2019-11-30 09:40:31 +08:00
"testing"
"time"
"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
h "github.com/hibiken/asynq/internal/asynqtest"
2019-12-22 23:15:45 +08:00
"github.com/hibiken/asynq/internal/base"
2019-11-30 09:40:31 +08:00
)
func TestClientEnqueueWithProcessAtOption(t *testing.T) {
2019-11-30 09:40:31 +08:00
r := setup(t)
client := NewClient(getRedisConnOpt(t))
2020-09-08 21:51:01 +08:00
defer client.Close()
2019-11-30 09:40:31 +08:00
2021-03-21 04:42:13 +08:00
task := NewTask("send_email", h.JSON(map[string]interface{}{"to": "customer@gmail.com", "from": "merchant@example.com"}))
var (
now = time.Now()
oneHourLater = now.Add(time.Hour)
)
2019-11-30 09:40:31 +08:00
tests := []struct {
desc string
task *Task
processAt time.Time // value for ProcessAt option
opts []Option // other options
wantInfo *TaskInfo
2020-09-05 22:03:43 +08:00
wantPending map[string][]*base.TaskMessage
2020-08-18 21:01:38 +08:00
wantScheduled map[string][]base.Z
2019-11-30 09:40:31 +08:00
}{
{
desc: "Process task immediately",
task: task,
processAt: now,
opts: []Option{},
wantInfo: &TaskInfo{
Queue: "default",
Type: task.Type(),
Payload: task.Payload(),
State: TaskStatePending,
MaxRetry: defaultMaxRetry,
Retried: 0,
LastErr: "",
LastFailedAt: time.Time{},
Timeout: defaultTimeout,
Deadline: time.Time{},
NextProcessAt: now,
},
2020-09-05 22:03:43 +08:00
wantPending: map[string][]*base.TaskMessage{
2020-03-14 05:18:18 +08:00
"default": {
{
2021-03-21 04:42:13 +08:00
Type: task.Type(),
Payload: task.Payload(),
Retry: defaultMaxRetry,
Queue: "default",
Timeout: int64(defaultTimeout.Seconds()),
Deadline: noDeadline.Unix(),
},
},
},
2020-08-18 21:01:38 +08:00
wantScheduled: map[string][]base.Z{
"default": {},
},
},
{
desc: "Schedule task to be processed in the future",
task: task,
processAt: oneHourLater,
opts: []Option{},
wantInfo: &TaskInfo{
Queue: "default",
Type: task.Type(),
Payload: task.Payload(),
State: TaskStateScheduled,
MaxRetry: defaultMaxRetry,
Retried: 0,
LastErr: "",
LastFailedAt: time.Time{},
Timeout: defaultTimeout,
Deadline: time.Time{},
NextProcessAt: oneHourLater,
},
2020-09-05 22:03:43 +08:00
wantPending: map[string][]*base.TaskMessage{
2020-08-18 21:01:38 +08:00
"default": {},
},
wantScheduled: map[string][]base.Z{
"default": {
{
Message: &base.TaskMessage{
2021-03-21 04:42:13 +08:00
Type: task.Type(),
Payload: task.Payload(),
2020-08-18 21:01:38 +08:00
Retry: defaultMaxRetry,
Queue: "default",
Timeout: int64(defaultTimeout.Seconds()),
Deadline: noDeadline.Unix(),
},
Score: oneHourLater.Unix(),
},
},
},
},
}
for _, tc := range tests {
h.FlushDB(t, r) // clean up db before each test case.
opts := append(tc.opts, ProcessAt(tc.processAt))
gotInfo, err := client.Enqueue(tc.task, opts...)
if err != nil {
t.Error(err)
continue
}
cmpOptions := []cmp.Option{
cmpopts.IgnoreFields(TaskInfo{}, "ID"),
cmpopts.EquateApproxTime(500 * time.Millisecond),
}
if diff := cmp.Diff(tc.wantInfo, gotInfo, cmpOptions...); diff != "" {
t.Errorf("%s;\nEnqueue(task, ProcessAt(%v)) returned %v, want %v; (-want,+got)\n%s",
tc.desc, tc.processAt, gotInfo, tc.wantInfo, diff)
}
2020-09-05 22:03:43 +08:00
for qname, want := range tc.wantPending {
gotPending := h.GetPendingMessages(t, r, qname)
if diff := cmp.Diff(want, gotPending, h.IgnoreIDOpt, cmpopts.EquateEmpty()); diff != "" {
t.Errorf("%s;\nmismatch found in %q; (-want,+got)\n%s", tc.desc, base.PendingKey(qname), diff)
}
}
2020-08-18 21:01:38 +08:00
for qname, want := range tc.wantScheduled {
gotScheduled := h.GetScheduledEntries(t, r, qname)
2020-08-19 20:32:05 +08:00
if diff := cmp.Diff(want, gotScheduled, h.IgnoreIDOpt, cmpopts.EquateEmpty()); diff != "" {
2020-08-18 21:01:38 +08:00
t.Errorf("%s;\nmismatch found in %q; (-want,+got)\n%s", tc.desc, base.ScheduledKey(qname), diff)
}
}
}
}
func TestClientEnqueue(t *testing.T) {
r := setup(t)
client := NewClient(getRedisConnOpt(t))
2020-09-08 21:51:01 +08:00
defer client.Close()
2021-03-21 04:42:13 +08:00
task := NewTask("send_email", h.JSON(map[string]interface{}{"to": "customer@gmail.com", "from": "merchant@example.com"}))
now := time.Now()
tests := []struct {
2020-09-05 22:03:43 +08:00
desc string
task *Task
opts []Option
wantInfo *TaskInfo
2020-09-05 22:03:43 +08:00
wantPending map[string][]*base.TaskMessage
}{
{
desc: "Process task immediately with a custom retry count",
task: task,
opts: []Option{
MaxRetry(3),
},
wantInfo: &TaskInfo{
Queue: "default",
Type: task.Type(),
Payload: task.Payload(),
State: TaskStatePending,
MaxRetry: 3,
Retried: 0,
LastErr: "",
LastFailedAt: time.Time{},
Timeout: defaultTimeout,
Deadline: time.Time{},
NextProcessAt: now,
},
2020-09-05 22:03:43 +08:00
wantPending: map[string][]*base.TaskMessage{
2020-03-14 05:18:18 +08:00
"default": {
{
2021-03-21 04:42:13 +08:00
Type: task.Type(),
Payload: task.Payload(),
Retry: 3,
Queue: "default",
Timeout: int64(defaultTimeout.Seconds()),
Deadline: noDeadline.Unix(),
},
},
},
2019-11-30 09:40:31 +08:00
},
{
desc: "Negative retry count",
task: task,
opts: []Option{
MaxRetry(-2),
},
wantInfo: &TaskInfo{
Queue: "default",
Type: task.Type(),
Payload: task.Payload(),
State: TaskStatePending,
MaxRetry: 0, // Retry count should be set to zero
Retried: 0,
LastErr: "",
LastFailedAt: time.Time{},
Timeout: defaultTimeout,
Deadline: time.Time{},
NextProcessAt: now,
},
2020-09-05 22:03:43 +08:00
wantPending: map[string][]*base.TaskMessage{
2020-03-14 05:18:18 +08:00
"default": {
{
2021-03-21 04:42:13 +08:00
Type: task.Type(),
Payload: task.Payload(),
Retry: 0, // Retry count should be set to zero
Queue: "default",
Timeout: int64(defaultTimeout.Seconds()),
Deadline: noDeadline.Unix(),
},
},
},
2019-11-30 09:40:31 +08:00
},
2019-12-22 02:02:03 +08:00
{
desc: "Conflicting options",
task: task,
2019-12-22 02:02:03 +08:00
opts: []Option{
MaxRetry(2),
MaxRetry(10),
},
wantInfo: &TaskInfo{
Queue: "default",
Type: task.Type(),
Payload: task.Payload(),
State: TaskStatePending,
MaxRetry: 10, // Last option takes precedence
Retried: 0,
LastErr: "",
LastFailedAt: time.Time{},
Timeout: defaultTimeout,
Deadline: time.Time{},
NextProcessAt: now,
},
2020-09-05 22:03:43 +08:00
wantPending: map[string][]*base.TaskMessage{
2020-03-14 05:18:18 +08:00
"default": {
{
2021-03-21 04:42:13 +08:00
Type: task.Type(),
Payload: task.Payload(),
Retry: 10, // Last option takes precedence
Queue: "default",
Timeout: int64(defaultTimeout.Seconds()),
Deadline: noDeadline.Unix(),
},
},
},
},
{
desc: "With queue option",
task: task,
opts: []Option{
Queue("custom"),
},
wantInfo: &TaskInfo{
Queue: "custom",
Type: task.Type(),
Payload: task.Payload(),
State: TaskStatePending,
MaxRetry: defaultMaxRetry,
Retried: 0,
LastErr: "",
LastFailedAt: time.Time{},
Timeout: defaultTimeout,
Deadline: time.Time{},
NextProcessAt: now,
},
2020-09-05 22:03:43 +08:00
wantPending: map[string][]*base.TaskMessage{
2020-03-14 05:18:18 +08:00
"custom": {
{
2021-03-21 04:42:13 +08:00
Type: task.Type(),
Payload: task.Payload(),
Retry: defaultMaxRetry,
Queue: "custom",
Timeout: int64(defaultTimeout.Seconds()),
Deadline: noDeadline.Unix(),
},
},
},
},
{
desc: "Queue option should be case sensitive",
task: task,
opts: []Option{
Queue("MyQueue"),
},
wantInfo: &TaskInfo{
Queue: "MyQueue",
Type: task.Type(),
Payload: task.Payload(),
State: TaskStatePending,
MaxRetry: defaultMaxRetry,
Retried: 0,
LastErr: "",
LastFailedAt: time.Time{},
Timeout: defaultTimeout,
Deadline: time.Time{},
NextProcessAt: now,
},
2020-09-05 22:03:43 +08:00
wantPending: map[string][]*base.TaskMessage{
"MyQueue": {
2020-03-14 05:18:18 +08:00
{
2021-03-21 04:42:13 +08:00
Type: task.Type(),
Payload: task.Payload(),
Retry: defaultMaxRetry,
Queue: "MyQueue",
Timeout: int64(defaultTimeout.Seconds()),
Deadline: noDeadline.Unix(),
2020-02-12 13:53:59 +08:00
},
},
},
},
{
desc: "With timeout option",
task: task,
2020-02-12 13:53:59 +08:00
opts: []Option{
Timeout(20 * time.Second),
},
wantInfo: &TaskInfo{
Queue: "default",
Type: task.Type(),
Payload: task.Payload(),
State: TaskStatePending,
MaxRetry: defaultMaxRetry,
Retried: 0,
LastErr: "",
LastFailedAt: time.Time{},
Timeout: 20 * time.Second,
Deadline: time.Time{},
NextProcessAt: now,
},
2020-09-05 22:03:43 +08:00
wantPending: map[string][]*base.TaskMessage{
2020-03-14 05:18:18 +08:00
"default": {
{
2021-03-21 04:42:13 +08:00
Type: task.Type(),
Payload: task.Payload(),
Retry: defaultMaxRetry,
Queue: "default",
Timeout: 20,
Deadline: noDeadline.Unix(),
},
},
},
},
{
desc: "With deadline option",
task: task,
opts: []Option{
Deadline(time.Date(2020, time.June, 24, 0, 0, 0, 0, time.UTC)),
},
wantInfo: &TaskInfo{
Queue: "default",
Type: task.Type(),
Payload: task.Payload(),
State: TaskStatePending,
MaxRetry: defaultMaxRetry,
Retried: 0,
LastErr: "",
LastFailedAt: time.Time{},
Timeout: noTimeout,
Deadline: time.Date(2020, time.June, 24, 0, 0, 0, 0, time.UTC),
NextProcessAt: now,
},
2020-09-05 22:03:43 +08:00
wantPending: map[string][]*base.TaskMessage{
2020-03-14 05:18:18 +08:00
"default": {
{
2021-03-21 04:42:13 +08:00
Type: task.Type(),
Payload: task.Payload(),
Retry: defaultMaxRetry,
Queue: "default",
Timeout: int64(noTimeout.Seconds()),
Deadline: time.Date(2020, time.June, 24, 0, 0, 0, 0, time.UTC).Unix(),
},
},
},
},
{
desc: "With both deadline and timeout options",
task: task,
opts: []Option{
Timeout(20 * time.Second),
Deadline(time.Date(2020, time.June, 24, 0, 0, 0, 0, time.UTC)),
},
wantInfo: &TaskInfo{
Queue: "default",
Type: task.Type(),
Payload: task.Payload(),
State: TaskStatePending,
MaxRetry: defaultMaxRetry,
Retried: 0,
LastErr: "",
LastFailedAt: time.Time{},
Timeout: 20 * time.Second,
Deadline: time.Date(2020, time.June, 24, 0, 0, 0, 0, time.UTC),
NextProcessAt: now,
},
2020-09-05 22:03:43 +08:00
wantPending: map[string][]*base.TaskMessage{
"default": {
{
2021-03-21 04:42:13 +08:00
Type: task.Type(),
Payload: task.Payload(),
Retry: defaultMaxRetry,
Queue: "default",
Timeout: 20,
Deadline: time.Date(2020, time.June, 24, 0, 0, 0, 0, time.UTC).Unix(),
},
2019-12-22 02:02:03 +08:00
},
},
},
}
for _, tc := range tests {
h.FlushDB(t, r) // clean up db before each test case.
gotInfo, err := client.Enqueue(tc.task, tc.opts...)
if err != nil {
t.Error(err)
continue
}
cmpOptions := []cmp.Option{
cmpopts.IgnoreFields(TaskInfo{}, "ID"),
cmpopts.EquateApproxTime(500 * time.Millisecond),
}
if diff := cmp.Diff(tc.wantInfo, gotInfo, cmpOptions...); diff != "" {
t.Errorf("%s;\nEnqueue(task) returned %v, want %v; (-want,+got)\n%s",
tc.desc, gotInfo, tc.wantInfo, diff)
}
2020-09-05 22:03:43 +08:00
for qname, want := range tc.wantPending {
got := h.GetPendingMessages(t, r, qname)
if diff := cmp.Diff(want, got, h.IgnoreIDOpt); diff != "" {
t.Errorf("%s;\nmismatch found in %q; (-want,+got)\n%s", tc.desc, base.PendingKey(qname), diff)
}
}
}
}
func TestClientEnqueueWithProcessInOption(t *testing.T) {
r := setup(t)
client := NewClient(getRedisConnOpt(t))
2020-09-08 21:51:01 +08:00
defer client.Close()
2021-03-21 04:42:13 +08:00
task := NewTask("send_email", h.JSON(map[string]interface{}{"to": "customer@gmail.com", "from": "merchant@example.com"}))
now := time.Now()
tests := []struct {
desc string
task *Task
delay time.Duration // value for ProcessIn option
opts []Option // other options
wantInfo *TaskInfo
2020-09-05 22:03:43 +08:00
wantPending map[string][]*base.TaskMessage
2020-08-18 21:01:38 +08:00
wantScheduled map[string][]base.Z
}{
{
2020-09-05 22:03:43 +08:00
desc: "schedule a task to be processed in one hour",
task: task,
delay: 1 * time.Hour,
opts: []Option{},
wantInfo: &TaskInfo{
Queue: "default",
Type: task.Type(),
Payload: task.Payload(),
State: TaskStateScheduled,
MaxRetry: defaultMaxRetry,
Retried: 0,
LastErr: "",
LastFailedAt: time.Time{},
Timeout: defaultTimeout,
Deadline: time.Time{},
NextProcessAt: time.Now().Add(1 * time.Hour),
},
2020-09-05 22:03:43 +08:00
wantPending: map[string][]*base.TaskMessage{
2020-08-18 21:01:38 +08:00
"default": {},
},
wantScheduled: map[string][]base.Z{
"default": {
{
Message: &base.TaskMessage{
2021-03-21 04:42:13 +08:00
Type: task.Type(),
Payload: task.Payload(),
2020-08-18 21:01:38 +08:00
Retry: defaultMaxRetry,
Queue: "default",
Timeout: int64(defaultTimeout.Seconds()),
Deadline: noDeadline.Unix(),
},
Score: time.Now().Add(time.Hour).Unix(),
},
},
},
},
{
desc: "Zero delay",
task: task,
delay: 0,
opts: []Option{},
wantInfo: &TaskInfo{
Queue: "default",
Type: task.Type(),
Payload: task.Payload(),
State: TaskStatePending,
MaxRetry: defaultMaxRetry,
Retried: 0,
LastErr: "",
LastFailedAt: time.Time{},
Timeout: defaultTimeout,
Deadline: time.Time{},
NextProcessAt: now,
},
2020-09-05 22:03:43 +08:00
wantPending: map[string][]*base.TaskMessage{
2020-03-14 05:18:18 +08:00
"default": {
{
2021-03-21 04:42:13 +08:00
Type: task.Type(),
Payload: task.Payload(),
Retry: defaultMaxRetry,
Queue: "default",
Timeout: int64(defaultTimeout.Seconds()),
Deadline: noDeadline.Unix(),
},
},
},
2020-08-18 21:01:38 +08:00
wantScheduled: map[string][]base.Z{
"default": {},
},
2019-12-22 02:02:03 +08:00
},
2019-11-30 09:40:31 +08:00
}
for _, tc := range tests {
h.FlushDB(t, r) // clean up db before each test case.
2019-11-30 09:40:31 +08:00
opts := append(tc.opts, ProcessIn(tc.delay))
gotInfo, err := client.Enqueue(tc.task, opts...)
2019-11-30 09:40:31 +08:00
if err != nil {
t.Error(err)
continue
}
cmpOptions := []cmp.Option{
cmpopts.IgnoreFields(TaskInfo{}, "ID"),
cmpopts.EquateApproxTime(500 * time.Millisecond),
}
if diff := cmp.Diff(tc.wantInfo, gotInfo, cmpOptions...); diff != "" {
t.Errorf("%s;\nEnqueue(task, ProcessIn(%v)) returned %v, want %v; (-want,+got)\n%s",
tc.desc, tc.delay, gotInfo, tc.wantInfo, diff)
}
2019-11-30 09:40:31 +08:00
2020-09-05 22:03:43 +08:00
for qname, want := range tc.wantPending {
gotPending := h.GetPendingMessages(t, r, qname)
if diff := cmp.Diff(want, gotPending, h.IgnoreIDOpt, cmpopts.EquateEmpty()); diff != "" {
t.Errorf("%s;\nmismatch found in %q; (-want,+got)\n%s", tc.desc, base.PendingKey(qname), diff)
}
}
2020-08-18 21:01:38 +08:00
for qname, want := range tc.wantScheduled {
gotScheduled := h.GetScheduledEntries(t, r, qname)
2020-08-19 20:32:05 +08:00
if diff := cmp.Diff(want, gotScheduled, h.IgnoreIDOpt, cmpopts.EquateEmpty()); diff != "" {
2020-08-18 21:01:38 +08:00
t.Errorf("%s;\nmismatch found in %q; (-want,+got)\n%s", tc.desc, base.ScheduledKey(qname), diff)
}
2019-11-30 09:40:31 +08:00
}
}
}
func TestClientEnqueueError(t *testing.T) {
r := setup(t)
client := NewClient(getRedisConnOpt(t))
2020-09-08 21:51:01 +08:00
defer client.Close()
2021-03-21 04:42:13 +08:00
task := NewTask("send_email", h.JSON(map[string]interface{}{"to": "customer@gmail.com", "from": "merchant@example.com"}))
tests := []struct {
desc string
task *Task
opts []Option
}{
{
desc: "With empty queue name",
task: task,
opts: []Option{
Queue(""),
},
},
{
desc: "With empty task typename",
task: NewTask("", h.JSON(map[string]interface{}{})),
opts: []Option{},
},
}
for _, tc := range tests {
h.FlushDB(t, r)
_, err := client.Enqueue(tc.task, tc.opts...)
if err == nil {
t.Errorf("%s; client.Enqueue(task, opts...) did not return non-nil error", tc.desc)
}
}
}
2020-04-26 22:48:38 +08:00
func TestClientDefaultOptions(t *testing.T) {
r := setup(t)
now := time.Now()
2020-04-26 22:48:38 +08:00
tests := []struct {
desc string
defaultOpts []Option // options set at the client level.
opts []Option // options used at enqueue time.
task *Task
wantInfo *TaskInfo
2020-04-26 22:48:38 +08:00
queue string // queue that the message should go into.
want *base.TaskMessage
}{
{
desc: "With queue routing option",
defaultOpts: []Option{Queue("feed")},
opts: []Option{},
task: NewTask("feed:import", nil),
wantInfo: &TaskInfo{
Queue: "feed",
Type: "feed:import",
Payload: nil,
State: TaskStatePending,
MaxRetry: defaultMaxRetry,
Retried: 0,
LastErr: "",
LastFailedAt: time.Time{},
Timeout: defaultTimeout,
Deadline: time.Time{},
NextProcessAt: now,
},
queue: "feed",
2020-04-26 22:48:38 +08:00
want: &base.TaskMessage{
Type: "feed:import",
Payload: nil,
Retry: defaultMaxRetry,
Queue: "feed",
Timeout: int64(defaultTimeout.Seconds()),
Deadline: noDeadline.Unix(),
2020-04-26 22:48:38 +08:00
},
},
{
desc: "With multiple options",
defaultOpts: []Option{Queue("feed"), MaxRetry(5)},
opts: []Option{},
task: NewTask("feed:import", nil),
wantInfo: &TaskInfo{
Queue: "feed",
Type: "feed:import",
Payload: nil,
State: TaskStatePending,
MaxRetry: 5,
Retried: 0,
LastErr: "",
LastFailedAt: time.Time{},
Timeout: defaultTimeout,
Deadline: time.Time{},
NextProcessAt: now,
},
queue: "feed",
2020-04-26 22:48:38 +08:00
want: &base.TaskMessage{
Type: "feed:import",
Payload: nil,
Retry: 5,
Queue: "feed",
Timeout: int64(defaultTimeout.Seconds()),
Deadline: noDeadline.Unix(),
2020-04-26 22:48:38 +08:00
},
},
{
desc: "With overriding options at enqueue time",
defaultOpts: []Option{Queue("feed"), MaxRetry(5)},
opts: []Option{Queue("critical")},
task: NewTask("feed:import", nil),
wantInfo: &TaskInfo{
Queue: "critical",
Type: "feed:import",
Payload: nil,
State: TaskStatePending,
MaxRetry: 5,
LastErr: "",
LastFailedAt: time.Time{},
Timeout: defaultTimeout,
Deadline: time.Time{},
NextProcessAt: now,
},
queue: "critical",
2020-04-26 22:48:38 +08:00
want: &base.TaskMessage{
Type: "feed:import",
Payload: nil,
Retry: 5,
Queue: "critical",
Timeout: int64(defaultTimeout.Seconds()),
Deadline: noDeadline.Unix(),
2020-04-26 22:48:38 +08:00
},
},
}
for _, tc := range tests {
h.FlushDB(t, r)
c := NewClient(getRedisConnOpt(t))
2020-09-08 21:51:01 +08:00
defer c.Close()
2021-03-21 04:42:13 +08:00
c.SetDefaultOptions(tc.task.Type(), tc.defaultOpts...)
gotInfo, err := c.Enqueue(tc.task, tc.opts...)
2020-04-26 22:48:38 +08:00
if err != nil {
t.Fatal(err)
}
cmpOptions := []cmp.Option{
cmpopts.IgnoreFields(TaskInfo{}, "ID"),
cmpopts.EquateApproxTime(500 * time.Millisecond),
}
if diff := cmp.Diff(tc.wantInfo, gotInfo, cmpOptions...); diff != "" {
t.Errorf("%s;\nEnqueue(task, opts...) returned %v, want %v; (-want,+got)\n%s",
tc.desc, gotInfo, tc.wantInfo, diff)
}
2020-09-05 22:03:43 +08:00
pending := h.GetPendingMessages(t, r, tc.queue)
if len(pending) != 1 {
2020-04-26 22:48:38 +08:00
t.Errorf("%s;\nexpected queue %q to have one message; got %d messages in the queue.",
2020-09-05 22:03:43 +08:00
tc.desc, tc.queue, len(pending))
2020-04-26 22:48:38 +08:00
continue
}
2020-09-05 22:03:43 +08:00
got := pending[0]
2020-04-26 22:48:38 +08:00
if diff := cmp.Diff(tc.want, got, h.IgnoreIDOpt); diff != "" {
2020-09-05 22:03:43 +08:00
t.Errorf("%s;\nmismatch found in pending task message; (-want,+got)\n%s",
2020-04-26 22:48:38 +08:00
tc.desc, diff)
}
}
}
func TestClientEnqueueUnique(t *testing.T) {
r := setup(t)
c := NewClient(getRedisConnOpt(t))
2020-09-08 21:51:01 +08:00
defer c.Close()
tests := []struct {
task *Task
ttl time.Duration
}{
{
2021-03-21 04:42:13 +08:00
NewTask("email", h.JSON(map[string]interface{}{"user_id": 123})),
time.Hour,
},
}
for _, tc := range tests {
h.FlushDB(t, r) // clean up db before each test case.
// Enqueue the task first. It should succeed.
_, err := c.Enqueue(tc.task, Unique(tc.ttl))
if err != nil {
t.Fatal(err)
}
2021-03-21 04:42:13 +08:00
gotTTL := r.TTL(base.UniqueKey(base.DefaultQueueName, tc.task.Type(), tc.task.Payload())).Val()
if !cmp.Equal(tc.ttl.Seconds(), gotTTL.Seconds(), cmpopts.EquateApprox(0, 1)) {
t.Errorf("TTL = %v, want %v", gotTTL, tc.ttl)
continue
}
// Enqueue the task again. It should fail.
_, err = c.Enqueue(tc.task, Unique(tc.ttl))
if err == nil {
t.Errorf("Enqueueing %+v did not return an error", tc.task)
continue
}
if !errors.Is(err, ErrDuplicateTask) {
t.Errorf("Enqueueing %+v returned an error that is not ErrDuplicateTask", tc.task)
continue
}
}
}
func TestClientEnqueueUniqueWithProcessInOption(t *testing.T) {
r := setup(t)
c := NewClient(getRedisConnOpt(t))
2020-09-08 21:51:01 +08:00
defer c.Close()
tests := []struct {
task *Task
d time.Duration
ttl time.Duration
}{
{
NewTask("reindex", nil),
time.Hour,
10 * time.Minute,
},
}
for _, tc := range tests {
h.FlushDB(t, r) // clean up db before each test case.
// Enqueue the task first. It should succeed.
_, err := c.Enqueue(tc.task, ProcessIn(tc.d), Unique(tc.ttl))
if err != nil {
t.Fatal(err)
}
2021-03-21 04:42:13 +08:00
gotTTL := r.TTL(base.UniqueKey(base.DefaultQueueName, tc.task.Type(), tc.task.Payload())).Val()
wantTTL := time.Duration(tc.ttl.Seconds()+tc.d.Seconds()) * time.Second
if !cmp.Equal(wantTTL.Seconds(), gotTTL.Seconds(), cmpopts.EquateApprox(0, 1)) {
t.Errorf("TTL = %v, want %v", gotTTL, wantTTL)
continue
}
// Enqueue the task again. It should fail.
_, err = c.Enqueue(tc.task, ProcessIn(tc.d), Unique(tc.ttl))
if err == nil {
t.Errorf("Enqueueing %+v did not return an error", tc.task)
continue
}
if !errors.Is(err, ErrDuplicateTask) {
t.Errorf("Enqueueing %+v returned an error that is not ErrDuplicateTask", tc.task)
continue
}
}
}
func TestClientEnqueueUniqueWithProcessAtOption(t *testing.T) {
r := setup(t)
c := NewClient(getRedisConnOpt(t))
2020-09-08 21:51:01 +08:00
defer c.Close()
tests := []struct {
task *Task
at time.Time
ttl time.Duration
}{
{
NewTask("reindex", nil),
time.Now().Add(time.Hour),
10 * time.Minute,
},
}
for _, tc := range tests {
h.FlushDB(t, r) // clean up db before each test case.
// Enqueue the task first. It should succeed.
_, err := c.Enqueue(tc.task, ProcessAt(tc.at), Unique(tc.ttl))
if err != nil {
t.Fatal(err)
}
2021-03-21 04:42:13 +08:00
gotTTL := r.TTL(base.UniqueKey(base.DefaultQueueName, tc.task.Type(), tc.task.Payload())).Val()
wantTTL := tc.at.Add(tc.ttl).Sub(time.Now())
if !cmp.Equal(wantTTL.Seconds(), gotTTL.Seconds(), cmpopts.EquateApprox(0, 1)) {
t.Errorf("TTL = %v, want %v", gotTTL, wantTTL)
continue
}
// Enqueue the task again. It should fail.
_, err = c.Enqueue(tc.task, ProcessAt(tc.at), Unique(tc.ttl))
if err == nil {
t.Errorf("Enqueueing %+v did not return an error", tc.task)
continue
}
if !errors.Is(err, ErrDuplicateTask) {
t.Errorf("Enqueueing %+v returned an error that is not ErrDuplicateTask", tc.task)
continue
}
}
}