diff --git a/internal/vaultik/prune_count_test.go b/internal/vaultik/prune_count_test.go index 11401c6..2009e01 100644 --- a/internal/vaultik/prune_count_test.go +++ b/internal/vaultik/prune_count_test.go @@ -1,13 +1,17 @@ package vaultik //nolint:testpackage // exercises unexported count helpers import ( + "bytes" "context" "testing" + "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "sneak.berlin/go/vaultik/internal/database" "sneak.berlin/go/vaultik/internal/log" + "sneak.berlin/go/vaultik/internal/snapshot" + "sneak.berlin/go/vaultik/internal/ui" ) // TestTableCountForReportSurfacesReadFailure is the regression guard for @@ -76,3 +80,59 @@ func TestCountDiffUnknownWhenEitherSideUnknown(t *testing.T) { assert.Nil(t, countDiff(&before, nil), "unknown after yields unknown delta") assert.Nil(t, countDiff(nil, nil)) } + +// TestPruneDatabaseSummaryLabelsTotals removes the only incomplete +// snapshot from an index that also holds a complete one. The figure in +// brackets is every snapshot left in the local index, so the line must +// say so rather than read as incomplete snapshots that remain. +func TestPruneDatabaseSummaryLabelsTotals(t *testing.T) { + log.Initialize(log.Config{}) + t.Parallel() + + ctx := context.Background() + + db, err := database.New(ctx, ":memory:") + require.NoError(t, err) + t.Cleanup(func() { _ = db.Close() }) + + repos := database.NewRepositories(db) + + startedAt := time.Date(2026, 1, 2, 3, 4, 5, 0, time.UTC) + completedAt := startedAt.Add(time.Minute) + + require.NoError(t, repos.Snapshots.Create(ctx, nil, &database.Snapshot{ + ID: "host_complete_2026-01-02T03:04:05Z", + Hostname: "host", + StartedAt: startedAt, + CompletedAt: &completedAt, + })) + require.NoError(t, repos.Snapshots.Create(ctx, nil, &database.Snapshot{ + ID: "host_incomplete_2026-01-02T03:04:05Z", + Hostname: "host", + StartedAt: startedAt, + })) + + var out bytes.Buffer + + v := &Vaultik{ + DB: db, + Repositories: repos, + SnapshotManager: snapshot.NewSnapshotManager( + snapshot.SnapshotManagerParams{Repos: repos}), + UI: ui.NewWithColor(&out, false), + } + v.SetContext(ctx) + + result, err := v.PruneDatabase() + require.NoError(t, err) + require.Equal(t, int64(1), result.SnapshotsDeleted) + + assert.Contains(t, out.String(), "Incomplete snapshots: 1 removed "+ + "(total snapshots left in the local index: 1).") + assert.Contains(t, out.String(), "Orphaned files: 0 removed "+ + "(total files left in the local index: 0).") + assert.Contains(t, out.String(), "Orphaned chunks: 0 removed "+ + "(total chunks left in the local index: 0).") + assert.Contains(t, out.String(), "Orphaned blobs: 0 removed "+ + "(total blobs left in the local index: 0).") +} diff --git a/internal/vaultik/snapshot.go b/internal/vaultik/snapshot.go index cef9cbf..d9eef00 100644 --- a/internal/vaultik/snapshot.go +++ b/internal/vaultik/snapshot.go @@ -1890,13 +1890,17 @@ func (v *Vaultik) PruneDatabase() (*PruneResult, error) { snapshotsRemain := countDiff(snapshotCountBefore, &result.SnapshotsDeleted) v.UI.Completef("Pruned local index database.") - v.UI.Detailf("Incomplete snapshots: %s removed (%s remain).", + v.UI.Detailf("Incomplete snapshots: %s removed "+ + "(total snapshots left in the local index: %s).", countText(&result.SnapshotsDeleted), countText(snapshotsRemain)) - v.UI.Detailf("Orphaned files: %s removed (%s remain).", + v.UI.Detailf("Orphaned files: %s removed "+ + "(total files left in the local index: %s).", countText(result.FilesDeleted), countText(fileCountAfter)) - v.UI.Detailf("Orphaned chunks: %s removed (%s remain).", + v.UI.Detailf("Orphaned chunks: %s removed "+ + "(total chunks left in the local index: %s).", countText(result.ChunksDeleted), countText(chunkCountAfter)) - v.UI.Detailf("Orphaned blobs: %s removed (%s remain).", + v.UI.Detailf("Orphaned blobs: %s removed "+ + "(total blobs left in the local index: %s).", countText(result.BlobsDeleted), countText(blobCountAfter)) return result, nil