v0.38.0 58133ea

cron_test.go RawHistoryFolder

1package scheduler
2
3import (
4	"testing"
5	"time"
6)
7
8func TestParseCronNext(t *testing.T) {
9	loc := time.FixedZone("UTC+2", 2*60*60)
10	schedule, err := ParseCron("*/15 9-10 * * 1-5", loc)
11	if err != nil {
12		t.Fatalf("ParseCron() error = %v", err)
13	}
14
15	after := time.Date(2026, time.August, 14, 9, 14, 45, 0, loc) // Friday
16	want := time.Date(2026, time.August, 14, 9, 15, 0, 0, loc)
17	if got := schedule.Next(after); !got.Equal(want) {
18		t.Fatalf("Next() = %v, want %v", got, want)
19	}
20}
21
22func TestParseCronDayOfMonthOrDayOfWeek(t *testing.T) {
23	loc := time.UTC
24	schedule, err := ParseCron("0 9 15 * 1", loc)
25	if err != nil {
26		t.Fatalf("ParseCron() error = %v", err)
27	}
28
29	// Vixie cron semantics: when both fields are restricted, either match is
30	// sufficient. Monday 2026-06-08 is not the fifteenth.
31	after := time.Date(2026, time.June, 7, 9, 0, 0, 0, loc)
32	want := time.Date(2026, time.June, 8, 9, 0, 0, 0, loc)
33	if got := schedule.Next(after); !got.Equal(want) {
34		t.Fatalf("Next() = %v, want %v", got, want)
35	}
36}
37
38func TestParseCronDSTTransitions(t *testing.T) {
39	loc, err := time.LoadLocation("America/New_York")
40	if err != nil {
41		t.Fatalf("LoadLocation() error = %v", err)
42	}
43	fallBack, err := ParseCron("30 1 * * *", loc)
44	if err != nil {
45		t.Fatalf("ParseCron() error = %v", err)
46	}
47	first := fallBack.Next(time.Date(2026, time.November, 1, 0, 59, 0, 0, loc))
48	second := fallBack.Next(first)
49	if first.Hour() != 1 || first.Minute() != 30 || second.Hour() != 1 || second.Minute() != 30 || first.Equal(second) || second.Sub(first) != time.Hour {
50		t.Fatalf("fall-back occurrences = %v, %v; want 01:30 exactly one elapsed hour apart", first, second)
51	}
52
53	springForward, err := ParseCron("30 2 * * *", loc)
54	if err != nil {
55		t.Fatalf("ParseCron() error = %v", err)
56	}
57	got := springForward.Next(time.Date(2026, time.March, 8, 1, 59, 0, 0, loc))
58	want := time.Date(2026, time.March, 9, 2, 30, 0, 0, loc)
59	if !got.Equal(want) {
60		t.Fatalf("spring-forward Next() = %v, want %v", got, want)
61	}
62}
63
64func TestParseCronRejectsInvalidField(t *testing.T) {
65	if _, err := ParseCron("61 * * * *", time.UTC); err == nil {
66		t.Fatal("ParseCron() error = nil, want invalid minute error")
67	}
68}
69
70func TestParseCronSupportsMacro(t *testing.T) {
71	schedule, err := ParseCron("@daily", time.UTC)
72	if err != nil {
73		t.Fatalf("ParseCron() error = %v", err)
74	}
75	got := schedule.Next(time.Date(2026, time.August, 14, 23, 59, 0, 0, time.UTC))
76	want := time.Date(2026, time.August, 15, 0, 0, 0, 0, time.UTC)
77	if !got.Equal(want) {
78		t.Fatalf("Next() = %v, want %v", got, want)
79	}
80}

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 1

Tags 476

↑↓ moveenter openesc close