From ebab35581caed46e6dfddef646ba4dd354cddddb Mon Sep 17 00:00:00 2001 From: Michael Eischer Date: Sun, 7 Nov 2021 22:39:38 +0100 Subject: [PATCH] Check in integration test that snapshots are listed before the index As an exception prune is still allowed to load the index before snapshots, as it uses exclusive locks. In case of problems with locking it is also better to load snapshots created after loading the index, as this will lead to a prune sanity check failure instead of a broken snapshot. --- cmd/restic/integration_fuse_test.go | 4 ++++ cmd/restic/integration_helpers_test.go | 3 +++ cmd/restic/integration_test.go | 25 +++++++++++++++++++++++++ 3 files changed, 32 insertions(+) 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) }