Review round 2 F3 (ADR 0517 §3, 1858/AC5): acted=1 stayed in the address, so a reload, a restored tab or a bookmark of it recorded no page opened or opened. An act's 303 (and a mode chosen) now sets mail_acted for 10 seconds, HttpOnly and SameSite=Strict, Secure but on 127.0.0.1; the next list or pane it reaches records nothing and clears it; the address carries no marker. The local run keeps the browser's other cookies.
103 lines
4.4 KiB
Go
103 lines
4.4 KiB
Go
package web
|
|
|
|
// Review rounds 1 and 2, F1 and F3 (novox/hq ADR 0517 §3, §5: no act writes two lines; the page opened is
|
|
// last looked): the page shown after an act — reached once, by the act's own short-lived cookie, or by the
|
|
// script's refresh — records nothing; any other opening of that same address records as ever, and the
|
|
// address carries no marker.
|
|
|
|
import (
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"net/url"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
// getWith is a GET of path carrying cookies and headers, answering the recorder.
|
|
func getWith(s http.Handler, path string, cookies []*http.Cookie, header map[string]string) *httptest.ResponseRecorder {
|
|
r := newGet(path, nil)
|
|
for _, c := range cookies {
|
|
r.AddCookie(c)
|
|
}
|
|
for k, v := range header {
|
|
r.Header.Set(k, v)
|
|
}
|
|
return serve(s, r)
|
|
}
|
|
|
|
// postAct posts form to path with the session's cookie, answering the recorder.
|
|
func postAct(s http.Handler, path string, form url.Values, cookie *http.Cookie) *httptest.ResponseRecorder {
|
|
r := httptest.NewRequest(http.MethodPost, path, strings.NewReader(form.Encode()))
|
|
r.Host = testHost
|
|
r.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
|
r.AddCookie(cookie)
|
|
return serve(s, r)
|
|
}
|
|
|
|
func actedCookie(w *httptest.ResponseRecorder) *http.Cookie {
|
|
for _, c := range w.Result().Cookies() {
|
|
if c.Name == ActedCookie {
|
|
return c
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// 1859/AC5, 1858/AC4, AC5: after a tick, a reminder, a correction or a mode chosen, the page it goes back to
|
|
// records nothing, once; opening that same address again records page opened (or opened, for a mail).
|
|
func TestThePageAfterAnActRecordsNothingOnceAndThenAsEver(t *testing.T) {
|
|
for _, tc := range []struct {
|
|
path, again string
|
|
form url.Values
|
|
}{
|
|
{"/item", "page opened", url.Values{"id": {"3"}, "item": {"task 1"}, "mode": {"everything"}, "act": {"handle"}}},
|
|
{"/item", "page opened", url.Values{"id": {"3"}, "item": {"task 1"}, "mode": {"everything"}, "act": {"remind"}}},
|
|
{"/mode", "page opened", url.Values{"mode": {"everything"}}},
|
|
{"/correct", "opened", url.Values{"id": {"3"}, "mode": {"everything"}, "read-later": {"on"}}},
|
|
} {
|
|
reading, b := paneBundle(t)
|
|
s, session, token := signedIn(t, b)
|
|
tc.form.Set(FormTokenField, token)
|
|
w := postAct(s, tc.path, tc.form, session)
|
|
back := w.Header().Get("Location")
|
|
if w.Code != http.StatusSeeOther || strings.Contains(back, "acted") {
|
|
t.Fatalf("%s: status %d to %q; want 303 to an address with no marker", tc.path, w.Code, back)
|
|
}
|
|
acted := actedCookie(w)
|
|
if acted == nil || acted.MaxAge <= 0 || acted.MaxAge > 60 || !acted.HttpOnly || acted.SameSite != http.SameSiteStrictMode {
|
|
t.Fatalf("%s: the act's cookie %+v, want a short-lived, HttpOnly, SameSite=Strict one", tc.path, acted)
|
|
}
|
|
before := len(reading.callsOf("record")) // the mode chosen is its own one line
|
|
shown := getWith(s, back, []*http.Cookie{session, acted}, nil)
|
|
if shown.Code != http.StatusOK || len(reading.callsOf("record")) != before {
|
|
t.Fatalf("%s: the page after it (%s): status %d, records %v; want nothing recorded", tc.path, back, shown.Code, reading.callsOf("record"))
|
|
}
|
|
if cleared := actedCookie(shown); cleared == nil || cleared.MaxAge >= 0 {
|
|
t.Fatalf("%s: the page after it did not clear the act's cookie: %+v", tc.path, cleared)
|
|
}
|
|
// A reload, the tab restored the next morning, a bookmark: the same address, without the cookie.
|
|
getWith(s, back, []*http.Cookie{session}, nil)
|
|
rec := reading.callsOf("record")
|
|
if len(rec) != before+1 || rec[len(rec)-1].Args["what"] != tc.again {
|
|
t.Fatalf("%s: opening %s again recorded %v; want one %s more", tc.path, back, rec, tc.again)
|
|
}
|
|
}
|
|
}
|
|
|
|
// The script's own refresh after an act records nothing; opening the page and a mail record one line each.
|
|
func TestTheScriptsRefreshRecordsNothing(t *testing.T) {
|
|
reading, b := paneBundle(t)
|
|
s, session, _ := signedIn(t, b)
|
|
for _, path := range []string{"/?mode=everything", "/read?id=3&mode=everything"} {
|
|
getWith(s, path, []*http.Cookie{session}, map[string]string{RefreshHeader: "1"})
|
|
}
|
|
if rec := reading.callsOf("record"); len(rec) != 0 {
|
|
t.Fatalf("the script's refreshes recorded %v, want nothing", rec)
|
|
}
|
|
getWith(s, "/?mode=everything", []*http.Cookie{session}, nil)
|
|
getWith(s, "/read?id=3&mode=everything", []*http.Cookie{session}, nil)
|
|
if rec := reading.callsOf("record"); len(rec) != 2 || rec[0].Args["what"] != "page opened" || rec[1].Args["what"] != "opened" {
|
|
t.Fatalf("opening the page and a mail recorded %v, want page opened then opened", rec)
|
|
}
|
|
}
|