Say what each action did in a one-line notice (closes #383)
check / check (push) Waiting to run
check / check (push) Waiting to run
Every action on the webhook pages, and signing out, redirects with a fixed notice code in the URL, and the page it lands on shows one line saying what was done. noticeFor maps codes to fixed text and an unknown code shows nothing, so nothing from the URL is echoed. One partial, templates/notice.html, shows the line under the navbar on every page; the error page shows none. Replay and resubmit use the same codes and partial in place of their own query parameters and event log banners. Model: opus-5-5
This commit is contained in:
@@ -260,6 +260,24 @@ func (e *testEnv) urlFrom(
|
||||
return html.UnescapeString(match[1])
|
||||
}
|
||||
|
||||
// requireNotice requires w to redirect to dest carrying the notice
|
||||
// code, then renders that page and requires it to show text.
|
||||
func (e *testEnv) requireNotice(
|
||||
t *testing.T,
|
||||
w *httptest.ResponseRecorder,
|
||||
dest, code, text string,
|
||||
cookies []*http.Cookie,
|
||||
) {
|
||||
t.Helper()
|
||||
|
||||
require.Equal(t, http.StatusSeeOther, w.Code)
|
||||
require.Equal(t, dest+"?notice="+code, w.Header().Get("Location"))
|
||||
|
||||
page := e.get(w.Header().Get("Location"), cookies)
|
||||
require.Equal(t, http.StatusOK, page.Code)
|
||||
assert.Contains(t, page.Body.String(), text)
|
||||
}
|
||||
|
||||
// authCookies forges an authenticated session for the given user.
|
||||
func (e *testEnv) authCookies(
|
||||
t *testing.T,
|
||||
@@ -738,6 +756,31 @@ func TestPagesLogin_ReturnsToTheRequestedPage(t *testing.T) {
|
||||
assert.Equal(t, asked, w.Header().Get("Location"))
|
||||
}
|
||||
|
||||
// TestPagesLogout_SaysSignedOut signs out with the navbar's form and
|
||||
// lands on the sign-in page, which says so.
|
||||
func TestPagesLogout_SaysSignedOut(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
env := newTestEnv(t)
|
||||
|
||||
userID, _ := env.seedUser(t, "leaver", "somepassword")
|
||||
token, cookies := env.csrfFrom(
|
||||
t, "/hooks", env.authCookies(t, userID, "leaver"),
|
||||
)
|
||||
|
||||
form := url.Values{}
|
||||
form.Set("csrf_token", token)
|
||||
|
||||
w := env.post(
|
||||
env.urlFrom(t, "/hooks", `action="(/pages/logout)"`, cookies),
|
||||
form, cookies,
|
||||
)
|
||||
|
||||
// The sign-in page is requested without the session cookie, which
|
||||
// the logout told the browser to delete.
|
||||
env.requireNotice(t, w, "/pages/login", "signed-out", "Signed out.", nil)
|
||||
}
|
||||
|
||||
// --- /user/{username} group ---
|
||||
|
||||
// TestPasswordChange_OversizeBody_RejectedAndPasswordUnchanged
|
||||
@@ -855,9 +898,9 @@ func TestHooks_ListAndNewWebhookForm(t *testing.T) {
|
||||
require.NoError(t,
|
||||
env.db.DB().Where("name = ?", "created").First(&created).Error,
|
||||
)
|
||||
assert.Equal(
|
||||
t, "/hook/"+created.ID, w.Header().Get("Location"),
|
||||
"creating a webhook should redirect to its page",
|
||||
env.requireNotice(
|
||||
t, w, "/hook/"+created.ID, "webhook-created", "Webhook created.",
|
||||
cookies,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -888,8 +931,7 @@ func TestHook_EditFormAndDelete(t *testing.T) {
|
||||
env.urlFrom(t, editPage, `action="(/hook/[^/"]+/edit)"`, cookies),
|
||||
form, cookies,
|
||||
)
|
||||
require.Equal(t, http.StatusSeeOther, w.Code)
|
||||
assert.Equal(t, page, w.Header().Get("Location"))
|
||||
env.requireNotice(t, w, page, "webhook-saved", "Webhook saved.", cookies)
|
||||
|
||||
var edited database.Webhook
|
||||
|
||||
@@ -903,16 +945,17 @@ func TestHook_EditFormAndDelete(t *testing.T) {
|
||||
env.urlFrom(t, page, `action="(/hook/[^/"]+/delete)"`, cookies),
|
||||
form, cookies,
|
||||
)
|
||||
require.Equal(t, http.StatusSeeOther, w.Code)
|
||||
assert.Equal(t, "/hooks", w.Header().Get("Location"))
|
||||
env.requireNotice(
|
||||
t, w, "/hooks", "webhook-deleted", "Webhook deleted.", cookies,
|
||||
)
|
||||
assert.Equal(
|
||||
t, http.StatusNotFound, env.get(page, cookies).Code,
|
||||
"a deleted webhook's page should be gone",
|
||||
)
|
||||
}
|
||||
|
||||
// TestHook_EntrypointActions adds, deactivates and deletes an
|
||||
// entrypoint with the forms on the webhook page, each submitted to
|
||||
// TestHook_EntrypointActions adds, deactivates, activates and deletes
|
||||
// an entrypoint with the forms on the webhook page, each submitted to
|
||||
// the action and with the token the page rendered.
|
||||
func TestHook_EntrypointActions(t *testing.T) {
|
||||
t.Parallel()
|
||||
@@ -930,16 +973,19 @@ func TestHook_EntrypointActions(t *testing.T) {
|
||||
form.Set("csrf_token", token)
|
||||
|
||||
// submit posts the webhook page's form whose action pattern
|
||||
// captures, and requires the redirect back to that page.
|
||||
submit := func(pattern string) {
|
||||
// captures, and requires the redirect back to that page with the
|
||||
// notice code, and the page to show text.
|
||||
submit := func(pattern, code, text string) {
|
||||
t.Helper()
|
||||
|
||||
w := env.post(env.urlFrom(t, page, pattern, cookies), form, cookies)
|
||||
require.Equal(t, http.StatusSeeOther, w.Code)
|
||||
require.Equal(t, page, w.Header().Get("Location"))
|
||||
env.requireNotice(t, w, page, code, text, cookies)
|
||||
}
|
||||
|
||||
submit(`action="(/hook/[^/"]+/entrypoints)"`)
|
||||
toggle := `action="(/hook/[^/"]+/entrypoints/[^/"]+/toggle)"`
|
||||
|
||||
submit(`action="(/hook/[^/"]+/entrypoints)"`,
|
||||
"entrypoint-added", "Entrypoint added.")
|
||||
|
||||
var added database.Entrypoint
|
||||
|
||||
@@ -948,7 +994,7 @@ func TestHook_EntrypointActions(t *testing.T) {
|
||||
)
|
||||
require.True(t, added.Active)
|
||||
|
||||
submit(`action="(/hook/[^/"]+/entrypoints/[^/"]+/toggle)"`)
|
||||
submit(toggle, "entrypoint-deactivated", "Entrypoint deactivated.")
|
||||
|
||||
var toggled database.Entrypoint
|
||||
|
||||
@@ -957,7 +1003,10 @@ func TestHook_EntrypointActions(t *testing.T) {
|
||||
)
|
||||
assert.False(t, toggled.Active, "the toggle should deactivate it")
|
||||
|
||||
submit(`action="(/hook/[^/"]+/entrypoints/[^/"]+/delete)"`)
|
||||
submit(toggle, "entrypoint-activated", "Entrypoint activated.")
|
||||
|
||||
submit(`action="(/hook/[^/"]+/entrypoints/[^/"]+/delete)"`,
|
||||
"entrypoint-deleted", "Entrypoint deleted.")
|
||||
|
||||
var left int64
|
||||
|
||||
@@ -968,8 +1017,8 @@ func TestHook_EntrypointActions(t *testing.T) {
|
||||
|
||||
// TestHook_TargetActions adds a target with the form on the webhook
|
||||
// page, follows its Edit link to the target edit form and submits
|
||||
// it, then deactivates and deletes it, every URL and token taken from
|
||||
// the rendered pages.
|
||||
// it, then deactivates, activates and deletes it, every URL and token
|
||||
// taken from the rendered pages.
|
||||
func TestHook_TargetActions(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
@@ -984,27 +1033,29 @@ func TestHook_TargetActions(t *testing.T) {
|
||||
|
||||
// submit posts form, with the token, to the action pattern
|
||||
// captures on the page at from, and requires the redirect back to
|
||||
// the webhook page.
|
||||
submit := func(from, pattern string, form url.Values) {
|
||||
// the webhook page with the notice code, and that page to show
|
||||
// text.
|
||||
submit := func(from, pattern string, form url.Values, code, text string) {
|
||||
t.Helper()
|
||||
|
||||
form.Set("csrf_token", token)
|
||||
|
||||
w := env.post(env.urlFrom(t, from, pattern, cookies), form, cookies)
|
||||
require.Equal(t, http.StatusSeeOther, w.Code)
|
||||
require.Equal(t, page, w.Header().Get("Location"))
|
||||
env.requireNotice(t, w, page, code, text, cookies)
|
||||
}
|
||||
|
||||
toggle := `action="(/hook/[^/"]+/targets/[^/"]+/toggle)"`
|
||||
|
||||
submit(page, `action="(/hook/[^/"]+/targets)"`, url.Values{
|
||||
"name": {"added"},
|
||||
"type": {string(database.TargetTypeLog)},
|
||||
})
|
||||
}, "target-added", "Target added.")
|
||||
|
||||
editPage := env.urlFrom(
|
||||
t, page, `href="(/hook/[^/"]+/targets/[^/"]+/edit)"`, cookies,
|
||||
)
|
||||
submit(editPage, `action="(/hook/[^/"]+/targets/[^/"]+/edit)"`,
|
||||
url.Values{"name": {"renamed"}})
|
||||
url.Values{"name": {"renamed"}}, "target-saved", "Target saved.")
|
||||
|
||||
var edited database.Target
|
||||
|
||||
@@ -1014,8 +1065,8 @@ func TestHook_TargetActions(t *testing.T) {
|
||||
assert.Equal(t, "renamed", edited.Name)
|
||||
require.True(t, edited.Active)
|
||||
|
||||
submit(page, `action="(/hook/[^/"]+/targets/[^/"]+/toggle)"`,
|
||||
url.Values{})
|
||||
submit(page, toggle, url.Values{},
|
||||
"target-deactivated", "Target deactivated.")
|
||||
|
||||
var toggled database.Target
|
||||
|
||||
@@ -1024,8 +1075,11 @@ func TestHook_TargetActions(t *testing.T) {
|
||||
)
|
||||
assert.False(t, toggled.Active, "the toggle should deactivate it")
|
||||
|
||||
submit(page, toggle, url.Values{},
|
||||
"target-activated", "Target activated.")
|
||||
|
||||
submit(page, `action="(/hook/[^/"]+/targets/[^/"]+/delete)"`,
|
||||
url.Values{})
|
||||
url.Values{}, "target-deleted", "Target deleted.")
|
||||
|
||||
var left int64
|
||||
|
||||
@@ -1061,9 +1115,9 @@ func TestHook_ResubmitFromEventLog(t *testing.T) {
|
||||
env.urlFrom(t, logsPath, `action="(/hook/[^"]+/resubmit)"`, cookies),
|
||||
form, cookies,
|
||||
)
|
||||
require.Equal(t, http.StatusSeeOther, w.Code)
|
||||
assert.Equal(
|
||||
t, logsPath+"?resubmit=no-targets", w.Header().Get("Location"),
|
||||
env.requireNotice(
|
||||
t, w, logsPath, "resubmit-no-targets",
|
||||
"this source has no active targets", cookies,
|
||||
)
|
||||
|
||||
webhookDB, err := env.dbMgr.GetDB(wh.ID)
|
||||
@@ -1299,10 +1353,8 @@ func TestDeliveryReplay_PostOnlyAndCSRFProtected(t *testing.T) {
|
||||
html.UnescapeString(action[1]), form, cookies,
|
||||
)
|
||||
|
||||
require.Equal(t, http.StatusSeeOther, w.Code)
|
||||
assert.Equal(
|
||||
t, logsPath+"?replay=queued",
|
||||
w.Header().Get("Location"),
|
||||
env.requireNotice(
|
||||
t, w, logsPath, "replay-queued", "Replay queued:", cookies,
|
||||
)
|
||||
assert.Equal(
|
||||
t, int64(2), env.countDeliveries(t, wh.ID),
|
||||
|
||||
Reference in New Issue
Block a user