retention.audit_days and retention.revisions_keep (DDI_RETENTION_*) drive a cleanup five minutes after the start and then daily. The latest revision, revisions agents run, fall back to or target, and revisions with pending deployments are never deleted; deployment rows stay. A cleanup that deletes anything records retention.cleanup in the audit log. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
65 lines
1.7 KiB
Go
65 lines
1.7 KiB
Go
// SPDX-License-Identifier: LicenseRef-DDI-Proprietary
|
|
|
|
package app
|
|
|
|
import (
|
|
"context"
|
|
"io"
|
|
"log/slog"
|
|
"testing"
|
|
"time"
|
|
|
|
"git.beugsiud.de/beug.k/DDI/server/internal/config"
|
|
"git.beugsiud.de/beug.k/DDI/server/internal/service"
|
|
"git.beugsiud.de/beug.k/DDI/server/internal/store"
|
|
"git.beugsiud.de/beug.k/DDI/server/internal/store/storetest"
|
|
)
|
|
|
|
func TestRetentionJob(t *testing.T) {
|
|
st := storetest.New(t)
|
|
ctx := context.Background()
|
|
if err := st.Q().InsertAudit(ctx, &store.AuditEntry{ActorName: "admin", Action: "old.one", ObjectType: "test"}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if _, err := st.Pool().Exec(ctx, `UPDATE audit_log SET at = now() - interval '10 days'`); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
log := slog.New(slog.NewTextHandler(io.Discard, nil))
|
|
cfg := config.Defaults()
|
|
core := &Core{Config: cfg, Store: st, Log: log, Service: service.New(service.Options{Store: st, Logger: log})}
|
|
|
|
// Disabled policy: returns at once.
|
|
done := make(chan struct{})
|
|
go func() { retention(ctx, core, 0, time.Hour); close(done) }()
|
|
select {
|
|
case <-done:
|
|
case <-time.After(5 * time.Second):
|
|
t.Fatal("disabled retention job did not return")
|
|
}
|
|
|
|
core.Config.Retention.AuditDays = 7
|
|
jobCtx, cancel := context.WithCancel(ctx)
|
|
done = make(chan struct{})
|
|
go func() { retention(jobCtx, core, 10*time.Millisecond, time.Hour); close(done) }()
|
|
deadline := time.Now().Add(10 * time.Second)
|
|
for {
|
|
entries, err := st.Q().ListAudit(ctx, store.AuditFilter{Action: "old.one"})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(entries) == 0 {
|
|
break
|
|
}
|
|
if time.Now().After(deadline) {
|
|
t.Fatal("old audit entry was not deleted")
|
|
}
|
|
time.Sleep(20 * time.Millisecond)
|
|
}
|
|
cancel()
|
|
select {
|
|
case <-done:
|
|
case <-time.After(5 * time.Second):
|
|
t.Fatal("retention job did not stop")
|
|
}
|
|
}
|