Say what a database or log target's attempt did, without a status (closes #388)
check / check (push) Successful in 3m20s

A database or log target sends no HTTP request, yet each of its attempts
read "success  Status: — (no response)", which for an http target means
a failed connection. The shared attempt template now reads a successful
database attempt as "archived" and a successful log attempt as "written
to the log", and shows no status for either, in the event log and on the
event's page. http and slack attempts are unchanged. One test per target
type, plus one for a failed database attempt, checks both pages.

Model: opus-5-5
This commit is contained in:
2026-10-03 00:33:24 +00:00
committed by sneak
parent f1da5e73dd
commit 8514c1e042
3 changed files with 98 additions and 1 deletions
+4
View File
@@ -1899,6 +1899,10 @@ retries) is individually logged for full observability.
| `error` | string | Error message (on failure) |
| `duration` | integer | Request duration in milliseconds |
A `database` or `log` target sends no HTTP request, so in the event log and
on the event's page its attempts show no status: a successful one reads
"archived" or "written to the log".
**Relations:** Belongs to Delivery.
#### EventTotals, TargetTotals and EntrypointTotals
@@ -0,0 +1,89 @@
package handlers_test
import (
"net/http"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"gorm.io/gorm/clause"
"sneak.berlin/go/webhooker/internal/database"
)
// TestDeliveryAttempts_ReadInTheTargetTypesOwnTerms proves, on the
// event's page and in the event log, that an http or slack attempt
// shows its status as before, while a database or log attempt, which
// sends no HTTP request, says what it did and shows no status.
func TestDeliveryAttempts_ReadInTheTargetTypesOwnTerms(t *testing.T) {
t.Parallel()
cases := []struct {
targetType database.TargetType
success bool
statusCode int
errText string
outcome string
status string // "" when the attempt must show no status
}{
{
database.TargetTypeHTTP, false, 0, "",
"failure", "Status: — (no response)",
},
{
database.TargetTypeSlack, true, http.StatusOK, "",
"success", "Status: 200",
},
{database.TargetTypeDatabase, true, 0, "", "archived", ""},
{
database.TargetTypeDatabase, false, 0,
"opening archive database: disk full", "failure", "",
},
{database.TargetTypeLog, true, 0, "", "written to the log", ""},
}
for _, tc := range cases {
t.Run(string(tc.targetType), func(t *testing.T) {
t.Parallel()
f := newRecentEventsFixture(t)
target := seedTarget(t, f.db, f.webhook.ID, tc.targetType)
event := f.event(t, contentTypeJSON, "{}", time.Now())
dlv := f.delivery(
t, event, target.ID, database.DeliveryStatusDelivered,
)
require.NoError(t, f.webhookDB.Omit(clause.Associations).Create(
&database.DeliveryResult{
DeliveryID: dlv.ID,
AttemptNum: 1,
Success: tc.success,
StatusCode: tc.statusCode,
Error: tc.errText,
},
).Error)
w := serveEventPage(t, f.h, f.sess, f.webhook.ID, event.ID)
require.Equal(t, http.StatusOK, w.Code)
pages := []string{
w.Body.String(),
renderSourceLogsPage(t, f.h, f.sess, f.webhook.ID),
}
for _, page := range pages {
assert.Contains(t, page, ">"+tc.outcome+"</span>")
if tc.errText != "" {
assert.Contains(t, page, "Error: "+tc.errText)
}
if tc.status == "" {
assert.NotContains(t, page, "Status:")
} else {
assert.Contains(t, page, tc.status)
}
}
})
}
}
+5 -1
View File
@@ -5,11 +5,15 @@
<p class="text-xs text-gray-500">{{.AttemptsOmitted}} attempt{{if ne .AttemptsOmitted 1}}s{{end}} omitted between the first and last shown.</p>
{{end}}
{{range .Results}}
{{/* Inside this loop, dot is one attempt and $ the whole delivery. */}}
<div class="rounded-md bg-white border border-gray-200 p-2">
<div class="flex flex-wrap items-center gap-3 text-xs">
<span class="text-gray-500">Attempt {{.AttemptNum}}</span>
<span class="{{if .Success}}text-green-600{{else}}text-red-600{{end}}">{{if .Success}}success{{else}}failure{{end}}</span>
<span class="{{if .Success}}text-green-600{{else}}text-red-600{{end}}">{{if not .Success}}failure{{else if eq $.Target.Type "database"}}archived{{else if eq $.Target.Type "log"}}written to the log{{else}}success{{end}}</span>
{{/* A database or log target sends no HTTP request, so its attempts have no status code. */}}
{{if not (eq $.Target.Type "database" "log")}}
<span class="text-gray-500">Status: {{if .HasStatusCode}}{{.StatusCode}}{{else}}&mdash; (no response){{end}}</span>
{{end}}
<span class="text-gray-500">Duration: {{.DurationMS}} ms</span>
</div>
{{if .Error}}