Offer no Replay for a delivery to a deleted target (closes #387) #483
@@ -1856,7 +1856,11 @@ deliver where the destination has since been fixed. A target that has
|
||||
been deleted or deactivated therefore refuses the replay with a
|
||||
message on the event log rather than delivering from stale
|
||||
configuration, and a replay is refused while an earlier one for the
|
||||
same event and target is still pending or retrying.
|
||||
same event and target is still pending or retrying. A delivery whose
|
||||
target has been deleted shows no **Replay** action at all: recreating
|
||||
the target makes a new one that the old delivery does not name, so
|
||||
**Resubmit** is how that event reaches the webhook's currently active
|
||||
targets.
|
||||
|
||||
**Resubmit.** Replay recovers one delivery; **resubmit** re-injects one
|
||||
EVENT. The event log offers a per-event **Resubmit** action that stores
|
||||
|
||||
@@ -21,7 +21,9 @@ const (
|
||||
// replayTargetDeleted reports a target that once existed and has
|
||||
// since been deleted. Deletes are soft and deliveries carry no
|
||||
// foreign key to the target row, so the history survives its
|
||||
// target and this is the ordinary case for an old event.
|
||||
// target and this is the ordinary case for an old event. The
|
||||
// event log shows no Replay button for such a delivery, so only
|
||||
// a page loaded before the delete reaches this.
|
||||
replayTargetDeleted noticeCode = "replay-target-deleted"
|
||||
|
||||
// replayTargetMissing reports a target id that names no row at
|
||||
|
||||
@@ -513,7 +513,11 @@ func TestHandleSourceLogs_RendersReplayControlAndBanner(t *testing.T) {
|
||||
)
|
||||
|
||||
assert.Contains(t, refused, "alert-error")
|
||||
assert.Contains(t, refused, "has been deleted")
|
||||
assert.Contains(
|
||||
t, refused,
|
||||
"has been deleted. Use Resubmit to send the event "+
|
||||
"to the webhook",
|
||||
)
|
||||
|
||||
// An outcome code nobody issued renders no banner at all.
|
||||
unknown := renderSourceLogsPageWithQuery(
|
||||
|
||||
@@ -66,7 +66,8 @@ func noticeFor(r *http.Request) *notice {
|
||||
},
|
||||
replayTargetDeleted: {
|
||||
Text: "Not replayed: the target this delivery was for " +
|
||||
"has been deleted. Recreate the target, then replay.",
|
||||
"has been deleted. Use Resubmit to send the event " +
|
||||
"to the webhook's currently active targets.",
|
||||
Failed: true,
|
||||
},
|
||||
replayTargetMissing: {
|
||||
|
||||
@@ -94,6 +94,44 @@ func TestHandleSourceLogs_NamesDeletedTarget(t *testing.T) {
|
||||
)
|
||||
}
|
||||
|
||||
// TestHandleSourceLogs_OffersNoReplayForDeletedTarget proves a
|
||||
// finished delivery offers Replay while its target lives and not
|
||||
// once the target is deleted. A replay to a deleted target is always
|
||||
// refused, and recreating the target makes a new one that the old
|
||||
// delivery does not name.
|
||||
func TestHandleSourceLogs_OffersNoReplayForDeletedTarget(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)
|
||||
|
||||
_, failed := seedFailedDelivery(t, dbMgr, wh.ID, tgt.ID)
|
||||
replayForm := `action="/hook/` + wh.ID + `/deliveries/` +
|
||||
failed.ID + `/replay"`
|
||||
|
||||
before := renderSourceLogsPage(t, h, sess, wh.ID)
|
||||
assert.Contains(t, before, replayForm)
|
||||
|
||||
deleteTargetThroughHandler(t, h, sess, wh.ID, tgt.ID)
|
||||
|
||||
after := renderSourceLogsPage(t, h, sess, wh.ID)
|
||||
assert.NotContains(t, after, replayForm)
|
||||
assert.NotContains(t, after, ">Replay<")
|
||||
assert.Contains(t, after, tgt.Name+deletedMarker)
|
||||
}
|
||||
|
||||
// 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
|
||||
|
||||
@@ -74,7 +74,7 @@
|
||||
</svg>
|
||||
</span>
|
||||
</button>
|
||||
{{if .Status.Terminal}}
|
||||
{{if and .Status.Terminal (not .Target.Deleted)}}
|
||||
<form method="POST" action="/hook/{{$.Webhook.ID}}/deliveries/{{.ID}}/replay" class="inline">
|
||||
<input type="hidden" name="csrf_token" value="{{$.CSRFToken}}">
|
||||
<input type="hidden" name="page" value="{{$.Page}}">
|
||||
|
||||
Reference in New Issue
Block a user