186 lines
5.6 KiB
Go
186 lines
5.6 KiB
Go
package test
|
|
|
|
import (
|
|
"RenewCMS/internal/domain/purge"
|
|
"RenewCMS/internal/infrastructure/useCases"
|
|
"bytes"
|
|
"crypto/sha256"
|
|
"encoding/hex"
|
|
"errors"
|
|
"log"
|
|
"reflect"
|
|
"sync"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestUpdatePurgeSettingsRejectsOutOfRangeIntervals(t *testing.T) {
|
|
for _, days := range []int{0, 366} {
|
|
repo := newMockPurgeSettingsRepo()
|
|
update := useCases.NewUpdatePurgeSettingsUseCase(repo, time.Now)
|
|
|
|
_, err := update.Update(useCases.UpdatePurgeSettingsCommand{AutoPurgeIntervalDays: &days})
|
|
|
|
if !errors.Is(err, purge.ErrInvalidPurgeInterval) {
|
|
t.Errorf("interval %d: expected ErrInvalidPurgeInterval, got %v", days, err)
|
|
}
|
|
if repo.saveCalls != 0 {
|
|
t.Errorf("interval %d: expected Save not to be called", days)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestRunPurgeDistinguishesBusyFromConflict(t *testing.T) {
|
|
newRun := func(env *mediaEnv) *useCases.RunPurgeUseCase {
|
|
merge := useCases.NewMergeMediaUseCase(env.images, env.articles, env.storage)
|
|
return useCases.NewRunPurgeUseCase(env.images, env.articles, merge, env.purgeSettings, func() time.Time { return env.clock }, log.New(&bytes.Buffer{}, "", 0))
|
|
}
|
|
|
|
t.Run("a non-matching fingerprint is a conflict and writes nothing", func(t *testing.T) {
|
|
env := newPurgeEnv(t)
|
|
env.seedGroup(hashA, 1, 2)
|
|
env.useImages(10, 1)
|
|
wrong := "wrong"
|
|
|
|
_, err := newRun(env).Run(&wrong)
|
|
|
|
if !errors.Is(err, purge.ErrPurgeConflict) || errors.Is(err, purge.ErrPurgeBusy) {
|
|
t.Errorf("expected only ErrPurgeConflict, got %v", err)
|
|
}
|
|
if env.purgeSettings.saveCalls != 0 || len(env.images.deleteCalls) != 0 {
|
|
t.Errorf("expected no write")
|
|
}
|
|
})
|
|
|
|
t.Run("a run while another holds the guard is busy and writes nothing", func(t *testing.T) {
|
|
env := newPurgeEnv(t)
|
|
env.seedGroup(hashA, 1, 2)
|
|
env.useImages(10, 1)
|
|
entered := make(chan struct{})
|
|
release := make(chan struct{})
|
|
var once sync.Once
|
|
env.images.onDelete = func(uint32) {
|
|
once.Do(func() {
|
|
close(entered)
|
|
<-release
|
|
})
|
|
}
|
|
run := newRun(env)
|
|
done := make(chan error, 1)
|
|
go func() {
|
|
_, err := run.Run(nil)
|
|
done <- err
|
|
}()
|
|
<-entered
|
|
savesBefore := env.purgeSettings.saveCalls
|
|
|
|
_, err := run.Run(nil)
|
|
|
|
if !errors.Is(err, purge.ErrPurgeBusy) || errors.Is(err, purge.ErrPurgeConflict) {
|
|
t.Errorf("expected only ErrPurgeBusy, got %v", err)
|
|
}
|
|
if env.purgeSettings.saveCalls != savesBefore {
|
|
t.Errorf("expected no write from the busy call")
|
|
}
|
|
close(release)
|
|
if err := <-done; err != nil {
|
|
t.Errorf("expected the first run to finish, got %v", err)
|
|
}
|
|
})
|
|
|
|
t.Run("a scheduler run without a fingerprint gets the result and the persistence", func(t *testing.T) {
|
|
env := newPurgeEnv(t)
|
|
env.seedGroup(hashA, 1, 2)
|
|
env.useImages(10, 1)
|
|
|
|
result, err := newRun(env).Run(nil)
|
|
|
|
if err != nil || result != (purge.RunResult{GroupsTotal: 1, GroupsPurged: 1, Merged: 1}) {
|
|
t.Errorf("unexpected result %+v, %v", result, err)
|
|
}
|
|
if env.purgeSettings.settings.LastPurgeAt == nil || env.purgeSettings.settings.LastPurgeMerged != 1 {
|
|
t.Errorf("expected last_purge_* persisted")
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestPurgePlanOrderingAndFingerprint(t *testing.T) {
|
|
t.Run("groups are ordered by the kept image id whatever the order they were found in", func(t *testing.T) {
|
|
env := newPurgeEnv(t)
|
|
env.seedGroup(hashA, 1, 6)
|
|
env.seedGroup(hashB, 2, 5)
|
|
env.seedGroup(hashC, 3, 4)
|
|
env.useImages(10, 6)
|
|
env.useImages(11, 5)
|
|
env.useImages(12, 3)
|
|
|
|
preview, err := useCases.NewPreviewPurgeUseCase(env.images, env.articles).Preview()
|
|
|
|
var kept []uint32
|
|
for _, group := range preview.List {
|
|
kept = append(kept, group.KeepID)
|
|
}
|
|
if err != nil || !reflect.DeepEqual(kept, []uint32{3, 5, 6}) {
|
|
t.Errorf("expected kept ids [3 5 6], got %v, %v", kept, err)
|
|
}
|
|
})
|
|
|
|
t.Run("the fingerprint hashes the kept id and the comma separated merged ids of each group", func(t *testing.T) {
|
|
env := newPurgeEnv(t)
|
|
env.seedGroup(hashA, 1, 2, 3)
|
|
env.seedGroup(hashB, 4, 5)
|
|
env.useImages(10, 1, 2, 3)
|
|
env.useImages(11, 5)
|
|
|
|
preview, err := useCases.NewPreviewPurgeUseCase(env.images, env.articles).Preview()
|
|
|
|
sum := sha256.Sum256([]byte("1:2,3;5:4;"))
|
|
if err != nil || preview.Fingerprint != hex.EncodeToString(sum[:]) {
|
|
t.Errorf("unexpected fingerprint %q, %v", preview.Fingerprint, err)
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestMergeMediaExposesTheRewrittenArticleIds(t *testing.T) {
|
|
t.Run("Existing merges report the same counts and now also the ids", func(t *testing.T) {
|
|
env := newPurgeEnv(t)
|
|
env.seedGroup(hashA, 1, 2)
|
|
env.useImages(1, 2)
|
|
env.useImages(2, 1, 2)
|
|
env.useImages(3, 1)
|
|
merge := useCases.NewMergeMediaUseCase(env.images, env.articles, env.storage)
|
|
|
|
result, err := merge.Merge(1, []uint32{2})
|
|
|
|
if err != nil || result.Merged != 1 || result.ArticlesUpdated != 2 || !reflect.DeepEqual(result.UpdatedArticleIDs, []uint32{1, 2}) {
|
|
t.Errorf("unexpected result %+v, %v", result, err)
|
|
}
|
|
})
|
|
|
|
t.Run("A rolled-back merge returns no ids", func(t *testing.T) {
|
|
env := newPurgeEnv(t)
|
|
env.seedGroup(hashA, 1, 2)
|
|
env.useImages(1, 2)
|
|
env.useImages(2, 2)
|
|
env.articles.failUpdateBodyFor = map[uint32]error{2: errRepositoryFailure}
|
|
merge := useCases.NewMergeMediaUseCase(env.images, env.articles, env.storage)
|
|
|
|
result, err := merge.Merge(1, []uint32{2})
|
|
|
|
if err == nil || result.Merged != 0 || result.ArticlesUpdated != 0 || len(result.UpdatedArticleIDs) != 0 {
|
|
t.Errorf("unexpected result %+v, %v", result, err)
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestPurgeSettingsNextPurgeAt(t *testing.T) {
|
|
t.Run("is null when off or when never enabled", func(t *testing.T) {
|
|
if purge.DefaultSettings().NextPurgeAt() != nil {
|
|
t.Errorf("expected nil")
|
|
}
|
|
if (purge.Settings{AutoPurgeEnabled: true, AutoPurgeIntervalDays: 3}).NextPurgeAt() != nil {
|
|
t.Errorf("expected nil without enabled_at")
|
|
}
|
|
})
|
|
}
|