mirror of
https://github.com/Dvorinka/Containr.git
synced 2026-10-28 07:41:27 +00:00
test: cron schedule + webhook URL + canvas layout coverage (#73)
- calculateNextRun: field-count, garbage, bad-zone errors; CRON_TZ actually shifts the instant (UTC vs Asia/Tokyo) - validWebhookURL: http/https only, host required, whitespace trimmed - canvas layout math extracted to canvas/layout.ts (component files may only export components) and covered: rectsOverlap gap zone, resolveFreeSpot grid-snap/collision/bounds-fallback, groupSlot fit/append/grow/ignore-dragged, buildMetadataFromFlow serialization Generated with [Devin](https://devin.ai) Co-authored-by: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
1 parent
c4307034ec
commit
a6b8397dd8
5 files changed
+408
-159
No files matched your search
@@ -0,0 +1,66 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestCalculateNextRun(t *testing.T) {
|
||||
cases := []struct {
|
||||
name string
|
||||
schedule string
|
||||
timezone string
|
||||
wantErr bool
|
||||
}{
|
||||
{"every minute", "* * * * *", "", false},
|
||||
{"daily at 4am", "0 4 * * *", "UTC", false},
|
||||
{"weekday run", "0 9 * * 1-5", "Europe/Prague", false},
|
||||
{"whitespace tolerated", " */15 * * * * ", "", false},
|
||||
{"empty schedule", "", "", true},
|
||||
{"bad field count", "* * *", "", true},
|
||||
{"garbage", "not a cron", "", true},
|
||||
{"bad timezone", "0 4 * * *", "Mars/Olympus", true},
|
||||
}
|
||||
now := time.Now()
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
next, err := calculateNextRun(tc.schedule, tc.timezone)
|
||||
if tc.wantErr {
|
||||
if err == nil {
|
||||
t.Fatalf("expected error, got next=%v", next)
|
||||
}
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if next == nil {
|
||||
t.Fatal("expected non-nil next run")
|
||||
}
|
||||
if !next.After(now) {
|
||||
t.Errorf("next run %v is not after %v", next, now)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestCalculateNextRunTimezone(t *testing.T) {
|
||||
// CRON_TZ must change the computed instant: 04:00 in a fixed-offset zone
|
||||
// lands at a different UTC hour than 04:00 UTC.
|
||||
utcNext, err := calculateNextRun("0 4 * * *", "UTC")
|
||||
if err != nil {
|
||||
t.Fatalf("utc: %v", err)
|
||||
}
|
||||
tokyoNext, err := calculateNextRun("0 4 * * *", "Asia/Tokyo")
|
||||
if err != nil {
|
||||
t.Fatalf("tokyo: %v", err)
|
||||
}
|
||||
if utcNext.Equal(*tokyoNext) {
|
||||
t.Fatalf("timezone had no effect: both %v", utcNext)
|
||||
}
|
||||
if !strings.EqualFold(utcNext.Location().String(), "Local") {
|
||||
// UTC-scheduled runs still land in server-local time representation.
|
||||
t.Logf("utc next: %v / tokyo next: %v", utcNext, tokyoNext)
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user