github.com/advanderveer/restic@v0.8.1-0.20171209104529-42a8c19aaea6/cmd/restic/integration_fuse_test.go (about) 1 // +build !openbsd 2 // +build !windows 3 4 package main 5 6 import ( 7 "context" 8 "fmt" 9 "os" 10 "path/filepath" 11 "testing" 12 "time" 13 14 "github.com/restic/restic/internal/repository" 15 "github.com/restic/restic/internal/restic" 16 rtest "github.com/restic/restic/internal/test" 17 ) 18 19 const ( 20 mountWait = 20 21 mountSleep = 100 * time.Millisecond 22 mountTestSubdir = "snapshots" 23 ) 24 25 func snapshotsDirExists(t testing.TB, dir string) bool { 26 f, err := os.Open(filepath.Join(dir, mountTestSubdir)) 27 if err != nil && os.IsNotExist(err) { 28 return false 29 } 30 31 if err != nil { 32 t.Error(err) 33 } 34 35 if err := f.Close(); err != nil { 36 t.Error(err) 37 } 38 39 return true 40 } 41 42 // waitForMount blocks (max mountWait * mountSleep) until the subdir 43 // "snapshots" appears in the dir. 44 func waitForMount(t testing.TB, dir string) { 45 for i := 0; i < mountWait; i++ { 46 if snapshotsDirExists(t, dir) { 47 t.Log("mounted directory is ready") 48 return 49 } 50 51 time.Sleep(mountSleep) 52 } 53 54 t.Errorf("subdir %q of dir %s never appeared", mountTestSubdir, dir) 55 } 56 57 func testRunMount(t testing.TB, gopts GlobalOptions, dir string) { 58 opts := MountOptions{} 59 rtest.OK(t, runMount(opts, gopts, []string{dir})) 60 } 61 62 func testRunUmount(t testing.TB, gopts GlobalOptions, dir string) { 63 var err error 64 for i := 0; i < mountWait; i++ { 65 if err = umount(dir); err == nil { 66 t.Logf("directory %v umounted", dir) 67 return 68 } 69 70 time.Sleep(mountSleep) 71 } 72 73 t.Errorf("unable to umount dir %v, last error was: %v", dir, err) 74 } 75 76 func listSnapshots(t testing.TB, dir string) []string { 77 snapshotsDir, err := os.Open(filepath.Join(dir, "snapshots")) 78 rtest.OK(t, err) 79 names, err := snapshotsDir.Readdirnames(-1) 80 rtest.OK(t, err) 81 rtest.OK(t, snapshotsDir.Close()) 82 return names 83 } 84 85 func checkSnapshots(t testing.TB, global GlobalOptions, repo *repository.Repository, mountpoint, repodir string, snapshotIDs restic.IDs, expectedSnapshotsInFuseDir int) { 86 t.Logf("checking for %d snapshots: %v", len(snapshotIDs), snapshotIDs) 87 88 go testRunMount(t, global, mountpoint) 89 waitForMount(t, mountpoint) 90 defer testRunUmount(t, global, mountpoint) 91 92 if !snapshotsDirExists(t, mountpoint) { 93 t.Fatal(`virtual directory "snapshots" doesn't exist`) 94 } 95 96 ids := listSnapshots(t, repodir) 97 t.Logf("found %v snapshots in repo: %v", len(ids), ids) 98 99 namesInSnapshots := listSnapshots(t, mountpoint) 100 t.Logf("found %v snapshots in fuse mount: %v", len(namesInSnapshots), namesInSnapshots) 101 rtest.Assert(t, 102 expectedSnapshotsInFuseDir == len(namesInSnapshots), 103 "Invalid number of snapshots: expected %d, got %d", expectedSnapshotsInFuseDir, len(namesInSnapshots)) 104 105 namesMap := make(map[string]bool) 106 for _, name := range namesInSnapshots { 107 namesMap[name] = false 108 } 109 110 // Is "latest" present? 111 if len(namesMap) != 0 { 112 _, ok := namesMap["latest"] 113 if !ok { 114 t.Errorf("Symlink latest isn't present in fuse dir") 115 } else { 116 namesMap["latest"] = true 117 } 118 } 119 120 for _, id := range snapshotIDs { 121 snapshot, err := restic.LoadSnapshot(context.TODO(), repo, id) 122 rtest.OK(t, err) 123 124 ts := snapshot.Time.Format(time.RFC3339) 125 present, ok := namesMap[ts] 126 if !ok { 127 t.Errorf("Snapshot %v (%q) isn't present in fuse dir", id.Str(), ts) 128 } 129 130 for i := 1; present; i++ { 131 ts = fmt.Sprintf("%s-%d", snapshot.Time.Format(time.RFC3339), i) 132 present, ok = namesMap[ts] 133 if !ok { 134 t.Errorf("Snapshot %v (%q) isn't present in fuse dir", id.Str(), ts) 135 } 136 137 if !present { 138 break 139 } 140 } 141 142 namesMap[ts] = true 143 } 144 145 for name, present := range namesMap { 146 rtest.Assert(t, present, "Directory %s is present in fuse dir but is not a snapshot", name) 147 } 148 } 149 150 func TestMount(t *testing.T) { 151 if !rtest.RunFuseTest { 152 t.Skip("Skipping fuse tests") 153 } 154 155 env, cleanup := withTestEnvironment(t) 156 defer cleanup() 157 158 testRunInit(t, env.gopts) 159 160 repo, err := OpenRepository(env.gopts) 161 rtest.OK(t, err) 162 163 // We remove the mountpoint now to check that cmdMount creates it 164 rtest.RemoveAll(t, env.mountpoint) 165 166 checkSnapshots(t, env.gopts, repo, env.mountpoint, env.repo, []restic.ID{}, 0) 167 168 rtest.SetupTarTestFixture(t, env.testdata, filepath.Join("testdata", "backup-data.tar.gz")) 169 170 // first backup 171 testRunBackup(t, []string{env.testdata}, BackupOptions{}, env.gopts) 172 snapshotIDs := testRunList(t, "snapshots", env.gopts) 173 rtest.Assert(t, len(snapshotIDs) == 1, 174 "expected one snapshot, got %v", snapshotIDs) 175 176 checkSnapshots(t, env.gopts, repo, env.mountpoint, env.repo, snapshotIDs, 2) 177 178 // second backup, implicit incremental 179 testRunBackup(t, []string{env.testdata}, BackupOptions{}, env.gopts) 180 snapshotIDs = testRunList(t, "snapshots", env.gopts) 181 rtest.Assert(t, len(snapshotIDs) == 2, 182 "expected two snapshots, got %v", snapshotIDs) 183 184 checkSnapshots(t, env.gopts, repo, env.mountpoint, env.repo, snapshotIDs, 3) 185 186 // third backup, explicit incremental 187 bopts := BackupOptions{Parent: snapshotIDs[0].String()} 188 testRunBackup(t, []string{env.testdata}, bopts, env.gopts) 189 snapshotIDs = testRunList(t, "snapshots", env.gopts) 190 rtest.Assert(t, len(snapshotIDs) == 3, 191 "expected three snapshots, got %v", snapshotIDs) 192 193 checkSnapshots(t, env.gopts, repo, env.mountpoint, env.repo, snapshotIDs, 4) 194 } 195 196 func TestMountSameTimestamps(t *testing.T) { 197 if !rtest.RunFuseTest { 198 t.Skip("Skipping fuse tests") 199 } 200 201 env, cleanup := withTestEnvironment(t) 202 defer cleanup() 203 204 rtest.SetupTarTestFixture(t, env.base, filepath.Join("testdata", "repo-same-timestamps.tar.gz")) 205 206 repo, err := OpenRepository(env.gopts) 207 rtest.OK(t, err) 208 209 ids := []restic.ID{ 210 restic.TestParseID("280303689e5027328889a06d718b729e96a1ce6ae9ef8290bff550459ae611ee"), 211 restic.TestParseID("75ad6cdc0868e082f2596d5ab8705e9f7d87316f5bf5690385eeff8dbe49d9f5"), 212 restic.TestParseID("5fd0d8b2ef0fa5d23e58f1e460188abb0f525c0f0c4af8365a1280c807a80a1b"), 213 } 214 215 checkSnapshots(t, env.gopts, repo, env.mountpoint, env.repo, ids, 4) 216 }