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  }