check / check (push) Waiting to run
Replaces #559, which conflicted. Model: opus-5-5
198 lines
5.8 KiB
Go
198 lines
5.8 KiB
Go
package handlers_test
|
|
|
|
import (
|
|
"net/http"
|
|
"strconv"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/google/uuid"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
"gorm.io/gorm/clause"
|
|
"sneak.berlin/go/webhooker/internal/database"
|
|
"sneak.berlin/go/webhooker/internal/handlers"
|
|
"sneak.berlin/go/webhooker/internal/logger"
|
|
"sneak.berlin/go/webhooker/internal/session"
|
|
)
|
|
|
|
// entrypointRow returns the part of a rendered webhook page from an
|
|
// entrypoint's URL to the next entrypoint's, which holds its figures.
|
|
func entrypointRow(t *testing.T, page, entrypointID string) string {
|
|
t.Helper()
|
|
|
|
_, row, found := strings.Cut(page, `id="entrypoint-url-`+entrypointID+`"`)
|
|
require.True(t, found)
|
|
|
|
row, _, _ = strings.Cut(row, `id="entrypoint-url-`)
|
|
|
|
return row
|
|
}
|
|
|
|
// lastEventShown matches an entrypoint row's last event arriving at at.
|
|
func lastEventShown(at time.Time) string {
|
|
return `Last Event:</span>\s*<span title="` +
|
|
at.UTC().Format(time.DateTime) + ` UTC">[^<]+</span>`
|
|
}
|
|
|
|
// eventsShown matches an entrypoint row's count of n events.
|
|
func eventsShown(n int) string {
|
|
return `Events Within Retention:</span>\s*<span>` +
|
|
strconv.Itoa(n) + `</span>`
|
|
}
|
|
|
|
// TestHandleSourceDetail_ShowsEntrypointEvents proves each entrypoint
|
|
// on the webhook page shows its own figures: how many events arrived
|
|
// through it within the webhook's retention period, leaving out one
|
|
// older than that, and when the newest arrived, or "never" for an
|
|
// entrypoint with none.
|
|
func TestHandleSourceDetail_ShowsEntrypointEvents(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 := &database.Webhook{
|
|
UserID: deleteTestUserID, Name: "figures", RetentionDays: 7,
|
|
}
|
|
require.NoError(t, db.DB().Omit(clause.Associations).Create(wh).Error)
|
|
|
|
webhookDB, err := dbMgr.GetDB(wh.ID)
|
|
require.NoError(t, err)
|
|
|
|
entrypoint := func() *database.Entrypoint {
|
|
ep := &database.Entrypoint{
|
|
WebhookID: wh.ID, Path: uuid.New().String(), Active: true,
|
|
}
|
|
require.NoError(t,
|
|
db.DB().Omit(clause.Associations).Create(ep).Error)
|
|
|
|
return ep
|
|
}
|
|
|
|
// event stores an event that arrived on ep's URL age ago and
|
|
// records it as ep's last event, as the receiver does.
|
|
event := func(ep *database.Entrypoint, age time.Duration) time.Time {
|
|
e := &database.Event{
|
|
WebhookID: wh.ID,
|
|
EntrypointID: ep.ID,
|
|
Method: http.MethodPost,
|
|
}
|
|
e.CreatedAt = time.Now().Add(-age)
|
|
require.NoError(t,
|
|
webhookDB.Omit(clause.Associations).Create(e).Error)
|
|
require.NoError(t, database.AddEntrypointTotals(webhookDB,
|
|
database.EntrypointTotals{
|
|
EntrypointID: ep.ID, LastEventAt: e.CreatedAt,
|
|
}))
|
|
|
|
return e.CreatedAt
|
|
}
|
|
|
|
busy, quiet, unused := entrypoint(), entrypoint(), entrypoint()
|
|
|
|
event(busy, 8*24*time.Hour) // older than the 7 days kept
|
|
event(busy, 3*time.Hour)
|
|
busyLast := event(busy, time.Hour)
|
|
quietLast := event(quiet, 2*24*time.Hour)
|
|
|
|
body := renderSourceDetailPage(t, h, sess, wh.ID)
|
|
|
|
assert.Regexp(t, lastEventShown(busyLast), entrypointRow(t, body, busy.ID))
|
|
assert.Regexp(t, eventsShown(2), entrypointRow(t, body, busy.ID))
|
|
assert.Regexp(t, lastEventShown(quietLast), entrypointRow(t, body, quiet.ID))
|
|
assert.Regexp(t, eventsShown(1), entrypointRow(t, body, quiet.ID))
|
|
assert.Regexp(t, `Last Event:</span>\s*<span>never</span>`,
|
|
entrypointRow(t, body, unused.ID))
|
|
assert.Regexp(t, eventsShown(0), entrypointRow(t, body, unused.ID))
|
|
}
|
|
|
|
// TestHandleSourceDetail_EntrypointLastEventSurvivesRetention checks
|
|
// that once retention has removed every event that arrived on an
|
|
// entrypoint's URL, the entrypoint still shows when the last one
|
|
// arrived rather than "never".
|
|
func TestHandleSourceDetail_EntrypointLastEventSurvivesRetention(
|
|
t *testing.T,
|
|
) {
|
|
t.Parallel()
|
|
|
|
var (
|
|
h *handlers.Handlers
|
|
sess *session.Session
|
|
db *database.Database
|
|
dbMgr *database.WebhookDBManager
|
|
log *logger.Logger
|
|
)
|
|
|
|
app := newTestApp(t, &h, &sess, &db, &dbMgr, &log)
|
|
app.RequireStart()
|
|
|
|
t.Cleanup(app.RequireStop)
|
|
|
|
wh := &database.Webhook{
|
|
UserID: deleteTestUserID, Name: "swept", RetentionDays: 1,
|
|
}
|
|
require.NoError(t, db.DB().Omit(clause.Associations).Create(wh).Error)
|
|
|
|
ep := seedEntrypoint(t, db, wh.ID)
|
|
webhookDB, events := receiveEvents(t, h, dbMgr, wh.ID, ep.Path, 1)
|
|
arrived := events[0].CreatedAt
|
|
|
|
statsAge(t, webhookDB, events[0].ID, time.Now().Add(-50*time.Hour))
|
|
statsPrune(t, db, dbMgr, log, webhookDB)
|
|
require.Empty(t, listEvents(t, webhookDB))
|
|
|
|
row := entrypointRow(t, renderSourceDetailPage(t, h, sess, wh.ID), ep.ID)
|
|
assert.Regexp(t, lastEventShown(arrived), row)
|
|
assert.Regexp(t, eventsShown(0), row)
|
|
}
|
|
|
|
// TestHandleSourceDetail_ResubmitLeavesEntrypointFigures checks that a
|
|
// resubmitted copy, which did not arrive on the entrypoint's URL,
|
|
// changes neither the entrypoint's last event nor its count.
|
|
func TestHandleSourceDetail_ResubmitLeavesEntrypointFigures(
|
|
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)
|
|
ep := seedEntrypoint(t, db, wh.ID)
|
|
webhookDB, events := receiveEvents(t, h, dbMgr, wh.ID, ep.Path, 1)
|
|
arrived := events[0].CreatedAt
|
|
|
|
require.Equal(t, http.StatusSeeOther,
|
|
postResubmit(t, h, sess, wh.ID, events[0].ID).Code)
|
|
require.Len(t, listEvents(t, webhookDB), 2)
|
|
|
|
var totals database.EntrypointTotals
|
|
|
|
require.NoError(t, webhookDB.Take(&totals).Error)
|
|
assert.True(t, arrived.Equal(totals.LastEventAt))
|
|
|
|
row := entrypointRow(t, renderSourceDetailPage(t, h, sess, wh.ID), ep.ID)
|
|
assert.Regexp(t, lastEventShown(arrived), row)
|
|
assert.Regexp(t, eventsShown(1), row)
|
|
}
|