Files
orbit/pulse/schedule/planner_test.go

57 lines
2.3 KiB
Go

package schedule
import (
"testing"
"time"
)
func TestMisfireOverlapAndBoundedCatchup(t *testing.T) {
start := stamp("2026-09-17T00:00:00Z")
c, err := Compile(Rule{Kind: "FIXED_RATE", Timezone: "UTC", StartAt: start, IntervalMS: 1000})
if err != nil {
t.Fatal(err)
}
base := Policy{Misfire: "CATCH_UP", Overlap: "PARALLEL", CatchupLimit: 3, CatchupWindowMS: 10000, GraceMS: 1000}
for _, tc := range []struct {
name, misfire, overlap string
active bool
kinds []string
next int
blocked bool
}{
{"catchup", "CATCH_UP", "PARALLEL", false, []string{"SKIPPED", "FIRED", "FIRED", "FIRED"}, 13, false},
{"coalesce", "COALESCE", "PARALLEL", false, []string{"SKIPPED", "COALESCED"}, 21, false},
{"skip", "SKIP", "PARALLEL", false, []string{"SKIPPED", "SKIPPED", "FIRED", "FIRED"}, 21, false},
{"serial_wait", "CATCH_UP", "SERIAL", true, []string{"SKIPPED"}, 10, true},
{"serial_one", "CATCH_UP", "SERIAL", false, []string{"SKIPPED", "FIRED"}, 11, false},
{"overlap_skip", "CATCH_UP", "SKIP", true, []string{"SKIPPED", "SKIPPED"}, 21, false},
} {
t.Run(tc.name, func(t *testing.T) {
p := base
p.Misfire = tc.misfire
p.Overlap = tc.overlap
out, err := Plan(c, p, start, start.Add(20*time.Second), nil, tc.active)
if err != nil || out.Next == nil || !out.Next.Equal(start.Add(time.Duration(tc.next)*time.Second)) || out.Blocked != tc.blocked || len(out.Decisions) != len(tc.kinds) {
t.Fatalf("unexpected batch %+v %v", out, err)
}
for i, kind := range tc.kinds {
if out.Decisions[i].Kind != kind {
t.Fatal("wrong decision", out.Decisions)
}
}
})
}
// 旧版本只覆盖生效边界之前,不能把新版本的时间合并进去。
before := start.Add(15 * time.Second)
base.Misfire = "COALESCE"
out, err := Plan(c, base, start, start.Add(20*time.Second), &before, false)
if err != nil || out.Next != nil || len(out.Decisions) != 2 || !out.Decisions[1].CoveredUntil.Equal(before) {
t.Fatalf("version boundary lost: %+v %v", out, err)
}
// 未到期不产生记录;同一快照重算得到同一原触发点。
out, err = Plan(c, base, start, start.Add(-time.Second), nil, false)
if err != nil || len(out.Decisions) != 0 || out.Next == nil || !out.Next.Equal(start) {
t.Fatal("future point processed")
}
}