github.com/anishathalye/periscope@v0.3.5/internal/periscope/refresh_test.go (about) 1 package periscope 2 3 import ( 4 "github.com/anishathalye/periscope/internal/db" 5 "github.com/anishathalye/periscope/internal/testfs" 6 7 "bytes" 8 "io/ioutil" 9 "os" 10 "path/filepath" 11 "testing" 12 13 "github.com/spf13/afero" 14 ) 15 16 func TestRefreshBasic(t *testing.T) { 17 fs := testfs.Read(` 18 /a [10000 1] 19 /b [10000 1] 20 /c/d/e [10000 1] 21 `).Mkfs() 22 ps, _, _ := newTest(fs) 23 ps.Scan([]string{"/"}, &ScanOptions{}) 24 fs.Remove("/b") 25 err := ps.Refresh(&RefreshOptions{}) 26 check(t, err) 27 got, _ := ps.db.AllDuplicates("") 28 expected := []db.DuplicateSet{{ 29 {Path: "/a", Size: 10000, ShortHash: nil, FullHash: nil}, 30 {Path: "/c/d/e", Size: 10000, ShortHash: nil, FullHash: nil}, 31 }} 32 checkEquivalentDuplicateSet(t, expected, got) 33 } 34 35 func TestRefreshNoChange(t *testing.T) { 36 fs := testfs.Read(` 37 /a [10000 1] 38 /b [10000 1] 39 /c/d/e [10000 1] 40 `).Mkfs() 41 ps, _, _ := newTest(fs) 42 ps.Scan([]string{"/"}, &ScanOptions{}) 43 err := ps.Refresh(&RefreshOptions{}) 44 check(t, err) 45 got, _ := ps.db.AllDuplicates("") 46 expected := []db.DuplicateSet{{ 47 {Path: "/a", Size: 10000, ShortHash: nil, FullHash: nil}, 48 {Path: "/b", Size: 10000, ShortHash: nil, FullHash: nil}, 49 {Path: "/c/d/e", Size: 10000, ShortHash: nil, FullHash: nil}, 50 }} 51 checkEquivalentDuplicateSet(t, expected, got) 52 } 53 54 func TestRefreshModifyFile(t *testing.T) { 55 fs := testfs.Read(` 56 /a [10000 1] 57 /b [10000 1] 58 /c/d/e [10000 1] 59 `).Mkfs() 60 ps, _, _ := newTest(fs) 61 ps.Scan([]string{"/"}, &ScanOptions{}) 62 afero.WriteFile(fs, "/a", []byte{'a', 'b', 'c'}, 0o644) 63 // double check that they're different 64 hashA, _ := ps.hashFile("/a") 65 hashB, _ := ps.hashFile("/b") 66 if bytes.Equal(hashA, hashB) { 67 t.Fatal("files are still equal") 68 } 69 err := ps.Refresh(&RefreshOptions{}) 70 check(t, err) 71 got, _ := ps.db.AllDuplicates("") 72 // refresh only checks that the files are still there, so we should 73 // still see it as a duplicate 74 expected := []db.DuplicateSet{{ 75 {Path: "/a", Size: 10000, ShortHash: nil, FullHash: nil}, 76 {Path: "/b", Size: 10000, ShortHash: nil, FullHash: nil}, 77 {Path: "/c/d/e", Size: 10000, ShortHash: nil, FullHash: nil}, 78 }} 79 checkEquivalentDuplicateSet(t, expected, got) 80 } 81 82 func TestRefreshMove(t *testing.T) { 83 fs := testfs.Read(` 84 /a [10000 1] 85 /b [10000 1] 86 /c/d/e [10000 1] 87 `).Mkfs() 88 ps, _, _ := newTest(fs) 89 ps.Scan([]string{"/"}, &ScanOptions{}) 90 fs.Rename("/a", "/f") 91 err := ps.Refresh(&RefreshOptions{}) 92 check(t, err) 93 got, _ := ps.db.AllDuplicates("") 94 expected := []db.DuplicateSet{{ 95 {Path: "/b", Size: 10000, ShortHash: nil, FullHash: nil}, 96 {Path: "/c/d/e", Size: 10000, ShortHash: nil, FullHash: nil}, 97 }} 98 checkEquivalentDuplicateSet(t, expected, got) 99 100 ps.Scan([]string{"/"}, &ScanOptions{}) 101 got, _ = ps.db.AllDuplicates("") 102 expected = []db.DuplicateSet{{ 103 {Path: "/b", Size: 10000, ShortHash: nil, FullHash: nil}, 104 {Path: "/c/d/e", Size: 10000, ShortHash: nil, FullHash: nil}, 105 {Path: "/f", Size: 10000, ShortHash: nil, FullHash: nil}, 106 }} 107 checkEquivalentDuplicateSet(t, expected, got) 108 } 109 110 func TestRefreshReplaceFileWithDirectory(t *testing.T) { 111 fs := testfs.Read(` 112 /a [10000 1] 113 /b [10000 1] 114 /c/d/e [10000 1] 115 `).Mkfs() 116 ps, _, _ := newTest(fs) 117 ps.Scan([]string{"/"}, &ScanOptions{}) 118 fs.Remove("/a") 119 fs.Mkdir("/a", 0o755) 120 afero.WriteFile(fs, "/a/x", []byte{'x'}, 0o644) 121 err := ps.Refresh(&RefreshOptions{}) 122 check(t, err) 123 got, _ := ps.db.AllDuplicates("") 124 expected := []db.DuplicateSet{{ 125 {Path: "/b", Size: 10000, ShortHash: nil, FullHash: nil}, 126 {Path: "/c/d/e", Size: 10000, ShortHash: nil, FullHash: nil}, 127 }} 128 checkEquivalentDuplicateSet(t, expected, got) 129 } 130 131 func TestRefreshRemoveSingletons(t *testing.T) { 132 fs := testfs.Read(` 133 /a/x/1 [10000 1] 134 /b/2 [10000 1] 135 `).Mkfs() 136 ps, _, _ := newTest(fs) 137 ps.Scan([]string{"/"}, &ScanOptions{}) 138 fs.Remove("/a/x/1") 139 err := ps.Refresh(&RefreshOptions{}) 140 check(t, err) 141 got, _ := ps.db.AllDuplicates("") 142 if len(got) != 0 { 143 t.Fatalf("expected no duplicate sets, got %d", len(got)) 144 } 145 } 146 147 func TestRefreshPreserveNonSingletons(t *testing.T) { 148 fs := testfs.Read(` 149 /a [10000 1] 150 /b [10000 1] 151 /c/d/e [10000 1] 152 /f [1337 2] 153 /g [1337 2] 154 `).Mkfs() 155 ps, _, _ := newTest(fs) 156 ps.Scan([]string{"/"}, &ScanOptions{}) 157 fs.Remove("/a") 158 fs.Remove("/f") 159 err := ps.Refresh(&RefreshOptions{}) 160 check(t, err) 161 got, _ := ps.db.AllDuplicates("") 162 expected := []db.DuplicateSet{{ 163 {Path: "/b", Size: 10000, ShortHash: nil, FullHash: nil}, 164 {Path: "/c/d/e", Size: 10000, ShortHash: nil, FullHash: nil}, 165 }} 166 checkEquivalentDuplicateSet(t, expected, got) 167 } 168 169 func TestRefreshPermissionError(t *testing.T) { 170 fs := afero.NewOsFs() 171 dir := tempDir() 172 defer os.RemoveAll(dir) 173 os.Mkdir(filepath.Join(dir, "d1"), 0o755) 174 os.Mkdir(filepath.Join(dir, "d2"), 0o755) 175 ioutil.WriteFile(filepath.Join(dir, "d1", "w"), []byte{'a'}, 0o644) 176 ioutil.WriteFile(filepath.Join(dir, "d1", "x"), []byte{'a'}, 0o644) 177 ioutil.WriteFile(filepath.Join(dir, "d2", "y"), []byte{'b'}, 0o644) 178 ioutil.WriteFile(filepath.Join(dir, "d2", "z"), []byte{'b'}, 0o644) 179 ps, _, _ := newTest(fs) 180 ps.Scan([]string{dir}, &ScanOptions{}) 181 os.Chmod(filepath.Join(dir, "d1"), 0o000) 182 ps.Refresh(&RefreshOptions{}) 183 got, _ := ps.db.AllDuplicates("") 184 expected := []db.DuplicateSet{{ 185 {Path: filepath.Join(dir, "d2", "y"), Size: 1, ShortHash: nil, FullHash: nil}, 186 {Path: filepath.Join(dir, "d2", "z"), Size: 1, ShortHash: nil, FullHash: nil}, 187 }} 188 checkEquivalentDuplicateSet(t, expected, got) 189 } 190 191 func TestRefreshNonRegularFile(t *testing.T) { 192 fs := afero.NewOsFs() 193 dir := tempDir() 194 defer os.RemoveAll(dir) 195 ioutil.WriteFile(filepath.Join(dir, "w"), []byte{'a'}, 0o644) 196 ioutil.WriteFile(filepath.Join(dir, "x"), []byte{'a'}, 0o644) 197 ioutil.WriteFile(filepath.Join(dir, "y"), []byte{'b'}, 0o644) 198 ioutil.WriteFile(filepath.Join(dir, "z"), []byte{'b'}, 0o644) 199 ps, _, _ := newTest(fs) 200 ps.Scan([]string{dir}, &ScanOptions{}) 201 os.Remove(filepath.Join(dir, "w")) 202 os.Symlink(filepath.Join(dir, "x"), filepath.Join(dir, "w")) 203 ps.Refresh(&RefreshOptions{}) 204 got, _ := ps.db.AllDuplicates("") 205 expected := []db.DuplicateSet{{ 206 {Path: filepath.Join(dir, "y"), Size: 1, ShortHash: nil, FullHash: nil}, 207 {Path: filepath.Join(dir, "z"), Size: 1, ShortHash: nil, FullHash: nil}, 208 }} 209 checkEquivalentDuplicateSet(t, expected, got) 210 } 211 212 func TestRefreshSymlinkDir(t *testing.T) { 213 fs := afero.NewOsFs() 214 dir := tempDir() 215 defer os.RemoveAll(dir) 216 os.Mkdir(filepath.Join(dir, "d"), 0o755) 217 os.Mkdir(filepath.Join(dir, "d2"), 0o755) 218 ioutil.WriteFile(filepath.Join(dir, "d", "x"), []byte{'b'}, 0o644) 219 ioutil.WriteFile(filepath.Join(dir, "d2", "y"), []byte{'b'}, 0o644) 220 ps, _, _ := newTest(fs) 221 ps.Scan([]string{dir}, &ScanOptions{}) 222 os.RemoveAll(filepath.Join(dir, "d2")) 223 os.Symlink(filepath.Join(dir, "d"), filepath.Join(dir, "d2")) 224 ps.Refresh(&RefreshOptions{}) 225 got, _ := ps.db.AllDuplicates("") 226 if len(got) != 0 { 227 t.Fatalf("expected no duplicates, got %d", len(got)) 228 } 229 }