145 lines
3.9 KiB
Go
145 lines
3.9 KiB
Go
package handlers_test
|
|
|
|
import (
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
"sneak.berlin/go/webhooker/internal/database"
|
|
"sneak.berlin/go/webhooker/internal/handlers"
|
|
"sneak.berlin/go/webhooker/internal/session"
|
|
)
|
|
|
|
// deletedMarker is the suffix the event log appends to the name
|
|
// of a target that no longer exists.
|
|
const deletedMarker = " (deleted)"
|
|
|
|
// deleteTargetThroughHandler removes a target through the real
|
|
// deletion handler, so the test soft-deletes exactly the way the
|
|
// UI does rather than by writing the timestamp itself.
|
|
func deleteTargetThroughHandler(
|
|
t *testing.T,
|
|
h *handlers.Handlers,
|
|
sess *session.Session,
|
|
webhookID, targetID string,
|
|
) {
|
|
t.Helper()
|
|
|
|
req := postRequest(
|
|
"/source/"+webhookID+"/targets/"+targetID+"/delete",
|
|
authenticatedCookies(
|
|
t, sess, deleteTestUserID, deleteTestUsername,
|
|
),
|
|
map[string]string{
|
|
paramSourceID: webhookID,
|
|
paramTargetID: targetID,
|
|
},
|
|
)
|
|
w := httptest.NewRecorder()
|
|
|
|
h.HandleTargetDelete().ServeHTTP(w, req)
|
|
|
|
require.Equal(t, http.StatusSeeOther, w.Code)
|
|
}
|
|
|
|
// TestHandleSourceLogs_NamesDeletedTarget proves a delivery
|
|
// produced by a since-deleted target still names it on the event
|
|
// log, marked as deleted.
|
|
//
|
|
// Deletes are soft and deliveries carry no foreign key to the
|
|
// target row, so the history outlives the target. Against a
|
|
// scoped lookup the delivery resolves to a zero view and the page
|
|
// renders ": delivered" with nothing saying what it was delivered
|
|
// to.
|
|
func TestHandleSourceLogs_NamesDeletedTarget(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
var (
|
|
h *handlers.Handlers
|
|
sess *session.Session
|
|
db *database.Database
|
|
dbMgr *database.WebhookDBManager
|
|
)
|
|
|
|
app := newTestApp(t, &h, &sess, &db, &dbMgr)
|
|
app.RequireStart()
|
|
|
|
t.Cleanup(app.RequireStop)
|
|
|
|
wh := seedWebhook(t, db)
|
|
tgt := seedTarget(t, db, wh.ID, database.TargetTypeLog)
|
|
|
|
seedDeliveredEvent(t, dbMgr, wh.ID, tgt.ID)
|
|
|
|
// The control: the name is on the page while the target
|
|
// lives, and is not yet marked as deleted.
|
|
before := renderSourceLogsPage(t, h, sess, wh.ID)
|
|
assert.Contains(t, before, tgt.Name)
|
|
assert.NotContains(t, before, tgt.Name+deletedMarker)
|
|
|
|
deleteTargetThroughHandler(t, h, sess, wh.ID, tgt.ID)
|
|
|
|
after := renderSourceLogsPage(t, h, sess, wh.ID)
|
|
|
|
assert.Contains(
|
|
t, after, tgt.Name+deletedMarker,
|
|
"a delivery from a deleted target must keep its name, "+
|
|
"marked as no longer existing",
|
|
)
|
|
assert.Contains(
|
|
t, after, "delivered",
|
|
"the delivery history itself must survive the delete",
|
|
)
|
|
}
|
|
|
|
// TestHandleSourceLogs_MasksDeletedTargetConfig proves that
|
|
// naming a deleted target does not widen what the page shows of
|
|
// it: its stored configuration stays masked by exactly the rules
|
|
// a live target's is.
|
|
//
|
|
// The lookup behind the name reads soft-deleted rows, so it
|
|
// carries a full target row — credential blob included — into the
|
|
// place a zero value used to sit. The projection to TargetView is
|
|
// what keeps that blob away from the template, and it must hold
|
|
// for a deleted row too.
|
|
func TestHandleSourceLogs_MasksDeletedTargetConfig(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
var (
|
|
h *handlers.Handlers
|
|
sess *session.Session
|
|
db *database.Database
|
|
dbMgr *database.WebhookDBManager
|
|
)
|
|
|
|
app := newTestApp(t, &h, &sess, &db, &dbMgr)
|
|
app.RequireStart()
|
|
|
|
t.Cleanup(app.RequireStop)
|
|
|
|
wh := seedWebhook(t, db)
|
|
tgt := seedConfiguredTarget(
|
|
t, db, wh.ID,
|
|
database.TargetTypeSlack,
|
|
`{"webhookUrl":"`+slackWebhookURL+`"}`,
|
|
)
|
|
|
|
seedDeliveredEvent(t, dbMgr, wh.ID, tgt.ID)
|
|
deleteTargetThroughHandler(t, h, sess, wh.ID, tgt.ID)
|
|
|
|
body := renderSourceLogsPage(t, h, sess, wh.ID)
|
|
|
|
assert.NotContains(t, body, slackSecretPath)
|
|
assert.NotContains(t, body, "T00000000")
|
|
assert.NotContains(t, body, "B00000000")
|
|
assert.NotContains(
|
|
t, body, "XXXXXXXXXXXXXXXXXXXXXXXX",
|
|
)
|
|
assert.NotContains(t, body, "webhookUrl")
|
|
|
|
// The name is there; only the credential is not.
|
|
assert.Contains(t, body, tgt.Name+deletedMarker)
|
|
}
|