github.com/anishathalye/periscope@v0.3.5/internal/db/db_test.go (about) 1 package db 2 3 import ( 4 "io/ioutil" 5 "os" 6 "path/filepath" 7 "reflect" 8 "strings" 9 "testing" 10 ) 11 12 func check(t *testing.T, err error) { 13 if err != nil { 14 t.Fatal(err) 15 } 16 } 17 18 func newInMemoryDb(t *testing.T) *Session { 19 db, err := NewInMemory() 20 check(t, err) 21 return db 22 } 23 24 func addAll(db *Session, infos []FileInfo) error { 25 for _, i := range infos { 26 err := db.Add(i) 27 if err != nil { 28 return err 29 } 30 } 31 return nil 32 } 33 34 func TestVersionOk(t *testing.T) { 35 dir, err := ioutil.TempDir("", "") 36 if err != nil { 37 t.Fatal(err) 38 } 39 defer os.RemoveAll(dir) 40 dbPath := filepath.Join(dir, "db.sqlite") 41 _, err = New(dbPath, true) 42 if err != nil { 43 t.Fatal(err) 44 } 45 // check that opening db is ok 46 _, err = New(dbPath, true) 47 if err != nil { 48 t.Fatal(err) 49 } 50 } 51 52 func TestVersionMismatch(t *testing.T) { 53 dir, err := ioutil.TempDir("", "") 54 if err != nil { 55 t.Fatal(err) 56 } 57 defer os.RemoveAll(dir) 58 dbPath := filepath.Join(dir, "db.sqlite") 59 db, err := New(dbPath, true) 60 if err != nil { 61 t.Fatal(err) 62 } 63 // corrupt version 64 _, err = db.db.Exec(`UPDATE meta SET value = ? WHERE key = "version"`, version+1) 65 if err != nil { 66 t.Fatal(err) 67 } 68 // check that we fail when creating another db 69 _, err = New(dbPath, true) 70 if err == nil { 71 t.Fatal("expected error") 72 } 73 expected := "database version mismatch" 74 if !strings.Contains(err.Error(), expected) { 75 t.Fatalf("expected error to contain '%s', was '%s'", expected, err.Error()) 76 } 77 } 78 79 func TestAdd(t *testing.T) { 80 db := newInMemoryDb(t) 81 expected := []FileInfo{ 82 {"/a/x", 1000, []byte("asdf"), []byte("asdfasdf")}, 83 {"/b/x", 1000, []byte("asdf"), []byte("asdfasdf")}, 84 {"/c/y", 33, []byte("xxxx"), nil}, 85 {"/d/z", 2, nil, nil}, 86 } 87 db.Add(expected[0]) 88 db.Add(expected[1]) 89 db.Add(expected[2]) 90 db.Add(expected[3]) 91 check(t, db.CreateIndexes()) 92 got, err := db.AllInfos() 93 check(t, err) 94 if len(got) != 4 { 95 t.Fatal("expected 4 infos") 96 } 97 if !reflect.DeepEqual(expected, got) { 98 t.Fatalf("expected %v, got %v", expected, got) 99 } 100 } 101 102 func TestAddOverwrite(t *testing.T) { 103 db := newInMemoryDb(t) 104 db.Add(FileInfo{"/a", 1000, nil, nil}) 105 db.Add(FileInfo{"/a", 1234, nil, nil}) 106 got, _ := db.AllInfos() 107 if len(got) != 1 { 108 t.Fatal("expected 1 infos") 109 } 110 expected := FileInfo{"/a", 1234, []byte("asdf"), []byte("asdfasdf")} 111 db.Add(expected) 112 got, _ = db.AllInfos() 113 if len(got) != 1 { 114 t.Fatal("expected 1 infos") 115 } 116 if !reflect.DeepEqual(expected, got[0]) { 117 t.Fatalf("expected %v, got %v", expected, got) 118 } 119 } 120 121 func TestAddTransaction(t *testing.T) { 122 db := newInMemoryDb(t) 123 expected := []FileInfo{ 124 {"/a/x", 1000, []byte("asdf"), []byte("asdfasdf")}, 125 {"/b/x", 1000, []byte("asdf"), []byte("asdfasdf")}, 126 {"/c/y", 33, []byte("xxxx"), nil}, 127 {"/d/z", 2, nil, nil}, 128 } 129 tx, _ := db.Begin() 130 tx.Add(expected[0]) 131 tx.Add(expected[1]) 132 tx.Add(expected[2]) 133 tx.Add(expected[3]) 134 check(t, tx.CreateIndexes()) 135 check(t, tx.Commit()) 136 got, err := db.AllInfos() 137 check(t, err) 138 if len(got) != 4 { 139 t.Fatal("expected 4 infos") 140 } 141 if !reflect.DeepEqual(expected, got) { 142 t.Fatalf("expected %v, got %v", expected, got) 143 } 144 } 145 146 func TestSummary(t *testing.T) { 147 db := newInMemoryDb(t) 148 err := addAll(db, []FileInfo{ 149 {"/a/c", 1000, []byte("a"), []byte("aa")}, 150 {"/x/c", 1000, []byte("a"), []byte("aa")}, 151 {"/y/c", 1000, []byte("a"), []byte("aa")}, 152 {"/a/b", 2000, []byte("b"), []byte("bb")}, 153 {"/x/b", 2000, []byte("b"), []byte("bb")}, 154 }) 155 check(t, err) 156 expected := InfoSummary{ 157 Files: 5, 158 Unique: 2, 159 Duplicate: 3, 160 Overhead: 1000*2 + 2000, 161 } 162 got, err := db.Summary() 163 check(t, err) 164 if !reflect.DeepEqual(expected, got) { 165 t.Fatalf("expected %v, got %v", expected, got) 166 } 167 } 168 169 func TestSummaryNonDuplicate(t *testing.T) { 170 db := newInMemoryDb(t) 171 err := addAll(db, []FileInfo{ 172 {"/a/c", 1000, []byte("a"), []byte("aa")}, 173 {"/x/c", 1000, []byte("a"), []byte("aa")}, 174 {"/y/c", 1000, []byte("a"), []byte("aa")}, 175 {"/a/b", 2000, []byte("b"), []byte("bb")}, // has full hash, but no duplicate 176 }) 177 check(t, err) 178 expected := InfoSummary{ 179 Files: 4, 180 Unique: 2, 181 Duplicate: 2, 182 Overhead: 1000 * 2, 183 } 184 got, err := db.Summary() 185 check(t, err) 186 if !reflect.DeepEqual(expected, got) { 187 t.Fatalf("expected %v, got %v", expected, got) 188 } 189 } 190 191 func TestSummaryMissingFullHash(t *testing.T) { 192 db := newInMemoryDb(t) 193 err := addAll(db, []FileInfo{ 194 {"/a/c", 1000, []byte("a"), []byte("aa")}, 195 {"/x/c", 1000, []byte("a"), []byte("aa")}, 196 {"/y/c", 1000, []byte("b"), nil}, 197 }) 198 check(t, err) 199 expected := InfoSummary{ 200 Files: 3, 201 Unique: 2, 202 Duplicate: 1, 203 Overhead: 1000, 204 } 205 got, err := db.Summary() 206 check(t, err) 207 if !reflect.DeepEqual(expected, got) { 208 t.Fatalf("expected %v, got %v", expected, got) 209 } 210 } 211 212 func TestAllDuplicates(t *testing.T) { 213 db := newInMemoryDb(t) 214 infos := []FileInfo{ 215 {"/a/x", 1000, []byte("asdf"), []byte("asdfasdf")}, 216 {"/b/x", 1000, []byte("asdf"), []byte("asdfasdf")}, 217 {"/c/y", 33, []byte("xxxx"), nil}, 218 {"/d/z", 2, nil, nil}, 219 } 220 err := addAll(db, infos) 221 check(t, err) 222 got, err := db.AllDuplicates("") 223 check(t, err) 224 if len(got) != 1 || len(got[0]) != 2 || !reflect.DeepEqual(infos[0], got[0][0]) || !reflect.DeepEqual(infos[1], got[0][1]) { 225 t.Fatalf("expected %v %v, got %v %v", infos[0], infos[1], got[0][0], got[0][1]) 226 } 227 got, err = db.AllDuplicates("/a") 228 check(t, err) 229 if len(got) != 1 || len(got[0]) != 2 || !reflect.DeepEqual(infos[0], got[0][0]) || !reflect.DeepEqual(infos[1], got[0][1]) { 230 t.Fatalf("expected %v %v, got %v %v", infos[0], infos[1], got[0][0], got[0][1]) 231 } 232 got, err = db.AllDuplicates("/c") 233 check(t, err) 234 if len(got) != 0 { 235 t.Fatalf("expected no infos, got %d", len(got)) 236 } 237 } 238 239 func TestLookup(t *testing.T) { 240 db := newInMemoryDb(t) 241 infos := []FileInfo{ 242 {"/a", 133, []byte("a"), []byte("aa")}, 243 {"/b", 133, []byte("a"), []byte("aa")}, 244 {"/x", 1234, []byte("a"), []byte("fff")}, 245 {"/y", 1337, nil, nil}, 246 {"/z", 1338, nil, nil}, 247 } 248 check(t, addAll(db, infos)) 249 got, err := db.Lookup("/a") 250 check(t, err) 251 expected := DuplicateSet{infos[0], infos[1]} 252 if !reflect.DeepEqual(expected, got) { 253 t.Fatalf("expected %v, got %v", expected, got) 254 } 255 got, err = db.Lookup("/b") 256 check(t, err) 257 expected = DuplicateSet{infos[1], infos[0]} 258 if !reflect.DeepEqual(expected, got) { 259 t.Fatalf("expected %v, got %v", expected, got) 260 } 261 // non-existent 262 got, err = db.Lookup("/c") 263 check(t, err) 264 if len(got) != 0 { 265 t.Fatalf("expected empty set") 266 } 267 // no matching 268 got, err = db.Lookup("/x") 269 check(t, err) 270 expected = DuplicateSet{infos[2]} 271 if !reflect.DeepEqual(expected, got) { 272 t.Fatalf("expected %v, got %v", expected, got) 273 } 274 // no full hash 275 got, err = db.Lookup("/y") 276 check(t, err) 277 expected = DuplicateSet{infos[3]} 278 if !reflect.DeepEqual(expected, got) { 279 t.Fatalf("expected %v, got %v", expected, got) 280 } 281 } 282 283 func TestInfosBySize(t *testing.T) { 284 db := newInMemoryDb(t) 285 infos := []FileInfo{ 286 {"/a", 133, []byte("a"), []byte("aa")}, 287 {"/x", 1234, []byte("a"), []byte("fff")}, 288 {"/y", 1337, nil, nil}, 289 {"/z", 1338, nil, nil}, 290 } 291 check(t, addAll(db, infos)) 292 got, err := db.InfosBySize(1234) 293 check(t, err) 294 expected := []FileInfo{{"/x", 1234, []byte("a"), []byte("fff")}} 295 if !reflect.DeepEqual(expected, got) { 296 t.Fatalf("expected %v, got %v", expected, got) 297 } 298 } 299 300 func TestLookupAll(t *testing.T) { 301 db := newInMemoryDb(t) 302 err := addAll(db, []FileInfo{ 303 {"/x/y/a", 1000, []byte("a"), []byte("aa")}, 304 {"/x/z/a", 1000, []byte("a"), []byte("aa")}, 305 {"/x/y/b", 1000, []byte("b"), []byte("bb")}, 306 {"/x/z/b", 1000, []byte("b"), []byte("bb")}, 307 {"/z/.c", 1000, []byte("c"), []byte("cc")}, 308 {"/y/.c", 1000, []byte("c"), []byte("cc")}, 309 {"/z/.d/e", 1000, []byte("d"), []byte("dd")}, 310 {"/y/.d/e", 1000, []byte("d"), []byte("dd")}, 311 {"/w/x/.a", 1000, []byte("e"), []byte("ee")}, 312 {"/w/x/.b", 1000, []byte("e"), []byte("ee")}, 313 {"/x/x", 1234, []byte("x"), []byte("xx")}, 314 {"/x/foo", 1000, []byte("f"), nil}, 315 {"/y/bar", 1000, nil, nil}, 316 }) 317 check(t, err) 318 319 expected := []DuplicateInfo{ 320 {"/x/y/a", []byte("aa"), 2}, 321 {"/x/y/b", []byte("bb"), 2}, 322 {"/x/z/a", []byte("aa"), 2}, 323 {"/x/z/b", []byte("bb"), 2}, 324 } 325 got, err := db.LookupAll("/x", false) 326 check(t, err) 327 if !reflect.DeepEqual(expected, got) { 328 t.Fatalf("expected %v, got %v", expected, got) 329 } 330 331 expected = []DuplicateInfo{ 332 {"/x/y/a", []byte("aa"), 2}, 333 {"/x/y/b", []byte("bb"), 2}, 334 } 335 got, err = db.LookupAll("/x/y", false) 336 check(t, err) 337 if !reflect.DeepEqual(expected, got) { 338 t.Fatalf("expected %v, got %v", expected, got) 339 } 340 341 got, err = db.LookupAll("/z", false) 342 check(t, err) 343 if len(got) != 0 { 344 t.Fatalf("expected [], got %v", got) 345 } 346 347 expected = []DuplicateInfo{ 348 {"/z/.c", []byte("cc"), 2}, 349 {"/z/.d/e", []byte("dd"), 2}, 350 } 351 got, err = db.LookupAll("/z", true) 352 check(t, err) 353 if !reflect.DeepEqual(expected, got) { 354 t.Fatalf("expected %v, got %v", expected, got) 355 } 356 357 expected = []DuplicateInfo{ 358 {"/z/.d/e", []byte("dd"), 2}, 359 } 360 got, err = db.LookupAll("/z/.d", false) 361 check(t, err) 362 if !reflect.DeepEqual(expected, got) { 363 t.Fatalf("expected %v, got %v", expected, got) 364 } 365 366 expected = []DuplicateInfo{ 367 {"/w/x/.a", []byte("ee"), 2}, 368 {"/w/x/.b", []byte("ee"), 2}, 369 } 370 got, err = db.LookupAll("/w/", true) 371 check(t, err) 372 if !reflect.DeepEqual(expected, got) { 373 t.Fatalf("expected %v, got %v", expected, got) 374 } 375 } 376 377 func TestRemove(t *testing.T) { 378 db := newInMemoryDb(t) 379 err := addAll(db, []FileInfo{ 380 {"/x/y/a", 1000, []byte("a"), []byte("aa")}, 381 {"/x/z/a", 1000, []byte("a"), []byte("aa")}, 382 {"/x/y/b", 1000, []byte("b"), []byte("bb")}, 383 {"/x/z/b", 1000, []byte("b"), []byte("bb")}, 384 {"/z/.c", 1000, []byte("c"), []byte("cc")}, 385 }) 386 check(t, err) 387 check(t, db.Remove("/x/y/a")) 388 got, err := db.AllDuplicates("") 389 check(t, err) 390 if len(got) != 1 { 391 t.Fatalf("expected 1 duplicate set, got %d", len(got)) 392 } 393 got2, err := db.AllInfos() 394 if len(got2) != 4 { 395 t.Fatalf("expected 4 infos, got %d", len(got2)) 396 } 397 } 398 399 func TestRemoveDir(t *testing.T) { 400 db := newInMemoryDb(t) 401 addAll(db, []FileInfo{ 402 {"/hello/x", 1000, []byte("a"), []byte("aa")}, 403 {"/hello/y", 1000, []byte("a"), []byte("aa")}, 404 {"/helloasdf", 1000, []byte("a"), []byte("aa")}, 405 {"/goodbye/z", 1000, []byte("b"), []byte("bb")}, 406 {"/goodbye/w", 1000, []byte("b"), []byte("bb")}, 407 {"/goodbyeasdf", 1000, []byte("b"), []byte("bb")}, 408 }) 409 check(t, db.RemoveDir("/hello", 0, 0)) 410 got, err := db.AllInfos() 411 check(t, err) 412 if len(got) != 4 { 413 t.Fatalf("expected 4 infos, got %d", len(got)) 414 } 415 check(t, db.RemoveDir("/goodbye/", 0, 0)) 416 got, err = db.AllInfos() 417 check(t, err) 418 if len(got) != 2 { 419 t.Fatalf("expected 2 infos, got %d", len(got)) 420 } 421 }