restic/cmd/restic/integration_fuse_test.go

220 lines
5.9 KiB
Go
Raw Normal View History

2022-03-28 20:23:47 +00:00
//go:build darwin || freebsd || linux
// +build darwin freebsd linux
package main
import (
"context"
"fmt"
"os"
"path/filepath"
"testing"
"time"
2017-07-23 12:21:03 +00:00
"github.com/restic/restic/internal/repository"
2017-07-24 15:42:25 +00:00
"github.com/restic/restic/internal/restic"
rtest "github.com/restic/restic/internal/test"
)
2015-07-19 20:53:10 +00:00
const (
mountWait = 20
mountSleep = 100 * time.Millisecond
mountTestSubdir = "snapshots"
)
2016-09-15 19:17:20 +00:00
func snapshotsDirExists(t testing.TB, dir string) bool {
f, err := os.Open(filepath.Join(dir, mountTestSubdir))
if err != nil && os.IsNotExist(err) {
return false
}
2015-07-19 20:53:10 +00:00
2016-09-15 19:17:20 +00:00
if err != nil {
t.Error(err)
}
2015-07-19 20:53:10 +00:00
2016-09-15 19:17:20 +00:00
if err := f.Close(); err != nil {
t.Error(err)
}
2015-07-19 20:53:10 +00:00
2016-09-15 19:17:20 +00:00
return true
}
// waitForMount blocks (max mountWait * mountSleep) until the subdir
// "snapshots" appears in the dir.
func waitForMount(t testing.TB, dir string) {
for i := 0; i < mountWait; i++ {
if snapshotsDirExists(t, dir) {
t.Log("mounted directory is ready")
return
2015-07-19 20:53:10 +00:00
}
time.Sleep(mountSleep)
}
2016-09-15 19:17:20 +00:00
t.Errorf("subdir %q of dir %s never appeared", mountTestSubdir, dir)
2015-07-19 20:53:10 +00:00
}
2017-06-18 12:23:35 +00:00
func testRunMount(t testing.TB, gopts GlobalOptions, dir string) {
opts := MountOptions{
TimeTemplate: time.RFC3339,
}
rtest.OK(t, runMount(context.TODO(), opts, gopts, []string{dir}))
2016-09-15 19:17:20 +00:00
}
2017-06-18 12:23:35 +00:00
func testRunUmount(t testing.TB, gopts GlobalOptions, dir string) {
2016-09-15 19:32:15 +00:00
var err error
for i := 0; i < mountWait; i++ {
2017-06-18 12:23:35 +00:00
if err = umount(dir); err == nil {
2016-09-15 19:32:15 +00:00
t.Logf("directory %v umounted", dir)
return
}
time.Sleep(mountSleep)
}
t.Errorf("unable to umount dir %v, last error was: %v", dir, err)
2016-09-15 19:17:20 +00:00
}
func listSnapshots(t testing.TB, dir string) []string {
snapshotsDir, err := os.Open(filepath.Join(dir, "snapshots"))
rtest.OK(t, err)
2016-09-15 19:17:20 +00:00
names, err := snapshotsDir.Readdirnames(-1)
rtest.OK(t, err)
rtest.OK(t, snapshotsDir.Close())
2016-09-15 19:17:20 +00:00
return names
}
func checkSnapshots(t testing.TB, global GlobalOptions, repo *repository.Repository, mountpoint, repodir string, snapshotIDs restic.IDs, expectedSnapshotsInFuseDir int) {
2016-09-18 16:30:25 +00:00
t.Logf("checking for %d snapshots: %v", len(snapshotIDs), snapshotIDs)
2017-06-18 12:23:35 +00:00
go testRunMount(t, global, mountpoint)
2016-09-18 16:30:25 +00:00
waitForMount(t, mountpoint)
2017-06-18 12:23:35 +00:00
defer testRunUmount(t, global, mountpoint)
2016-09-18 16:30:25 +00:00
if !snapshotsDirExists(t, mountpoint) {
t.Fatal(`virtual directory "snapshots" doesn't exist`)
}
2016-09-18 16:30:25 +00:00
ids := listSnapshots(t, repodir)
t.Logf("found %v snapshots in repo: %v", len(ids), ids)
2016-09-18 16:30:25 +00:00
namesInSnapshots := listSnapshots(t, mountpoint)
t.Logf("found %v snapshots in fuse mount: %v", len(namesInSnapshots), namesInSnapshots)
rtest.Assert(t,
expectedSnapshotsInFuseDir == len(namesInSnapshots),
"Invalid number of snapshots: expected %d, got %d", expectedSnapshotsInFuseDir, len(namesInSnapshots))
2015-07-19 13:21:21 +00:00
2016-09-18 16:30:25 +00:00
namesMap := make(map[string]bool)
for _, name := range namesInSnapshots {
namesMap[name] = false
}
2016-09-15 19:17:20 +00:00
// Is "latest" present?
if len(namesMap) != 0 {
_, ok := namesMap["latest"]
if !ok {
t.Errorf("Symlink latest isn't present in fuse dir")
} else {
namesMap["latest"] = true
}
}
2016-09-18 16:30:25 +00:00
for _, id := range snapshotIDs {
snapshot, err := restic.LoadSnapshot(context.TODO(), repo, id)
rtest.OK(t, err)
2016-09-18 16:30:25 +00:00
ts := snapshot.Time.Format(time.RFC3339)
present, ok := namesMap[ts]
if !ok {
t.Errorf("Snapshot %v (%q) isn't present in fuse dir", id.Str(), ts)
}
2016-09-15 19:17:20 +00:00
2016-09-18 16:30:25 +00:00
for i := 1; present; i++ {
ts = fmt.Sprintf("%s-%d", snapshot.Time.Format(time.RFC3339), i)
present, ok = namesMap[ts]
if !ok {
t.Errorf("Snapshot %v (%q) isn't present in fuse dir", id.Str(), ts)
2016-09-15 19:17:20 +00:00
}
2016-09-18 16:30:25 +00:00
if !present {
break
2016-09-15 19:17:20 +00:00
}
}
2016-09-18 16:30:25 +00:00
namesMap[ts] = true
}
for name, present := range namesMap {
rtest.Assert(t, present, "Directory %s is present in fuse dir but is not a snapshot", name)
2016-09-18 16:30:25 +00:00
}
}
func TestMount(t *testing.T) {
if !rtest.RunFuseTest {
2016-09-18 16:30:25 +00:00
t.Skip("Skipping fuse tests")
}
env, cleanup := withTestEnvironment(t)
// must list snapshots more than once
env.gopts.backendTestHook = nil
defer cleanup()
2017-06-18 12:23:35 +00:00
testRunInit(t, env.gopts)
repo, err := OpenRepository(context.TODO(), env.gopts)
rtest.OK(t, err)
checkSnapshots(t, env.gopts, repo, env.mountpoint, env.repo, []restic.ID{}, 0)
rtest.SetupTarTestFixture(t, env.testdata, filepath.Join("testdata", "backup-data.tar.gz"))
// first backup
2018-03-25 21:36:31 +00:00
testRunBackup(t, "", []string{env.testdata}, BackupOptions{}, env.gopts)
snapshotIDs := testRunList(t, "snapshots", env.gopts)
rtest.Assert(t, len(snapshotIDs) == 1,
"expected one snapshot, got %v", snapshotIDs)
checkSnapshots(t, env.gopts, repo, env.mountpoint, env.repo, snapshotIDs, 2)
// second backup, implicit incremental
2018-03-25 21:36:31 +00:00
testRunBackup(t, "", []string{env.testdata}, BackupOptions{}, env.gopts)
snapshotIDs = testRunList(t, "snapshots", env.gopts)
rtest.Assert(t, len(snapshotIDs) == 2,
"expected two snapshots, got %v", snapshotIDs)
checkSnapshots(t, env.gopts, repo, env.mountpoint, env.repo, snapshotIDs, 3)
// third backup, explicit incremental
bopts := BackupOptions{Parent: snapshotIDs[0].String()}
2018-03-25 21:36:31 +00:00
testRunBackup(t, "", []string{env.testdata}, bopts, env.gopts)
snapshotIDs = testRunList(t, "snapshots", env.gopts)
rtest.Assert(t, len(snapshotIDs) == 3,
"expected three snapshots, got %v", snapshotIDs)
checkSnapshots(t, env.gopts, repo, env.mountpoint, env.repo, snapshotIDs, 4)
2016-09-18 16:30:25 +00:00
}
func TestMountSameTimestamps(t *testing.T) {
if !rtest.RunFuseTest {
2016-09-18 16:30:25 +00:00
t.Skip("Skipping fuse tests")
}
env, cleanup := withTestEnvironment(t)
// must list snapshots more than once
env.gopts.backendTestHook = nil
defer cleanup()
2016-09-18 16:30:25 +00:00
rtest.SetupTarTestFixture(t, env.base, filepath.Join("testdata", "repo-same-timestamps.tar.gz"))
2016-09-18 16:30:25 +00:00
repo, err := OpenRepository(context.TODO(), env.gopts)
rtest.OK(t, err)
ids := []restic.ID{
restic.TestParseID("280303689e5027328889a06d718b729e96a1ce6ae9ef8290bff550459ae611ee"),
restic.TestParseID("75ad6cdc0868e082f2596d5ab8705e9f7d87316f5bf5690385eeff8dbe49d9f5"),
restic.TestParseID("5fd0d8b2ef0fa5d23e58f1e460188abb0f525c0f0c4af8365a1280c807a80a1b"),
}
2016-09-18 16:30:25 +00:00
checkSnapshots(t, env.gopts, repo, env.mountpoint, env.repo, ids, 4)
}