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:\s*[1-9][0-9.]* [kM]?B`, 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") require.True(t, found, "the page has no targets section") list, _, _ = strings.Cut(list, "]*>`).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:") }