restic/cmd/restic/cmd_repair_snapshots_integration_test.go
Michael Eischer 675a49a95b Restructure integration tests
The tests are now split into individual files for each command. The
separation isn't perfect as many tests make use of multiple commands. In
particular `init`, `backup`, `check` and `list` are used by a larger
number of test cases.

Most tests now reside in files name cmd_<name>_integration_test.go. This
provides a certain indication which commands have significant test
coverage.
2023-05-26 19:38:43 +02:00

135 lines
4 KiB
Go

package main
import (
"context"
"hash/fnv"
"io"
"math/rand"
"os"
"path/filepath"
"reflect"
"testing"
"github.com/restic/restic/internal/restic"
rtest "github.com/restic/restic/internal/test"
)
func testRunRepairSnapshot(t testing.TB, gopts GlobalOptions, forget bool) {
opts := RepairOptions{
Forget: forget,
}
rtest.OK(t, runRepairSnapshots(context.TODO(), gopts, opts, nil))
}
func createRandomFile(t testing.TB, env *testEnvironment, path string, size int) {
fn := filepath.Join(env.testdata, path)
rtest.OK(t, os.MkdirAll(filepath.Dir(fn), 0o755))
h := fnv.New64()
_, err := h.Write([]byte(path))
rtest.OK(t, err)
r := rand.New(rand.NewSource(int64(h.Sum64())))
f, err := os.OpenFile(fn, os.O_CREATE|os.O_RDWR, 0o644)
rtest.OK(t, err)
_, err = io.Copy(f, io.LimitReader(r, int64(size)))
rtest.OK(t, err)
rtest.OK(t, f.Close())
}
func TestRepairSnapshotsWithLostData(t *testing.T) {
env, cleanup := withTestEnvironment(t)
defer cleanup()
testRunInit(t, env.gopts)
createRandomFile(t, env, "foo/bar/file", 512*1024)
testRunBackup(t, "", []string{env.testdata}, BackupOptions{}, env.gopts)
testListSnapshots(t, env.gopts, 1)
// damage repository
removePacksExcept(env.gopts, t, restic.NewIDSet(), false)
createRandomFile(t, env, "foo/bar/file2", 256*1024)
testRunBackup(t, "", []string{env.testdata}, BackupOptions{}, env.gopts)
snapshotIDs := testListSnapshots(t, env.gopts, 2)
testRunCheckMustFail(t, env.gopts)
// repair but keep broken snapshots
testRunRebuildIndex(t, env.gopts)
testRunRepairSnapshot(t, env.gopts, false)
testListSnapshots(t, env.gopts, 4)
testRunCheckMustFail(t, env.gopts)
// repository must be ok after removing the broken snapshots
testRunForget(t, env.gopts, snapshotIDs[0].String(), snapshotIDs[1].String())
testListSnapshots(t, env.gopts, 2)
_, err := testRunCheckOutput(env.gopts, false)
rtest.OK(t, err)
}
func TestRepairSnapshotsWithLostTree(t *testing.T) {
env, cleanup := withTestEnvironment(t)
defer cleanup()
testRunInit(t, env.gopts)
createRandomFile(t, env, "foo/bar/file", 12345)
testRunBackup(t, "", []string{env.testdata}, BackupOptions{}, env.gopts)
oldSnapshot := testListSnapshots(t, env.gopts, 1)
oldPacks := testRunList(t, "packs", env.gopts)
// keep foo/bar unchanged
createRandomFile(t, env, "foo/bar2", 1024)
testRunBackup(t, "", []string{env.testdata}, BackupOptions{}, env.gopts)
testListSnapshots(t, env.gopts, 2)
// remove tree for foo/bar and the now completely broken first snapshot
removePacks(env.gopts, t, restic.NewIDSet(oldPacks...))
testRunForget(t, env.gopts, oldSnapshot[0].String())
testRunCheckMustFail(t, env.gopts)
// repair
testRunRebuildIndex(t, env.gopts)
testRunRepairSnapshot(t, env.gopts, true)
testListSnapshots(t, env.gopts, 1)
_, err := testRunCheckOutput(env.gopts, false)
rtest.OK(t, err)
}
func TestRepairSnapshotsWithLostRootTree(t *testing.T) {
env, cleanup := withTestEnvironment(t)
defer cleanup()
testRunInit(t, env.gopts)
createRandomFile(t, env, "foo/bar/file", 12345)
testRunBackup(t, "", []string{env.testdata}, BackupOptions{}, env.gopts)
testListSnapshots(t, env.gopts, 1)
oldPacks := testRunList(t, "packs", env.gopts)
// remove all trees
removePacks(env.gopts, t, restic.NewIDSet(oldPacks...))
testRunCheckMustFail(t, env.gopts)
// repair
testRunRebuildIndex(t, env.gopts)
testRunRepairSnapshot(t, env.gopts, true)
testListSnapshots(t, env.gopts, 0)
_, err := testRunCheckOutput(env.gopts, false)
rtest.OK(t, err)
}
func TestRepairSnapshotsIntact(t *testing.T) {
env, cleanup := withTestEnvironment(t)
defer cleanup()
testSetupBackupData(t, env)
testRunBackup(t, filepath.Dir(env.testdata), []string{"testdata"}, BackupOptions{}, env.gopts)
oldSnapshotIDs := testListSnapshots(t, env.gopts, 1)
// use an exclude that will not exclude anything
testRunRepairSnapshot(t, env.gopts, false)
snapshotIDs := testListSnapshots(t, env.gopts, 1)
rtest.Assert(t, reflect.DeepEqual(oldSnapshotIDs, snapshotIDs), "unexpected snapshot id mismatch %v vs. %v", oldSnapshotIDs, snapshotIDs)
testRunCheck(t, env.gopts)
}