T1.4: Create src/scheduler; move scheduler logic
Move scheduler.go and scheduler_test.go from src/core to the new src/scheduler package. The scheduler still takes *[]domain.Job and *core.Store (storage moves in T1.5). Update src/gui/app.go to import the new package; rename the local variable to sched to avoid shadowing the scheduler package name. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,110 @@
|
||||
package scheduler
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"gitea.mixdep.ru/mix/gosentry/src/domain"
|
||||
)
|
||||
|
||||
func TestNextRunTimeRejectsInvalidSchedules(t *testing.T) {
|
||||
from := time.Date(2026, 6, 14, 12, 0, 0, 0, time.UTC)
|
||||
cases := []struct {
|
||||
schedule string
|
||||
desc string
|
||||
}{
|
||||
{"", "empty string"},
|
||||
{" ", "whitespace only"},
|
||||
{"@every", "bare @every without duration"},
|
||||
{"@every xyz", "invalid @every duration string"},
|
||||
{"@every -1s", "negative @every duration"},
|
||||
{"@every 0s", "zero @every duration"},
|
||||
{"not-a-cron", "invalid cron expression"},
|
||||
{"60 * * * *", "cron minute out of range"},
|
||||
}
|
||||
for _, tc := range cases {
|
||||
_, ok := nextRunTime(tc.schedule, from)
|
||||
if ok {
|
||||
t.Errorf("nextRunTime(%q) [%s]: expected false, got true", tc.schedule, tc.desc)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestPrepareNextRunSetsDisplayString(t *testing.T) {
|
||||
jobs := []domain.Job{{Schedule: "*/5 * * * *", Enabled: true}}
|
||||
s := &Scheduler{jobs: &jobs}
|
||||
from := time.Date(2026, 6, 14, 12, 3, 0, 0, time.UTC)
|
||||
|
||||
s.prepareNextRun(&jobs[0], from)
|
||||
|
||||
want := "2026-06-14 12:05:00"
|
||||
if jobs[0].NextRun != want {
|
||||
t.Errorf("NextRun: got %q, want %q", jobs[0].NextRun, want)
|
||||
}
|
||||
wantDue := time.Date(2026, 6, 14, 12, 5, 0, 0, time.UTC)
|
||||
if !jobs[0].NextDue.Equal(wantDue) {
|
||||
t.Errorf("NextDue: got %v, want %v", jobs[0].NextDue, wantDue)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPrepareNextRunSetsInvalidScheduleLabel(t *testing.T) {
|
||||
jobs := []domain.Job{{Schedule: "not-a-cron", Enabled: true}}
|
||||
s := &Scheduler{jobs: &jobs}
|
||||
|
||||
s.prepareNextRun(&jobs[0], time.Now())
|
||||
|
||||
if jobs[0].NextRun != "Invalid schedule" {
|
||||
t.Errorf("NextRun: got %q, want 'Invalid schedule'", jobs[0].NextRun)
|
||||
}
|
||||
if !jobs[0].NextDue.IsZero() {
|
||||
t.Errorf("NextDue should be zero for invalid schedule, got %v", jobs[0].NextDue)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNextRunTimeSupportsEvery(t *testing.T) {
|
||||
from := time.Date(2026, 6, 14, 12, 0, 0, 0, time.UTC)
|
||||
next, ok := nextRunTime("@every 10s", from)
|
||||
if !ok {
|
||||
t.Fatal("expected @every schedule to parse")
|
||||
}
|
||||
if want := from.Add(10 * time.Second); !next.Equal(want) {
|
||||
t.Fatalf("expected %s, got %s", want, next)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNextRunTimeSupportsCron(t *testing.T) {
|
||||
from := time.Date(2026, 6, 14, 12, 3, 0, 0, time.UTC)
|
||||
next, ok := nextRunTime("*/5 * * * *", from)
|
||||
if !ok {
|
||||
t.Fatal("expected cron schedule to parse")
|
||||
}
|
||||
want := time.Date(2026, 6, 14, 12, 5, 0, 0, time.UTC)
|
||||
if !next.Equal(want) {
|
||||
t.Fatalf("expected %s, got %s", want, next)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunningOutputIncludesInvocation(t *testing.T) {
|
||||
started := time.Date(2026, 6, 17, 23, 40, 0, 0, time.Local)
|
||||
job := domain.Job{
|
||||
Name: "Backup",
|
||||
Command: `C:\Program Files\FreeFileSync\FreeFileSync.exe`,
|
||||
Arguments: `D:\Local\Jobs\Auto.ffs_batch`,
|
||||
SuccessExitCodes: "0,1",
|
||||
}
|
||||
|
||||
output := runningOutput(job, "Manual", started)
|
||||
for _, want := range []string{
|
||||
"Running since 2026-06-17 23:40:00",
|
||||
"Manual",
|
||||
job.Command,
|
||||
job.Arguments,
|
||||
"0,1",
|
||||
"start_only",
|
||||
} {
|
||||
if !strings.Contains(output, want) {
|
||||
t.Fatalf("expected running output to contain %q, got:\n%s", want, output)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user