diff --git a/cmd/restic/integration_fuse_test.go b/cmd/restic/integration_fuse_test.go index 1337be88e..156a8abae 100644 --- a/cmd/restic/integration_fuse_test.go +++ b/cmd/restic/integration_fuse_test.go @@ -154,6 +154,8 @@ func TestMount(t *testing.T) { } env, cleanup := withTestEnvironment(t) + // must list snapshots more than once + env.gopts.backendTestHook = nil defer cleanup() testRunInit(t, env.gopts) @@ -197,6 +199,8 @@ func TestMountSameTimestamps(t *testing.T) { } env, cleanup := withTestEnvironment(t) + // must list snapshots more than once + env.gopts.backendTestHook = nil defer cleanup() rtest.SetupTarTestFixture(t, env.base, filepath.Join("testdata", "repo-same-timestamps.tar.gz")) diff --git a/cmd/restic/integration_helpers_test.go b/cmd/restic/integration_helpers_test.go index df9893350..e87baddca 100644 --- a/cmd/restic/integration_helpers_test.go +++ b/cmd/restic/integration_helpers_test.go @@ -198,6 +198,9 @@ func withTestEnvironment(t testing.TB) (env *testEnvironment, cleanup func()) { stdout: os.Stdout, stderr: os.Stderr, extended: make(options.Options), + + // replace this hook with "nil" if listing a filetype more than once is necessary + backendTestHook: func(r restic.Backend) (restic.Backend, error) { return newOrderedListOnceBackend(r), nil }, } // always overwrite global options diff --git a/cmd/restic/integration_test.go b/cmd/restic/integration_test.go index 4b935d2c8..49121bb1d 100644 --- a/cmd/restic/integration_test.go +++ b/cmd/restic/integration_test.go @@ -275,6 +275,11 @@ func testRunForgetJSON(t testing.TB, gopts GlobalOptions, args ...string) { } func testRunPrune(t testing.TB, gopts GlobalOptions, opts PruneOptions) { + oldHook := gopts.backendTestHook + gopts.backendTestHook = func(r restic.Backend) (restic.Backend, error) { return newListOnceBackend(r), nil } + defer func() { + gopts.backendTestHook = oldHook + }() rtest.OK(t, runPrune(opts, gopts)) } @@ -1065,6 +1070,8 @@ func TestKeyAddRemove(t *testing.T) { } env, cleanup := withTestEnvironment(t) + // must list keys more than once + env.gopts.backendTestHook = nil defer cleanup() testRunInit(t, env.gopts) @@ -1659,6 +1666,11 @@ func TestPruneWithDamagedRepository(t *testing.T) { rtest.Assert(t, len(snapshotIDs) == 1, "expected one snapshot, got %v", snapshotIDs) + oldHook := env.gopts.backendTestHook + env.gopts.backendTestHook = func(r restic.Backend) (restic.Backend, error) { return newListOnceBackend(r), nil } + defer func() { + env.gopts.backendTestHook = oldHook + }() // prune should fail rtest.Assert(t, runPrune(pruneDefaultOptions, env.gopts) == errorPacksMissing, "prune should have reported index not complete error") @@ -1752,12 +1764,22 @@ func testEdgeCaseRepo(t *testing.T, tarfile string, optionsCheck CheckOptions, o type listOnceBackend struct { restic.Backend listedFileType map[restic.FileType]bool + strictOrder bool } func newListOnceBackend(be restic.Backend) *listOnceBackend { return &listOnceBackend{ Backend: be, listedFileType: make(map[restic.FileType]bool), + strictOrder: false, + } +} + +func newOrderedListOnceBackend(be restic.Backend) *listOnceBackend { + return &listOnceBackend{ + Backend: be, + listedFileType: make(map[restic.FileType]bool), + strictOrder: true, } } @@ -1765,6 +1787,9 @@ func (be *listOnceBackend) List(ctx context.Context, t restic.FileType, fn func( if t != restic.LockFile && be.listedFileType[t] { return errors.Errorf("tried listing type %v the second time", t) } + if be.strictOrder && t == restic.SnapshotFile && be.listedFileType[restic.IndexFile] { + return errors.Errorf("tried listing type snapshots after index") + } be.listedFileType[t] = true return be.Backend.List(ctx, t, fn) }