Loading internal/api/api_test.go +3 −0 Changes for internal/api/api_test.go: 3 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -1853,6 +1853,9 @@ func (c *fakeCluster) WorldVolumeExists(_ context.Context, n string) (bool, erro } func (c *fakeCluster) SetDesiredState(_ context.Context, n string, s v1alpha1.DesiredState) error { if _, ok := c.byName[n]; !ok { return ErrNotFound // the MinecraftServer is gone, as K8sCluster.getServer reports it } if err := c.wakeErr[n]; err != nil && s == v1alpha1.DesiredRunning { return err } Loading internal/api/handlers_stop_test.go 0 → 100644 +66 −0 Changes for internal/api/handlers_stop_test.go: 66 added lines, 0 removed lines. Original line number Diff line number Diff line package api import ( "net/http" "testing" "felis.lolicon.best/internal/apis/felis/v1alpha1" ) // A stop flips desiredState to Stopped for the server's owner or an admin. A // server whose database row outlived its MinecraftServer answers 404 not_found, // the same as a wake of it, where it used to be an opaque 500. func TestStop(t *testing.T) { mk := func(p *Principal, inCluster bool) (*API, *fakeCluster, *fakeRepo) { repo := newFakeRepo() repo.byName["survival"] = &ServerRecord{Name: "survival", OwnerID: "u1"} cl := newFakeCluster() if inCluster { cl.byName["survival"] = &ServerInfo{Name: "survival", DesiredState: string(v1alpha1.DesiredRunning)} } api := newTestAPI(repo, cl) api.External = staticExternal{p: p} return api, cl, repo } owner := &Principal{UserID: "u1", Role: "user"} stop := func(api *API) (int, string) { w := do(api.ExternalHandler(), "POST", "/api/v1/servers/survival/stop", "", nil) if w.Code == http.StatusAccepted { return w.Code, "" } return w.Code, decodeErr(t, w) } t.Run("the owner stops it", func(t *testing.T) { api, cl, repo := mk(owner, true) if code, e := stop(api); code != http.StatusAccepted { t.Fatalf("stop = %d %s, want 202", code, e) } if cl.desired["survival"] != v1alpha1.DesiredStopped { t.Fatalf("desired = %q, want Stopped", cl.desired["survival"]) } if len(repo.audits) != 1 || repo.audits[0].Action != "stop" || repo.audits[0].ServerName != "survival" { t.Fatalf("audits = %+v, want one stop of survival", repo.audits) } }) t.Run("someone else is refused", func(t *testing.T) { api, cl, repo := mk(&Principal{UserID: "u2", Role: "user"}, true) if code, e := stop(api); code != http.StatusForbidden || e != "forbidden" { t.Fatalf("stop = %d %s, want 403 forbidden", code, e) } if _, set := cl.desired["survival"]; set || len(repo.audits) != 0 { t.Fatalf("a refused stop wrote desired=%v audits=%+v", cl.desired, repo.audits) } }) t.Run("its MinecraftServer is gone", func(t *testing.T) { api, _, repo := mk(owner, false) if code, e := stop(api); code != http.StatusNotFound || e != "not_found" { t.Fatalf("stop = %d %s, want 404 not_found", code, e) } if len(repo.audits) != 0 { t.Fatalf("audits = %+v, want none", repo.audits) } }) } internal/api/handlers_user.go +1 −1 Changes for internal/api/handlers_user.go: 1 added line, 1 removed line. Original line number Diff line number Diff line Loading @@ -112,7 +112,7 @@ func (a *API) handleStop(w http.ResponseWriter, r *http.Request) { } if err := a.Cluster.SetDesiredState(r.Context(), name, v1alpha1.DesiredStopped); err != nil { writeError(w, r, err) a.writeLookupError(w, r, err) // a row whose MinecraftServer is gone is 404, as for a wake return } a.audit(r, "stop", name) Loading Loading
internal/api/api_test.go +3 −0 Changes for internal/api/api_test.go: 3 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -1853,6 +1853,9 @@ func (c *fakeCluster) WorldVolumeExists(_ context.Context, n string) (bool, erro } func (c *fakeCluster) SetDesiredState(_ context.Context, n string, s v1alpha1.DesiredState) error { if _, ok := c.byName[n]; !ok { return ErrNotFound // the MinecraftServer is gone, as K8sCluster.getServer reports it } if err := c.wakeErr[n]; err != nil && s == v1alpha1.DesiredRunning { return err } Loading
internal/api/handlers_stop_test.go 0 → 100644 +66 −0 Changes for internal/api/handlers_stop_test.go: 66 added lines, 0 removed lines. Original line number Diff line number Diff line package api import ( "net/http" "testing" "felis.lolicon.best/internal/apis/felis/v1alpha1" ) // A stop flips desiredState to Stopped for the server's owner or an admin. A // server whose database row outlived its MinecraftServer answers 404 not_found, // the same as a wake of it, where it used to be an opaque 500. func TestStop(t *testing.T) { mk := func(p *Principal, inCluster bool) (*API, *fakeCluster, *fakeRepo) { repo := newFakeRepo() repo.byName["survival"] = &ServerRecord{Name: "survival", OwnerID: "u1"} cl := newFakeCluster() if inCluster { cl.byName["survival"] = &ServerInfo{Name: "survival", DesiredState: string(v1alpha1.DesiredRunning)} } api := newTestAPI(repo, cl) api.External = staticExternal{p: p} return api, cl, repo } owner := &Principal{UserID: "u1", Role: "user"} stop := func(api *API) (int, string) { w := do(api.ExternalHandler(), "POST", "/api/v1/servers/survival/stop", "", nil) if w.Code == http.StatusAccepted { return w.Code, "" } return w.Code, decodeErr(t, w) } t.Run("the owner stops it", func(t *testing.T) { api, cl, repo := mk(owner, true) if code, e := stop(api); code != http.StatusAccepted { t.Fatalf("stop = %d %s, want 202", code, e) } if cl.desired["survival"] != v1alpha1.DesiredStopped { t.Fatalf("desired = %q, want Stopped", cl.desired["survival"]) } if len(repo.audits) != 1 || repo.audits[0].Action != "stop" || repo.audits[0].ServerName != "survival" { t.Fatalf("audits = %+v, want one stop of survival", repo.audits) } }) t.Run("someone else is refused", func(t *testing.T) { api, cl, repo := mk(&Principal{UserID: "u2", Role: "user"}, true) if code, e := stop(api); code != http.StatusForbidden || e != "forbidden" { t.Fatalf("stop = %d %s, want 403 forbidden", code, e) } if _, set := cl.desired["survival"]; set || len(repo.audits) != 0 { t.Fatalf("a refused stop wrote desired=%v audits=%+v", cl.desired, repo.audits) } }) t.Run("its MinecraftServer is gone", func(t *testing.T) { api, _, repo := mk(owner, false) if code, e := stop(api); code != http.StatusNotFound || e != "not_found" { t.Fatalf("stop = %d %s, want 404 not_found", code, e) } if len(repo.audits) != 0 { t.Fatalf("audits = %+v, want none", repo.audits) } }) }
internal/api/handlers_user.go +1 −1 Changes for internal/api/handlers_user.go: 1 added line, 1 removed line. Original line number Diff line number Diff line Loading @@ -112,7 +112,7 @@ func (a *API) handleStop(w http.ResponseWriter, r *http.Request) { } if err := a.Cluster.SetDesiredState(r.Context(), name, v1alpha1.DesiredStopped); err != nil { writeError(w, r, err) a.writeLookupError(w, r, err) // a row whose MinecraftServer is gone is 404, as for a wake return } a.audit(r, "stop", name) Loading