package console import ( "net/http" "net/url" "testing" "github.com/carlosframework/platform/internal/registry" "github.com/carlosframework/platform/internal/release" ) func TestBrowserAppRestartUsesSharedGeneration(t *testing.T) { fx := newConsoleFixture(t) c := signInPaul(t, fx) csrf := sessionToken(t, fx, c) status, _, _ := postForm(t, c, fx.u("/apps/kass/restart"), url.Values{"csrf": {csrf}}) if status != http.StatusOK { t.Fatalf("confirm = %d", status) } if restartGenEtag(t, fx, "kass") != "" || len(scopeLog(t, fx, "kass").Requests) != 0 { t.Fatal("confirmation page wrote restart state") } status, loc, _ := postGated(t, fx, c, fx.u("/apps/kass/restart"), url.Values{"csrf": {csrf}, "confirmed": {"1"}}) if status != http.StatusSeeOther || loc != fx.path("/apps/kass/instances") { t.Fatalf("restart = %d -> %q", status, loc) } if restartGenEtag(t, fx, "kass") == "" { t.Fatal("browser restart did not touch app generation") } if got := serial(t, fx); got != 1 { t.Fatalf("serial = %d", got) } } func TestBrowserInstanceRestartIsExactAndNeverWidens(t *testing.T) { fx := newConsoleFixture(t) fx.addRoute(t, registry.Route{Host: "sleep.kass.test", App: "kass", Account: "bab", Kind: "instance", Status: "ready", Hibernate: true}) c := signInPaul(t, fx) csrf := sessionToken(t, fx, c) endpoint := fx.u("/apps/kass/instances/sleep.kass.test/restart") status, _, _ := postGated(t, fx, c, endpoint, url.Values{"csrf": {csrf}, "confirmed": {"1"}}) if status != http.StatusSeeOther { t.Fatalf("restart = %d", status) } if restartGenEtag(t, fx, "kass") != "" { t.Fatal("instance restart widened into app generation") } log := scopeLog(t, fx, "kass") if len(log.Requests) != 1 || log.Requests[0].Scope.Kind != release.RestartScopeHost || log.Requests[0].Scope.Value != "sleep.kass.test" { t.Fatalf("scope log = %+v", log) } reg, _ := registry.Open(fx.regPath) routes, _ := reg.List() for _, rt := range routes { if rt.Host == "sleep.kass.test" && !rt.Hibernate { t.Fatal("restart request woke sleeping route") } } } func TestBrowserInstanceRestartRefusesUnaddressableHosts(t *testing.T) { fx := newConsoleFixture(t) fx.addRoute(t, registry.Route{Host: "foreign.test", App: "kass", Account: "elsewhere", Kind: "instance", Status: "ready"}) c := signInPaul(t, fx) csrf := sessionToken(t, fx, c) for _, host := range []string{"missing.test", "foreign.test", "docs.kass.carlosapp.dev", "%20", "%09", "%20%20"} { status, _, body := postGated(t, fx, c, fx.u("/apps/kass/instances/"+host+"/restart"), url.Values{"csrf": {csrf}, "confirmed": {"1"}}) if status != http.StatusNotFound || body != "404 page not found\n" { t.Errorf("%s = %d %q", host, status, body) } } if restartGenEtag(t, fx, "kass") != "" || len(scopeLog(t, fx, "kass").Requests) != 0 { t.Fatal("refusal wrote restart state") } } func TestBrowserRestartRequiresCSRF(t *testing.T) { fx := newConsoleFixture(t) c := signInPaul(t, fx) status, _, _ := postForm(t, c, fx.u("/apps/kass/restart"), url.Values{"csrf": {"wrong"}}) if status != http.StatusForbidden { t.Fatalf("csrf = %d", status) } status, _, _ = postForm(t, c, fx.u("/apps/no-such-app/restart"), url.Values{"csrf": {"wrong"}}) if status != http.StatusForbidden { t.Fatalf("csrf before app membership = %d", status) } }