From a6a53436aca582e362a4a0672ad5dc82e2551f78 Mon Sep 17 00:00:00 2001 From: reugn Date: Sat, 5 Oct 2024 17:52:19 +0300 Subject: [PATCH] test(quartz): improve code coverage and refactor cron tests --- quartz/cron_test.go | 420 ++++++++++++++++++++++--------------------- quartz/queue_test.go | 27 +++ 2 files changed, 238 insertions(+), 209 deletions(-) create mode 100644 quartz/queue_test.go diff --git a/quartz/cron_test.go b/quartz/cron_test.go index 10cc57a..80b73ba 100644 --- a/quartz/cron_test.go +++ b/quartz/cron_test.go @@ -10,146 +10,97 @@ import ( "github.com/reugn/go-quartz/quartz" ) -func TestCronExpression1(t *testing.T) { - prev := time.Date(2023, 4, 22, 12, 00, 00, 00, time.UTC).UnixNano() - cronTrigger, err := quartz.NewCronTrigger("10/20 15 14 5-10 * ? *") - assert.IsNil(t, err) - result, _ := iterate(prev, cronTrigger, 50) - assert.Equal(t, result, "Sun Jul 9 14:15:30 2023") -} - -func TestCronExpression2(t *testing.T) { - prev := time.Date(2024, 1, 1, 12, 00, 00, 00, time.UTC).UnixNano() - cronTrigger, err := quartz.NewCronTrigger("10 5,7,9 14-16 * * ? *") - assert.IsNil(t, err) - result, _ := iterate(prev, cronTrigger, 50) - assert.Equal(t, result, "Sat Jan 6 15:07:10 2024") -} - -func TestCronExpression3(t *testing.T) { - prev := time.Date(2024, 1, 1, 12, 00, 00, 00, time.UTC).UnixNano() - cronTrigger, err := quartz.NewCronTrigger("0 5,7,9 14/2 ? * WED,Sat *") - assert.IsNil(t, err) - result, _ := iterate(prev, cronTrigger, 50) - assert.Equal(t, result, "Sat Jan 13 16:07:00 2024") -} - -func TestCronExpression4(t *testing.T) { - expression := "0 5,7 14 1 * Sun *" - _, err := quartz.NewCronTrigger(expression) - assert.ErrorIs(t, err, quartz.ErrCronParse) -} - -func TestCronExpression5(t *testing.T) { - prev := time.Date(2023, 4, 22, 12, 00, 00, 00, time.UTC).UnixNano() - cronTrigger, err := quartz.NewCronTrigger("* * * * * ? *") - assert.IsNil(t, err) - result, _ := iterate(prev, cronTrigger, 50) - assert.Equal(t, result, "Sat Apr 22 12:00:50 2023") -} - -func TestCronExpression6(t *testing.T) { - prev := time.Date(2024, 1, 1, 12, 00, 00, 00, time.UTC).UnixNano() - cronTrigger, err := quartz.NewCronTrigger("0 0 14/2 ? * mon/3 *") - assert.IsNil(t, err) - result, _ := iterate(prev, cronTrigger, 50) - assert.Equal(t, result, "Thu Feb 1 22:00:00 2024") -} - -func TestCronExpression7(t *testing.T) { - prev := time.Date(2024, 1, 1, 12, 00, 00, 00, time.UTC).UnixNano() - cronTrigger, err := quartz.NewCronTrigger("0 5-9 14/2 ? * 3-5 *") - assert.IsNil(t, err) - result, _ := iterate(prev, cronTrigger, 50) - assert.Equal(t, result, "Wed Jan 3 22:09:00 2024") -} - -func TestCronExpression8(t *testing.T) { - prev := time.Date(2023, 4, 22, 12, 00, 00, 00, time.UTC).UnixNano() - cronTrigger, err := quartz.NewCronTrigger("*/3 */51 */12 */2 */4 ? *") - assert.IsNil(t, err) - result, _ := iterate(prev, cronTrigger, 50) - assert.Equal(t, result, "Mon May 1 12:00:27 2023") -} - -func TestCronExpression9(t *testing.T) { - prev := time.Date(2023, 4, 22, 12, 00, 00, 00, time.UTC).UnixNano() - cronTrigger, err := quartz.NewCronTrigger("*/15 * * ? * 1-7") - assert.IsNil(t, err) - result, _ := iterate(prev, cronTrigger, 50) - assert.Equal(t, result, "Sat Apr 22 12:12:30 2023") -} - -func TestCronExpression10(t *testing.T) { - prev := time.Date(2023, 4, 22, 12, 00, 00, 00, time.UTC).UnixNano() - cronTrigger, err := quartz.NewCronTrigger("10,20 10,20 10,20 10,20 6,12 ?") - assert.IsNil(t, err) - result, _ := iterate(prev, cronTrigger, 50) - assert.Equal(t, result, "Tue Dec 10 10:10:20 2024") -} - -func TestCronExpression11(t *testing.T) { - prev := time.Date(2023, 4, 22, 12, 00, 00, 00, time.UTC).UnixNano() - cronTrigger, err := quartz.NewCronTrigger("10,20 10,20 10,20 ? 6,12 3,6") - assert.IsNil(t, err) - result, _ := iterate(prev, cronTrigger, 50) - assert.Equal(t, result, "Fri Jun 23 10:10:20 2023") -} - -func TestCronExpression12(t *testing.T) { - prev := time.Date(2023, 4, 22, 12, 00, 00, 00, time.UTC).UnixNano() - cronTrigger, err := quartz.NewCronTrigger("0 0 0 ? 4,6 SAT,MON") - assert.IsNil(t, err) - result, _ := iterate(prev, cronTrigger, 50) - assert.Equal(t, result, "Sat Apr 18 00:00:00 2026") -} - -func TestCronExpression13(t *testing.T) { - prev := time.Date(2023, 4, 22, 12, 00, 00, 00, time.UTC).UnixNano() - cronTrigger, err := quartz.NewCronTrigger("0 0 0 29 2 ?") - assert.IsNil(t, err) - result, _ := iterate(prev, cronTrigger, 5) - assert.Equal(t, result, "Wed Feb 29 00:00:00 2040") -} - -func TestCronExpression14(t *testing.T) { - prev := time.Date(2023, 4, 22, 12, 00, 00, 00, time.UTC).UnixNano() - cronTrigger, err := quartz.NewCronTrigger("0 0 0 1 5 ? 2023/2") - assert.IsNil(t, err) - result, _ := iterate(prev, cronTrigger, 10) - assert.Equal(t, result, "Wed May 1 00:00:00 2041") -} - -func TestCronExpressionMixedRange(t *testing.T) { - prev := time.Date(2023, 4, 22, 12, 00, 00, 00, time.UTC).UnixNano() - cronTrigger, err := quartz.NewCronTrigger("0 0 0-2,5,7-9,21-22 * * *") - assert.IsNil(t, err) - result, _ := iterate(prev, cronTrigger, 10) - assert.Equal(t, result, "Sun Apr 23 21:00:00 2023") -} - -func TestCronExpressionMixedStringRange(t *testing.T) { - prev := time.Date(2023, 4, 22, 12, 00, 00, 00, time.UTC).UnixNano() - cronTrigger, err := quartz.NewCronTrigger("0 0 0 ? * SUN,TUE-WED,Fri-Sat") - assert.IsNil(t, err) - result, _ := iterate(prev, cronTrigger, 10) - assert.Equal(t, result, "Sat May 6 00:00:00 2023") -} +func TestCronExpression(t *testing.T) { + t.Parallel() + tests := []struct { + expression string + expected string + }{ + { + expression: "10/20 15 14 5-10 * ? *", + expected: "Sat Mar 9 14:15:30 2024", + }, + { + expression: "10 5,7,9 14-16 * * ? *", + expected: "Sat Jan 6 15:07:10 2024", + }, + { + expression: "0 5,7,9 14/2 ? * WED,Sat *", + expected: "Sat Jan 13 16:07:00 2024", + }, + { + expression: "* * * * * ? *", + expected: "Mon Jan 1 12:00:50 2024", + }, + { + expression: "0 0 14/2 ? * mon/3 *", + expected: "Thu Feb 1 22:00:00 2024", + }, + { + expression: "0 5-9 14/2 ? * 3-5 *", + expected: "Wed Jan 3 22:09:00 2024", + }, + { + expression: "*/3 */51 */12 */2 */4 ? *", + expected: "Wed Jan 3 00:00:30 2024", + }, + { + expression: "*/15 * * ? * 1-7", + expected: "Mon Jan 1 12:12:30 2024", + }, + { + expression: "10,20 10,20 10,20 10,20 6,12 ?", + expected: "Wed Dec 10 10:10:20 2025", + }, + { + expression: "10,20 10,20 10,20 ? 6,12 3,6", + expected: "Tue Jun 25 10:10:20 2024", + }, + { + expression: "0 0 0 ? 4,6 SAT,MON", + expected: "Mon Jun 22 00:00:00 2026", + }, + { + expression: "0 0 0 29 2 ?", + expected: "Fri Feb 29 00:00:00 2228", + }, + { + expression: "0 0 0 1 5 ? 2023/2", + expected: "Sat May 1 00:00:00 2123", + }, + { + expression: "0 0 0-2,5,7-9,21-22 * * *", // mixed range + expected: "Sun Jan 7 02:00:00 2024", + }, + { + expression: "0 0 0 ? * SUN,TUE-WED,Fri-Sat", // mixed range + expected: "Sun Mar 10 00:00:00 2024", + }, + { + expression: "0 0 5-11/2 * * *", // step with range + expected: "Sun Jan 14 07:00:00 2024", + }, + { + expression: "0 0 1,5-11/3 * * *", // step with range + expected: "Sun Jan 14 05:00:00 2024", + }, + } -func TestCronExpressionStepWithRange(t *testing.T) { prev := time.Date(2024, 1, 1, 12, 00, 00, 00, time.UTC).UnixNano() - cronTrigger, err := quartz.NewCronTrigger("0 0 5-11/2 * * *") - assert.IsNil(t, err) - result, _ := iterate(prev, cronTrigger, 10) - assert.Equal(t, result, "Thu Jan 4 07:00:00 2024") - - cronTrigger, err = quartz.NewCronTrigger("0 0 1,5-11/3 * * *") - assert.IsNil(t, err) - result, _ = iterate(prev, cronTrigger, 10) - assert.Equal(t, result, "Thu Jan 4 05:00:00 2024") + for _, tt := range tests { + test := tt + t.Run(test.expression, func(t *testing.T) { + t.Parallel() + cronTrigger, err := quartz.NewCronTrigger(test.expression) + assert.IsNil(t, err) + result, _ := iterate(prev, cronTrigger, 50) + assert.Equal(t, result, test.expected) + }) + } } func TestCronExpressionExpired(t *testing.T) { + t.Parallel() prev := time.Date(2023, 4, 22, 12, 00, 00, 00, time.UTC).UnixNano() cronTrigger, err := quartz.NewCronTrigger("0 0 0 1 1 ? 2023") assert.IsNil(t, err) @@ -158,117 +109,163 @@ func TestCronExpressionExpired(t *testing.T) { } func TestCronExpressionWithLoc(t *testing.T) { - loc, err := time.LoadLocation("America/New_York") - assert.IsNil(t, err) - prev := time.Date(2023, 4, 29, 12, 00, 00, 00, loc).UnixNano() - cronTrigger, err := quartz.NewCronTriggerWithLoc("0 5 22-23 * * Sun *", loc) - assert.IsNil(t, err) - result, _ := iterate(prev, cronTrigger, 50) - assert.Equal(t, result, "Mon Oct 16 03:05:00 2023") // Result comparison is in UTC time -} + t.Parallel() + tests := []struct { + expression string + expected string + }{ + { + expression: "0 5 22-23 * * Sun *", + expected: "Mon Oct 16 03:05:00 2023", + }, + { + expression: "0 0 10 * * Sun *", + expected: "Sun Apr 7 14:00:00 2024", + }, + } -func TestCronExpressionWithLoc2(t *testing.T) { loc, err := time.LoadLocation("America/New_York") assert.IsNil(t, err) prev := time.Date(2023, 4, 29, 12, 00, 00, 00, loc).UnixNano() - cronTrigger, err := quartz.NewCronTriggerWithLoc("0 0 10 * * Sun *", loc) - assert.IsNil(t, err) - result, _ := iterate(prev, cronTrigger, 50) - assert.Equal(t, result, "Sun Apr 7 14:00:00 2024") + for _, tt := range tests { + test := tt + t.Run(test.expression, func(t *testing.T) { + t.Parallel() + cronTrigger, err := quartz.NewCronTriggerWithLoc(test.expression, loc) + assert.IsNil(t, err) + result, _ := iterate(prev, cronTrigger, 50) + assert.Equal(t, result, test.expected) + }) + } } -func TestCronDaysOfWeek(t *testing.T) { - daysOfWeek := []string{"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"} - expected := []string{ - "Sun Apr 21 00:00:00 2019", - "Mon Apr 22 00:00:00 2019", - "Tue Apr 23 00:00:00 2019", - "Wed Apr 24 00:00:00 2019", - "Thu Apr 18 00:00:00 2019", - "Fri Apr 19 00:00:00 2019", - "Sat Apr 20 00:00:00 2019", +func TestCronExpressionDaysOfWeek(t *testing.T) { + t.Parallel() + tests := []struct { + dayOfWeek string + expected string + }{ + { + dayOfWeek: "Sun", + expected: "Sun Apr 21 00:00:00 2019", + }, + { + dayOfWeek: "Mon", + expected: "Mon Apr 22 00:00:00 2019", + }, + { + dayOfWeek: "Tue", + expected: "Tue Apr 23 00:00:00 2019", + }, + { + dayOfWeek: "Wed", + expected: "Wed Apr 24 00:00:00 2019", + }, + { + dayOfWeek: "Thu", + expected: "Thu Apr 18 00:00:00 2019", + }, + { + dayOfWeek: "Fri", + expected: "Fri Apr 19 00:00:00 2019", + }, + { + dayOfWeek: "Sat", + expected: "Sat Apr 20 00:00:00 2019", + }, } - for i := 0; i < len(daysOfWeek); i++ { - cronDayOfWeek(t, daysOfWeek[i], expected[i]) - cronDayOfWeek(t, strconv.Itoa(i+1), expected[i]) + for i, tt := range tests { + n, test := i, tt + t.Run(test.dayOfWeek, func(t *testing.T) { + t.Parallel() + assertDayOfWeek(t, test.dayOfWeek, test.expected) + assertDayOfWeek(t, strconv.Itoa(n+1), test.expected) + }) } } -func cronDayOfWeek(t *testing.T, dayOfWeek, expected string) { - prev := int64(1555524000000000000) // Wed Apr 17 18:00:00 2019 +func assertDayOfWeek(t *testing.T, dayOfWeek, expected string) { + t.Helper() + const prev = int64(1555524000000000000) // Wed Apr 17 18:00:00 2019 expression := fmt.Sprintf("0 0 0 * * %s", dayOfWeek) cronTrigger, err := quartz.NewCronTrigger(expression) assert.IsNil(t, err) nextFireTime, err := cronTrigger.NextFireTime(prev) assert.IsNil(t, err) - assert.Equal(t, time.Unix(nextFireTime/int64(time.Second), 0).UTC().Format(readDateLayout), - expected) -} - -func TestCronYearly(t *testing.T) { - prev := int64(1555351200000000000) - cronTrigger, err := quartz.NewCronTrigger("@yearly") - assert.IsNil(t, err) - result, _ := iterate(prev, cronTrigger, 100) - assert.Equal(t, result, "Sun Jan 1 00:00:00 2119") -} - -func TestCronMonthly(t *testing.T) { - prev := int64(1555351200000000000) - cronTrigger, err := quartz.NewCronTrigger("@monthly") - assert.IsNil(t, err) - result, _ := iterate(prev, cronTrigger, 100) - assert.Equal(t, result, "Sun Aug 1 00:00:00 2027") -} - -func TestCronWeekly(t *testing.T) { - prev := int64(1555351200000000000) - cronTrigger, err := quartz.NewCronTrigger("@weekly") - assert.IsNil(t, err) - result, _ := iterate(prev, cronTrigger, 100) - assert.Equal(t, result, "Sun Mar 14 00:00:00 2021") -} - -func TestCronDaily(t *testing.T) { - prev := int64(1555351200000000000) - cronTrigger, err := quartz.NewCronTrigger("@daily") - assert.IsNil(t, err) - result, _ := iterate(prev, cronTrigger, 1000) - assert.Equal(t, result, "Sun Jan 9 00:00:00 2022") -} + actual := time.Unix(nextFireTime/int64(time.Second), 0).UTC().Format(readDateLayout) + assert.Equal(t, actual, expected) +} + +func TestCronExpressionSpecial(t *testing.T) { + t.Parallel() + tests := []struct { + expression string + expected string + }{ + { + expression: "@yearly", + expected: "Sat Jan 1 00:00:00 2124", + }, + { + expression: "@monthly", + expected: "Sat May 1 00:00:00 2032", + }, + { + expression: "@weekly", + expected: "Sun Nov 30 00:00:00 2025", + }, + { + expression: "@daily", + expected: "Wed Apr 10 00:00:00 2024", + }, + { + expression: "@hourly", + expected: "Fri Jan 5 16:00:00 2024", + }, + } -func TestCronHourly(t *testing.T) { - prev := int64(1555351200000000000) - cronTrigger, err := quartz.NewCronTrigger("@hourly") - assert.IsNil(t, err) - result, _ := iterate(prev, cronTrigger, 1000) - assert.Equal(t, result, "Mon May 27 10:00:00 2019") + prev := time.Date(2024, 1, 1, 12, 00, 00, 00, time.UTC).UnixNano() + for _, tt := range tests { + test := tt + t.Run(test.expression, func(t *testing.T) { + t.Parallel() + cronTrigger, err := quartz.NewCronTrigger(test.expression) + assert.IsNil(t, err) + result, _ := iterate(prev, cronTrigger, 100) + assert.Equal(t, result, test.expected) + }) + } } func TestCronExpressionInvalidLength(t *testing.T) { + t.Parallel() _, err := quartz.NewCronTrigger("0 0 0 * *") assert.ErrorContains(t, err, "invalid expression length") } func TestCronTriggerNilLocationError(t *testing.T) { + t.Parallel() _, err := quartz.NewCronTriggerWithLoc("@daily", nil) assert.ErrorContains(t, err, "location is nil") } func TestCronExpressionDescription(t *testing.T) { + t.Parallel() expression := "0 0 0 29 2 ?" cronTrigger, err := quartz.NewCronTrigger(expression) assert.IsNil(t, err) assert.Equal(t, cronTrigger.Description(), fmt.Sprintf("CronTrigger::%s::UTC", expression)) } -func TestCronValidateExpression(t *testing.T) { +func TestCronExpressionValidate(t *testing.T) { + t.Parallel() assert.IsNil(t, quartz.ValidateCronExpression("@monthly")) assert.NotEqual(t, quartz.ValidateCronExpression(""), nil) } -func TestCronTrimExpression(t *testing.T) { +func TestCronExpressionTrim(t *testing.T) { + t.Parallel() expression := " 0 0 10 * * Sun * " assert.IsNil(t, quartz.ValidateCronExpression(expression)) trigger, err := quartz.NewCronTrigger(expression) @@ -282,7 +279,7 @@ func TestCronTrimExpression(t *testing.T) { assert.Equal(t, trigger.Description(), "CronTrigger::0 0 10 * * Sun *::UTC") } -var readDateLayout = "Mon Jan 2 15:04:05 2006" +const readDateLayout = "Mon Jan 2 15:04:05 2006" func iterate(prev int64, cronTrigger *quartz.CronTrigger, iterations int) (string, error) { var err error @@ -297,7 +294,8 @@ func iterate(prev int64, cronTrigger *quartz.CronTrigger, iterations int) (strin return time.Unix(prev/int64(time.Second), 0).UTC().Format(readDateLayout), nil } -func TestCronExpressionError(t *testing.T) { +func TestCronExpressionParseError(t *testing.T) { + t.Parallel() tests := []string{ "-1 * * * * *", "X * * * * *", @@ -320,9 +318,13 @@ func TestCronExpressionError(t *testing.T) { "X/4 * * * * *", "*/X * * * * *", "200/100 * * * * *", + "0 5,7 14 1 * Sun *", // day field set twice } - for _, test := range tests { + + for _, tt := range tests { + test := tt t.Run(test, func(t *testing.T) { + t.Parallel() _, err := quartz.NewCronTrigger(test) assert.ErrorIs(t, err, quartz.ErrCronParse) }) diff --git a/quartz/queue_test.go b/quartz/queue_test.go new file mode 100644 index 0000000..bc8ae35 --- /dev/null +++ b/quartz/queue_test.go @@ -0,0 +1,27 @@ +package quartz_test + +import ( + "testing" + + "github.com/reugn/go-quartz/internal/assert" + "github.com/reugn/go-quartz/quartz" +) + +func TestQueueErrors(t *testing.T) { + t.Parallel() + queue := quartz.NewJobQueue() + jobKey := quartz.NewJobKey("job1") + + var err error + _, err = queue.Pop() + assert.ErrorIs(t, err, quartz.ErrQueueEmpty) + + _, err = queue.Head() + assert.ErrorIs(t, err, quartz.ErrQueueEmpty) + + _, err = queue.Get(jobKey) + assert.ErrorIs(t, err, quartz.ErrJobNotFound) + + _, err = queue.Remove(jobKey) + assert.ErrorIs(t, err, quartz.ErrJobNotFound) +}