first commit
Some checks failed
Backend Tests / Static Checks (push) Has been cancelled
Backend Tests / Tests (other) (push) Has been cancelled
Backend Tests / Tests (plugin) (push) Has been cancelled
Backend Tests / Tests (server) (push) Has been cancelled
Backend Tests / Tests (store) (push) Has been cancelled
Build Canary Image / build-frontend (push) Has been cancelled
Build Canary Image / build-push (linux/amd64) (push) Has been cancelled
Build Canary Image / build-push (linux/arm64) (push) Has been cancelled
Build Canary Image / merge (push) Has been cancelled
Frontend Tests / Lint (push) Has been cancelled
Frontend Tests / Build (push) Has been cancelled
Proto Linter / Lint Protos (push) Has been cancelled
Some checks failed
Backend Tests / Static Checks (push) Has been cancelled
Backend Tests / Tests (other) (push) Has been cancelled
Backend Tests / Tests (plugin) (push) Has been cancelled
Backend Tests / Tests (server) (push) Has been cancelled
Backend Tests / Tests (store) (push) Has been cancelled
Build Canary Image / build-frontend (push) Has been cancelled
Build Canary Image / build-push (linux/amd64) (push) Has been cancelled
Build Canary Image / build-push (linux/arm64) (push) Has been cancelled
Build Canary Image / merge (push) Has been cancelled
Frontend Tests / Lint (push) Has been cancelled
Frontend Tests / Build (push) Has been cancelled
Proto Linter / Lint Protos (push) Has been cancelled
This commit is contained in:
127
plugin/scheduler/parser_test.go
Normal file
127
plugin/scheduler/parser_test.go
Normal file
@@ -0,0 +1,127 @@
|
||||
package scheduler
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestParseCronExpression(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
expr string
|
||||
wantErr bool
|
||||
}{
|
||||
// Standard 5-field format
|
||||
{"every minute", "* * * * *", false},
|
||||
{"hourly", "0 * * * *", false},
|
||||
{"daily midnight", "0 0 * * *", false},
|
||||
{"weekly sunday", "0 0 * * 0", false},
|
||||
{"monthly", "0 0 1 * *", false},
|
||||
{"specific time", "30 14 * * *", false}, // 2:30 PM daily
|
||||
{"range", "0 9-17 * * *", false}, // Every hour 9 AM - 5 PM
|
||||
{"step", "*/15 * * * *", false}, // Every 15 minutes
|
||||
{"list", "0 8,12,18 * * *", false}, // 8 AM, 12 PM, 6 PM
|
||||
|
||||
// 6-field format with seconds
|
||||
{"with seconds", "0 * * * * *", false},
|
||||
{"every 30 seconds", "*/30 * * * * *", false},
|
||||
|
||||
// Invalid expressions
|
||||
{"empty", "", true},
|
||||
{"too few fields", "* * *", true},
|
||||
{"too many fields", "* * * * * * *", true},
|
||||
{"invalid minute", "60 * * * *", true},
|
||||
{"invalid hour", "0 24 * * *", true},
|
||||
{"invalid day", "0 0 32 * *", true},
|
||||
{"invalid month", "0 0 1 13 *", true},
|
||||
{"invalid weekday", "0 0 * * 8", true},
|
||||
{"garbage", "not a cron expression", true},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
schedule, err := ParseCronExpression(tt.expr)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("ParseCronExpression(%q) error = %v, wantErr %v", tt.expr, err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
if !tt.wantErr && schedule == nil {
|
||||
t.Errorf("ParseCronExpression(%q) returned nil schedule without error", tt.expr)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestScheduleNext(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
expr string
|
||||
from time.Time
|
||||
expected time.Time
|
||||
}{
|
||||
{
|
||||
name: "every minute from start of hour",
|
||||
expr: "* * * * *",
|
||||
from: time.Date(2025, 1, 1, 10, 0, 0, 0, time.UTC),
|
||||
expected: time.Date(2025, 1, 1, 10, 1, 0, 0, time.UTC),
|
||||
},
|
||||
{
|
||||
name: "hourly at minute 30",
|
||||
expr: "30 * * * *",
|
||||
from: time.Date(2025, 1, 1, 10, 0, 0, 0, time.UTC),
|
||||
expected: time.Date(2025, 1, 1, 10, 30, 0, 0, time.UTC),
|
||||
},
|
||||
{
|
||||
name: "hourly at minute 30 (already past)",
|
||||
expr: "30 * * * *",
|
||||
from: time.Date(2025, 1, 1, 10, 45, 0, 0, time.UTC),
|
||||
expected: time.Date(2025, 1, 1, 11, 30, 0, 0, time.UTC),
|
||||
},
|
||||
{
|
||||
name: "daily at 2 AM",
|
||||
expr: "0 2 * * *",
|
||||
from: time.Date(2025, 1, 1, 10, 0, 0, 0, time.UTC),
|
||||
expected: time.Date(2025, 1, 2, 2, 0, 0, 0, time.UTC),
|
||||
},
|
||||
{
|
||||
name: "every 15 minutes",
|
||||
expr: "*/15 * * * *",
|
||||
from: time.Date(2025, 1, 1, 10, 7, 0, 0, time.UTC),
|
||||
expected: time.Date(2025, 1, 1, 10, 15, 0, 0, time.UTC),
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
schedule, err := ParseCronExpression(tt.expr)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to parse expression: %v", err)
|
||||
}
|
||||
|
||||
next := schedule.Next(tt.from)
|
||||
if !next.Equal(tt.expected) {
|
||||
t.Errorf("Next(%v) = %v, expected %v", tt.from, next, tt.expected)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestScheduleNextWithTimezone(t *testing.T) {
|
||||
nyc, _ := time.LoadLocation("America/New_York")
|
||||
|
||||
// Schedule for 9 AM in New York
|
||||
schedule, err := ParseCronExpression("0 9 * * *")
|
||||
if err != nil {
|
||||
t.Fatalf("failed to parse expression: %v", err)
|
||||
}
|
||||
|
||||
// Current time: 8 AM in New York
|
||||
from := time.Date(2025, 1, 1, 8, 0, 0, 0, nyc)
|
||||
next := schedule.Next(from)
|
||||
|
||||
// Should be 9 AM same day in New York
|
||||
expected := time.Date(2025, 1, 1, 9, 0, 0, 0, nyc)
|
||||
if !next.Equal(expected) {
|
||||
t.Errorf("Next(%v) = %v, expected %v", from, next, expected)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user