carlos / platform Public

schedule: control — DELETE refuses a declared schedule on error too

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Paul Campbell pushed by paul@keymail.dev 501d0ed2bf2b0ba4e7ea933383b6840ee283eb60 parent 5d447e9
2 files changed, +17 −1
  • internal/schedule/control.go +5 −1
  • internal/schedule/control_test.go +12 −0
diff --git a/internal/schedule/control.go b/internal/schedule/control.go
index 693417597..5a5e249dc 100644
--- a/internal/schedule/control.go
+++ b/internal/schedule/control.go
@@ -111,9 +111,13 @@ func Mount(mux *http.ServeMux, host string, store TimerStore, token func() (stri
http.Error(w, "bad name", http.StatusBadRequest)
return
}
- if row, err := store.GetTimer(host, name); err == nil && row.Kind != KindOnce {
+ switch row, err := store.GetTimer(host, name); {
+ case err == nil && row.Kind != KindOnce:
http.Error(w, "name is a declared schedule — remove it with carlos schedule rm", http.StatusConflict)
return
+ case err != nil && !errors.Is(err, os.ErrNotExist):
+ http.Error(w, "registry error", http.StatusInternalServerError)
+ return
}
if err := store.DeleteTimer(host, name); err != nil {
http.Error(w, "registry error", http.StatusInternalServerError)
diff --git a/internal/schedule/control_test.go b/internal/schedule/control_test.go
index 3349da0d0..13bd412b5 100644
--- a/internal/schedule/control_test.go
+++ b/internal/schedule/control_test.go
@@ -110,6 +110,18 @@ func TestControlRefusals(t *testing.T) {
}
}
+func TestControlDeleteRefusesDeclaredSchedule(t *testing.T) {
+ reg, mux := controlFixture(t)
+ reg.UpsertTimer(registry.Timer{Host: "a.bab.oncarlos.com", Name: "sync", Kind: KindSchedule, Spec: "every 6h0m0s", Path: "/s", NextAt: 1})
+ if rec := do(mux, "DELETE", "/schedule/sync", "Bearer tok", ""); rec.Code != http.StatusConflict {
+ t.Fatalf("delete declared schedule = %d, want 409 (%s)", rec.Code, rec.Body)
+ }
+ tm, err := reg.GetTimer("a.bab.oncarlos.com", "sync")
+ if err != nil || tm == nil || tm.Kind != KindSchedule {
+ t.Fatalf("row did not survive the refused delete: %v, err=%v", tm, err)
+ }
+}
+
func TestControlCapsOncePerHost(t *testing.T) {
reg, mux := controlFixture(t)
for i := 0; i < MaxOncePerHost; i++ {