From e7dddb065a3ea38fc30b8dc03dfad8aff4bf548b Mon Sep 17 00:00:00 2001 From: Winfried Plappert Date: Wed, 5 Mar 2025 21:58:34 +0000 Subject: [PATCH] restic prune integration tests: added one test TestPruneSizeMonitoring() which runs a failed backup and then calls prune to remove the partial snapshot. cmd/restic/integration_test needed to be modified, since it does not allow multiple calls to list snapshots. --- cmd/restic/cmd_prune_integration_test.go | 30 ++++++++++++++++++++++-- cmd/restic/integration_test.go | 22 ++++++++++++++--- 2 files changed, 47 insertions(+), 5 deletions(-) diff --git a/cmd/restic/cmd_prune_integration_test.go b/cmd/restic/cmd_prune_integration_test.go index 0561f8243..95b0c8e4a 100644 --- a/cmd/restic/cmd_prune_integration_test.go +++ b/cmd/restic/cmd_prune_integration_test.go @@ -8,13 +8,14 @@ import ( "github.com/restic/restic/internal/backend" "github.com/restic/restic/internal/repository" + //"github.com/restic/restic/internal/restic" rtest "github.com/restic/restic/internal/test" "github.com/restic/restic/internal/ui/termstatus" ) func testRunPrune(t testing.TB, gopts GlobalOptions, opts PruneOptions) { oldHook := gopts.backendTestHook - gopts.backendTestHook = func(r backend.Backend) (backend.Backend, error) { return newListOnceBackend(r), nil } + gopts.backendTestHook = func(r backend.Backend) (backend.Backend, error) { return newListMultipleBackend(r), nil } defer func() { gopts.backendTestHook = oldHook }() @@ -142,7 +143,7 @@ func TestPruneWithDamagedRepository(t *testing.T) { removePacksExcept(env.gopts, t, oldPacks, false) oldHook := env.gopts.backendTestHook - env.gopts.backendTestHook = func(r backend.Backend) (backend.Backend, error) { return newListOnceBackend(r), nil } + env.gopts.backendTestHook = func(r backend.Backend) (backend.Backend, error) { return newListMultipleBackend(r), nil } defer func() { env.gopts.backendTestHook = oldHook }() @@ -237,3 +238,28 @@ func testEdgeCaseRepo(t *testing.T, tarfile string, optionsCheck CheckOptions, o "prune should have reported an error") } } + +func TestPruneSizeMonitoring(t *testing.T) { + env, cleanup := withTestEnvironment(t) + defer cleanup() + + datafile := filepath.Join("testdata", "backup-data.tar.gz") + testRunInit(t, env.gopts) + + rtest.SetupTarTestFixture(t, env.testdata, datafile) + opts := BackupOptions{RepoMaxSize: "50k"} + + // create and delete snapshot to create unused blobs + oldHook := env.gopts.backendTestHook + env.gopts.backendTestHook = func(r backend.Backend) (backend.Backend, error) { return newListMultipleBackend(r), nil } + defer func() { + env.gopts.backendTestHook = oldHook + }() + err := testRunBackupAssumeFailure(t, filepath.Dir(env.testdata), []string{env.testdata}, opts, env.gopts) + rtest.Assert(t, err != nil, "backup should have ended in failure '%v'", err) + firstSnapshot := testListSnapshots(t, env.gopts, 1)[0] + t.Logf("first snapshot %v", firstSnapshot) + + testRunPrune(t, env.gopts, PruneOptions{MaxUnused: "0"}) + _ = testListSnapshots(t, env.gopts, 0) +} diff --git a/cmd/restic/integration_test.go b/cmd/restic/integration_test.go index 3ef98a168..2cbc0e9b8 100644 --- a/cmd/restic/integration_test.go +++ b/cmd/restic/integration_test.go @@ -46,15 +46,20 @@ type listOnceBackend struct { backend.Backend listedFileType map[restic.FileType]bool strictOrder bool + allowMultiple bool } -func newListOnceBackend(be backend.Backend) *listOnceBackend { +// the linter bites here: says newListOnceBackend is not used +// I need to be able to call SnapshotLister more than once to check for partial snapshots +// and restic prune uses `getUsedBlobs` to get all used blobs which uses +// `restic.ForAllSnapshots()` to do the work. +/*func newListOnceBackend(be backend.Backend) *listOnceBackend { return &listOnceBackend{ Backend: be, listedFileType: make(map[restic.FileType]bool), strictOrder: false, } -} +}*/ func newOrderedListOnceBackend(be backend.Backend) *listOnceBackend { return &listOnceBackend{ @@ -64,6 +69,15 @@ func newOrderedListOnceBackend(be backend.Backend) *listOnceBackend { } } +func newListMultipleBackend(be backend.Backend) *listOnceBackend { + return &listOnceBackend{ + Backend: be, + listedFileType: make(map[restic.FileType]bool), + strictOrder: false, + allowMultiple: true, + } +} + func (be *listOnceBackend) List(ctx context.Context, t restic.FileType, fn func(backend.FileInfo) error) error { if t != restic.LockFile && be.listedFileType[t] { return errors.Errorf("tried listing type %v the second time", t) @@ -71,7 +85,9 @@ func (be *listOnceBackend) List(ctx context.Context, t restic.FileType, fn func( if be.strictOrder && t == restic.SnapshotFile && be.listedFileType[restic.IndexFile] { return errors.Errorf("tried listing type snapshots after index") } - be.listedFileType[t] = true + if !be.allowMultiple { + be.listedFileType[t] = true + } return be.Backend.List(ctx, t, fn) }