check / check (push) Successful in 3m17s
Each row of the webhook page's target list now shows the target's delivered and failed deliveries, in total and in the last 24 hours. The totals are the target's running totals, so retention does not reduce them; the 24-hour figures are counted over that window of the deliveries' status index, in one query for all targets. Deliveries still pending or retrying count in neither. Model: opus-5-5
175 lines
5.6 KiB
Go
175 lines
5.6 KiB
Go
package handlers_test
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"regexp"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
"sneak.berlin/go/webhooker/internal/database"
|
|
"sneak.berlin/go/webhooker/internal/delivery"
|
|
"sneak.berlin/go/webhooker/internal/handlers"
|
|
"sneak.berlin/go/webhooker/internal/logger"
|
|
"sneak.berlin/go/webhooker/internal/session"
|
|
)
|
|
|
|
// TestHandleSourceDetail_ShowsArchiveFile proves a database target's
|
|
// row names its archive file and says "not created yet" before the
|
|
// first write, adds the file's size and last write once it has one row,
|
|
// and says "not created yet" again once the file has been moved away.
|
|
// A target of another type shows no archive file.
|
|
func TestHandleSourceDetail_ShowsArchiveFile(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)
|
|
archive := seedTarget(t, db, wh.ID, database.TargetTypeDatabase)
|
|
seedTarget(t, db, wh.ID, database.TargetTypeLog)
|
|
|
|
path := delivery.ArchivePath(dbMgr, wh, archive)
|
|
|
|
body := renderSourceDetailPage(t, h, sess, wh.ID)
|
|
assert.Equal(t, 1, strings.Count(body, "Archive File:"))
|
|
assert.Contains(t, body, filepath.Base(path))
|
|
assert.Contains(t, body, "not created yet")
|
|
assert.NotContains(t, body, "Archive Size:")
|
|
|
|
seedArchive(t, path, 1, 100)
|
|
|
|
file, err := os.Stat(path)
|
|
require.NoError(t, err)
|
|
|
|
body = renderSourceDetailPage(t, h, sess, wh.ID)
|
|
assert.Contains(t, body, filepath.Base(path))
|
|
assert.NotContains(t, body, "not created yet")
|
|
assert.Regexp(t,
|
|
`Archive Size:</span>\s*<span>[1-9][0-9.]* [kM]?B</span>`, body,
|
|
)
|
|
assert.Contains(t, body,
|
|
`title="`+file.ModTime().UTC().Format(time.DateTime)+` UTC"`,
|
|
)
|
|
|
|
require.NoError(t, os.Rename(path, filepath.Join(t.TempDir(), "moved.db")))
|
|
|
|
body = renderSourceDetailPage(t, h, sess, wh.ID)
|
|
assert.Contains(t, body, filepath.Base(path))
|
|
assert.Contains(t, body, "not created yet")
|
|
assert.NotContains(t, body, "Archive Size:")
|
|
}
|
|
|
|
// targetList returns the text of the targets section in a rendered
|
|
// webhook page, from its heading to the next heading, with the markup
|
|
// taken out and each run of space made one space. Each target's row
|
|
// then reads as its name, type, state and buttons, followed by the
|
|
// lines below them.
|
|
func targetList(t *testing.T, page string) string {
|
|
t.Helper()
|
|
|
|
_, list, found := strings.Cut(page, ">Targets</h2>")
|
|
require.True(t, found, "the page has no targets section")
|
|
|
|
list, _, _ = strings.Cut(list, "<h2")
|
|
list = regexp.MustCompile(`<[^>]*>`).ReplaceAllString(list, " ")
|
|
|
|
return strings.Join(strings.Fields(list), " ")
|
|
}
|
|
|
|
// TestHandleSourceDetail_ShowsTargetDeliveries checks each target row's
|
|
// delivered and failed deliveries, in total and in the last 24 hours,
|
|
// for the history seedStatsHistory builds, before and after the real
|
|
// retention reaper removes the oldest event. The http target has one
|
|
// delivered, one of them in the last 24 hours, and three failed, one of
|
|
// them in the last 24 hours and one of them the oldest event's, which
|
|
// retention removes without changing the total. The active log target
|
|
// has two failed, both in the last 24 hours, and its pending and
|
|
// retrying deliveries count in neither. The four inactive log targets
|
|
// have none.
|
|
func TestHandleSourceDetail_ShowsTargetDeliveries(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)
|
|
|
|
hist := seedStatsHistory(t, h, sess, db, dbMgr)
|
|
|
|
const (
|
|
httpRow = "Delivered: 1 in total, 1 in the last 24 hours " +
|
|
"Failed: 3 in total, 1 in the last 24 hours"
|
|
activeLogRow = "t-log log Active Edit Deactivate Delete " +
|
|
"Delivered: 0 in total, 0 in the last 24 hours " +
|
|
"Failed: 2 in total, 2 in the last 24 hours"
|
|
inactiveLogRow = "t-log log Inactive Edit Activate Delete " +
|
|
"Delivered: 0 in total, 0 in the last 24 hours " +
|
|
"Failed: 0 in total, 0 in the last 24 hours"
|
|
)
|
|
|
|
list := targetList(t, renderSourceDetailPage(t, h, sess, hist.webhook.ID))
|
|
assert.Equal(t, 1, strings.Count(list, httpRow))
|
|
assert.Equal(t, 1, strings.Count(list, activeLogRow))
|
|
assert.Equal(t, 4, strings.Count(list, inactiveLogRow))
|
|
|
|
statsPrune(t, db, dbMgr, log, hist.webhookDB)
|
|
|
|
list = targetList(t, renderSourceDetailPage(t, h, sess, hist.webhook.ID))
|
|
assert.Equal(t, 1, strings.Count(list, httpRow))
|
|
assert.Equal(t, 1, strings.Count(list, activeLogRow))
|
|
assert.Equal(t, 4, strings.Count(list, inactiveLogRow))
|
|
}
|
|
|
|
// TestHandleSourceDetail_TargetDeliveriesUnreadable checks that when the
|
|
// webhook's event database cannot be read, each target's row says so
|
|
// instead of showing zeros.
|
|
func TestHandleSourceDetail_TargetDeliveriesUnreadable(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)
|
|
seedTarget(t, db, wh.ID, database.TargetTypeLog)
|
|
|
|
webhookDB, err := dbMgr.GetDB(wh.ID)
|
|
require.NoError(t, err)
|
|
require.NoError(t,
|
|
webhookDB.Migrator().DropTable(&database.TargetTotals{}))
|
|
|
|
list := targetList(t, renderSourceDetailPage(t, h, sess, wh.ID))
|
|
assert.Contains(t, list, "t-log log Active Edit Deactivate Delete "+
|
|
"The delivery counts could not be read.")
|
|
assert.NotContains(t, list, "Delivered:")
|
|
}
|