A target's settings move from the per-type JSON string in targets.config to columns: url, headers, timeout_seconds, forward_query, archive_expiry and archive_rotation. A column a type does not use stays empty. headers holds the header map as JSON text through GORM's JSON serializer, and archive_expiry holds a time.Duration, 0 meaning never. The forms check each setting once, with the same refusals and messages, and the edit form is filled from the columns, so the per-type config structs, their parsers and the "could not be read" branches are gone. A delivery task carries the six settings in place of the JSON string; tests check that each copy into a task, and back out of one, keeps all six. Model: opus-5-5
This commit was merged in pull request #554.
This commit is contained in:
@@ -106,10 +106,10 @@ func (env *archiveEnv) archivePath(tgt *database.Target) string {
|
||||
)
|
||||
}
|
||||
|
||||
// seedDatabaseTarget creates a webhook with one database target
|
||||
// carrying the given target config JSON, and returns the target.
|
||||
// seedDatabaseTarget creates a webhook with one database target with
|
||||
// the given archive expiry and rotation, and returns the target.
|
||||
func (env *archiveEnv) seedDatabaseTarget(
|
||||
t *testing.T, configJSON string,
|
||||
t *testing.T, expiry time.Duration, rotation string,
|
||||
) *database.Target {
|
||||
t.Helper()
|
||||
|
||||
@@ -124,23 +124,27 @@ func (env *archiveEnv) seedDatabaseTarget(
|
||||
Create(wh).Error,
|
||||
)
|
||||
|
||||
return env.addDatabaseTarget(t, wh.ID, configJSON)
|
||||
return env.addDatabaseTarget(t, wh.ID, expiry, rotation)
|
||||
}
|
||||
|
||||
// addDatabaseTarget creates one more database target on an
|
||||
// existing webhook and returns it.
|
||||
func (env *archiveEnv) addDatabaseTarget(
|
||||
t *testing.T, webhookID, configJSON string,
|
||||
t *testing.T,
|
||||
webhookID string,
|
||||
expiry time.Duration,
|
||||
rotation string,
|
||||
) *database.Target {
|
||||
t.Helper()
|
||||
|
||||
tgt := &database.Target{
|
||||
WebhookID: webhookID,
|
||||
Name: "Archive",
|
||||
Type: database.TargetTypeDatabase,
|
||||
Active: true,
|
||||
Config: configJSON,
|
||||
MaxAttempts: 1,
|
||||
WebhookID: webhookID,
|
||||
Name: "Archive",
|
||||
Type: database.TargetTypeDatabase,
|
||||
Active: true,
|
||||
ArchiveExpiry: expiry,
|
||||
ArchiveRotation: rotation,
|
||||
MaxAttempts: 1,
|
||||
}
|
||||
require.NoError(
|
||||
t,
|
||||
@@ -323,7 +327,7 @@ func TestArchiveSweeper_LoopOutlivesStartHookContext(
|
||||
|
||||
env := setupArchiveTest(t)
|
||||
|
||||
tgt := env.seedDatabaseTarget(t, `{"expiry":"1h"}`)
|
||||
tgt := env.seedDatabaseTarget(t, time.Hour, "")
|
||||
|
||||
now := time.Now()
|
||||
path := env.seedArchiveRows(
|
||||
@@ -377,7 +381,7 @@ func TestArchiveSweep_DoesNotResurrectEvictedWriter(
|
||||
|
||||
env := setupArchiveTest(t)
|
||||
|
||||
tgt := env.seedDatabaseTarget(t, `{"expiry":"1h"}`)
|
||||
tgt := env.seedDatabaseTarget(t, time.Hour, "")
|
||||
env.seedArchiveRows(
|
||||
t, tgt, time.Now().Add(-48*time.Hour),
|
||||
)
|
||||
@@ -411,7 +415,7 @@ func TestArchiveSweep_LeavesNoRegistryEntry(t *testing.T) {
|
||||
|
||||
env := setupArchiveTest(t)
|
||||
|
||||
tgt := env.seedDatabaseTarget(t, `{"expiry":"1h"}`)
|
||||
tgt := env.seedDatabaseTarget(t, time.Hour, "")
|
||||
path := env.seedArchiveRows(
|
||||
t, tgt,
|
||||
time.Now().Add(-48*time.Hour),
|
||||
@@ -444,7 +448,7 @@ func TestArchiveSweep_KeepsWriterAdoptedByDelivery(
|
||||
|
||||
env := setupArchiveTest(t)
|
||||
|
||||
tgt := env.seedDatabaseTarget(t, `{"expiry":"1h"}`)
|
||||
tgt := env.seedDatabaseTarget(t, time.Hour, "")
|
||||
env.seedArchiveRows(
|
||||
t, tgt, time.Now().Add(-48*time.Hour),
|
||||
)
|
||||
@@ -498,7 +502,7 @@ func TestArchiveSweep_KeepsWriterAdoptedDuringSweep(
|
||||
|
||||
env := setupArchiveTest(t)
|
||||
|
||||
tgt := env.seedDatabaseTarget(t, `{"expiry":"1h"}`)
|
||||
tgt := env.seedDatabaseTarget(t, time.Hour, "")
|
||||
env.seedArchiveRows(
|
||||
t, tgt, time.Now().Add(-48*time.Hour),
|
||||
)
|
||||
@@ -551,8 +555,8 @@ func TestArchiveSweep_KeepsWriterAdoptedDuringSweep(
|
||||
|
||||
// TestArchiveSweep_ContinuesAfterPerTargetFailure proves a
|
||||
// failure for one target does not abort the sweep for the
|
||||
// others: an unparseable expiry and an unreadable archive both
|
||||
// have to be logged and stepped over.
|
||||
// others: an unreadable archive has to be logged and stepped
|
||||
// over.
|
||||
func TestArchiveSweep_ContinuesAfterPerTargetFailure(
|
||||
t *testing.T,
|
||||
) {
|
||||
@@ -560,21 +564,16 @@ func TestArchiveSweep_ContinuesAfterPerTargetFailure(
|
||||
|
||||
env := setupArchiveTest(t)
|
||||
|
||||
// Seeded first so the sweep reaches them before the healthy
|
||||
// Seeded first so the sweep reaches it before the healthy
|
||||
// target: targets come back in insertion order.
|
||||
badConfig := env.seedDatabaseTarget(t, `{"expiry":"!!!"}`)
|
||||
env.seedArchiveRows(
|
||||
t, badConfig, time.Now().Add(-48*time.Hour),
|
||||
)
|
||||
|
||||
corrupt := env.seedDatabaseTarget(t, `{"expiry":"1h"}`)
|
||||
corrupt := env.seedDatabaseTarget(t, time.Hour, "")
|
||||
require.NoError(t, os.WriteFile(
|
||||
env.archivePath(corrupt),
|
||||
[]byte("this is not a sqlite database"),
|
||||
0o600,
|
||||
))
|
||||
|
||||
healthy := env.seedDatabaseTarget(t, `{"expiry":"1h"}`)
|
||||
healthy := env.seedDatabaseTarget(t, time.Hour, "")
|
||||
healthyPath := env.seedArchiveRows(
|
||||
t, healthy,
|
||||
time.Now().Add(-48*time.Hour),
|
||||
@@ -631,7 +630,7 @@ func TestArchiveSweep_PrunesIdleArchive(t *testing.T) {
|
||||
|
||||
env := setupArchiveTest(t)
|
||||
|
||||
tgt := env.seedDatabaseTarget(t, `{"expiry":"1h"}`)
|
||||
tgt := env.seedDatabaseTarget(t, time.Hour, "")
|
||||
|
||||
now := time.Now()
|
||||
path := env.seedArchiveRows(
|
||||
@@ -670,7 +669,7 @@ func TestArchiveSweep_LeavesArchiveClosed(t *testing.T) {
|
||||
|
||||
env := setupArchiveTest(t)
|
||||
|
||||
tgt := env.seedDatabaseTarget(t, `{"expiry":"1h"}`)
|
||||
tgt := env.seedDatabaseTarget(t, time.Hour, "")
|
||||
path := env.seedArchiveRows(
|
||||
t, tgt, time.Now().Add(-48*time.Hour),
|
||||
)
|
||||
@@ -710,7 +709,7 @@ func TestArchiveSweep_ClosesHandleOfRegisteredWriter(
|
||||
|
||||
env := setupArchiveTest(t)
|
||||
|
||||
tgt := env.seedDatabaseTarget(t, `{"expiry":"1h"}`)
|
||||
tgt := env.seedDatabaseTarget(t, time.Hour, "")
|
||||
env.seedArchiveRows(
|
||||
t, tgt, time.Now().Add(-48*time.Hour),
|
||||
)
|
||||
@@ -795,36 +794,29 @@ func TestArchiveSweep_CancelledSweepLogsNoError(t *testing.T) {
|
||||
}
|
||||
|
||||
// TestArchiveSweep_NeverExpiryUntouched proves the sweep is a
|
||||
// no-op for the default retention policy, so archives with no
|
||||
// expiry (or the literal "never") behave exactly as before.
|
||||
// no-op for the default retention policy, so an archive with an
|
||||
// expiry of 0, which keeps it forever, is left alone.
|
||||
func TestArchiveSweep_NeverExpiryUntouched(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
for _, configJSON := range []string{
|
||||
`{"expiry":"never"}`,
|
||||
`{"expiry":""}`,
|
||||
"",
|
||||
} {
|
||||
env := setupArchiveTest(t)
|
||||
env := setupArchiveTest(t)
|
||||
|
||||
tgt := env.seedDatabaseTarget(t, configJSON)
|
||||
path := env.seedArchiveRows(
|
||||
t, tgt,
|
||||
time.Now().Add(-10000*time.Hour),
|
||||
)
|
||||
tgt := env.seedDatabaseTarget(t, 0, "")
|
||||
path := env.seedArchiveRows(
|
||||
t, tgt,
|
||||
time.Now().Add(-10000*time.Hour),
|
||||
)
|
||||
|
||||
env.sweeper.ExportSweep(context.Background())
|
||||
env.sweeper.ExportSweep(context.Background())
|
||||
|
||||
assert.Equal(
|
||||
t, []string{sweepRowOld}, archivedEventIDs(t, path),
|
||||
"config %q must keep rows forever", configJSON,
|
||||
)
|
||||
assert.False(
|
||||
t, env.writers.ExportHasArchiveWriter(tgt.ID),
|
||||
"config %q must leave no registry entry behind",
|
||||
configJSON,
|
||||
)
|
||||
}
|
||||
assert.Equal(
|
||||
t, []string{sweepRowOld}, archivedEventIDs(t, path),
|
||||
"an expiry of 0 must keep rows forever",
|
||||
)
|
||||
assert.False(
|
||||
t, env.writers.ExportHasArchiveWriter(tgt.ID),
|
||||
"an expiry of 0 must leave no registry entry behind",
|
||||
)
|
||||
}
|
||||
|
||||
// TestArchiveSweep_NeverExpirySkipsBeforeOpening pins the
|
||||
@@ -845,7 +837,7 @@ func TestArchiveSweep_NeverExpirySkipsBeforeOpening(
|
||||
|
||||
env := setupArchiveTest(t)
|
||||
|
||||
tgt := env.seedDatabaseTarget(t, `{"expiry":"never"}`)
|
||||
tgt := env.seedDatabaseTarget(t, 0, "")
|
||||
path := env.archivePath(tgt)
|
||||
|
||||
seedUnmigratedArchive(t, path)
|
||||
@@ -897,7 +889,7 @@ func TestArchiveSweep_DoesNotCreateArchiveFile(t *testing.T) {
|
||||
|
||||
env := setupArchiveTest(t)
|
||||
|
||||
tgt := env.seedDatabaseTarget(t, `{"expiry":"1h"}`)
|
||||
tgt := env.seedDatabaseTarget(t, time.Hour, "")
|
||||
path := env.archivePath(tgt)
|
||||
|
||||
require.NoFileExists(t, path)
|
||||
@@ -928,7 +920,7 @@ func TestArchiveSweep_DoesNotCreateAfterWriterExists(
|
||||
|
||||
env := setupArchiveTest(t)
|
||||
|
||||
tgt := env.seedDatabaseTarget(t, `{"expiry":"1h"}`)
|
||||
tgt := env.seedDatabaseTarget(t, time.Hour, "")
|
||||
|
||||
path, err := env.writers.ExportEnsureArchiveWriter(tgt.ID)
|
||||
require.NoError(t, err)
|
||||
@@ -947,7 +939,7 @@ func TestArchiveSweep_SkipsDeletedWebhookTargets(t *testing.T) {
|
||||
|
||||
env := setupArchiveTest(t)
|
||||
|
||||
tgt := env.seedDatabaseTarget(t, `{"expiry":"1h"}`)
|
||||
tgt := env.seedDatabaseTarget(t, time.Hour, "")
|
||||
path := env.seedArchiveRows(
|
||||
t, tgt, time.Now().Add(-48*time.Hour),
|
||||
)
|
||||
@@ -975,7 +967,7 @@ func TestArchiveSweep_ConcurrentWrites(t *testing.T) {
|
||||
|
||||
env := setupArchiveTest(t)
|
||||
|
||||
tgt := env.seedDatabaseTarget(t, `{"expiry":"1h"}`)
|
||||
tgt := env.seedDatabaseTarget(t, time.Hour, "")
|
||||
|
||||
deliveries := make(
|
||||
[]*database.Delivery, 0, sweepConcurrentWrites,
|
||||
@@ -1020,7 +1012,7 @@ func TestArchiveSweeper_StopsCleanly(t *testing.T) {
|
||||
|
||||
env := setupArchiveTest(t)
|
||||
|
||||
tgt := env.seedDatabaseTarget(t, `{"expiry":"1h"}`)
|
||||
tgt := env.seedDatabaseTarget(t, time.Hour, "")
|
||||
env.seedArchiveRows(
|
||||
t, tgt, time.Now().Add(-48*time.Hour),
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user