Browse Source

storage: add more tests for index

Yicheng Qin 10 years ago
parent
commit
0813139140
1 changed files with 167 additions and 136 deletions
  1. 167 136
      storage/index_test.go

+ 167 - 136
storage/index_test.go

@@ -5,35 +5,55 @@ import (
 	"testing"
 	"testing"
 )
 )
 
 
-func TestIndexPutAndGet(t *testing.T) {
-	index := newTestTreeIndex()
-
-	tests := []T{
-		{[]byte("foo"), 0, ErrRevisionNotFound, 0},
-		{[]byte("foo"), 1, nil, 1},
-		{[]byte("foo"), 3, nil, 1},
-		{[]byte("foo"), 5, nil, 5},
-		{[]byte("foo"), 6, nil, 5},
-
-		{[]byte("foo1"), 0, ErrRevisionNotFound, 0},
-		{[]byte("foo1"), 1, ErrRevisionNotFound, 0},
-		{[]byte("foo1"), 2, nil, 2},
-		{[]byte("foo1"), 5, nil, 2},
-		{[]byte("foo1"), 6, nil, 6},
-
-		{[]byte("foo2"), 0, ErrRevisionNotFound, 0},
-		{[]byte("foo2"), 1, ErrRevisionNotFound, 0},
-		{[]byte("foo2"), 3, nil, 3},
-		{[]byte("foo2"), 4, nil, 4},
-		{[]byte("foo2"), 6, nil, 4},
+func TestIndexGet(t *testing.T) {
+	index := newTreeIndex()
+	index.Put([]byte("foo"), revision{main: 2})
+	index.Put([]byte("foo"), revision{main: 4})
+	index.Tombstone([]byte("foo"), revision{main: 6})
+
+	tests := []struct {
+		rev int64
+
+		wrev     revision
+		wcreated revision
+		wver     int64
+		werr     error
+	}{
+		{0, revision{}, revision{}, 0, ErrRevisionNotFound},
+		{1, revision{}, revision{}, 0, ErrRevisionNotFound},
+		{2, revision{main: 2}, revision{main: 2}, 1, nil},
+		{3, revision{main: 2}, revision{main: 2}, 1, nil},
+		{4, revision{main: 4}, revision{main: 2}, 2, nil},
+		{5, revision{main: 4}, revision{main: 2}, 2, nil},
+		{6, revision{}, revision{}, 0, ErrRevisionNotFound},
+	}
+	for i, tt := range tests {
+		rev, created, ver, err := index.Get([]byte("foo"), tt.rev)
+		if err != tt.werr {
+			t.Errorf("#%d: err = %v, want %v", i, err, tt.werr)
+		}
+		if rev != tt.wrev {
+			t.Errorf("#%d: rev = %+v, want %+v", i, rev, tt.wrev)
+		}
+		if created != tt.wcreated {
+			t.Errorf("#%d: created = %+v, want %+v", i, created, tt.wcreated)
+		}
+		if ver != tt.wver {
+			t.Errorf("#%d: ver = %d, want %d", i, ver, tt.wver)
+		}
 	}
 	}
-	verify(t, index, tests)
 }
 }
 
 
 func TestIndexRange(t *testing.T) {
 func TestIndexRange(t *testing.T) {
-	atRev := int64(3)
 	allKeys := [][]byte{[]byte("foo"), []byte("foo1"), []byte("foo2")}
 	allKeys := [][]byte{[]byte("foo"), []byte("foo1"), []byte("foo2")}
 	allRevs := []revision{{main: 1}, {main: 2}, {main: 3}}
 	allRevs := []revision{{main: 1}, {main: 2}, {main: 3}}
+
+	index := newTreeIndex()
+	for i := range allKeys {
+		index.Put(allKeys[i], allRevs[i])
+	}
+
+	atRev := int64(3)
 	tests := []struct {
 	tests := []struct {
 		key, end []byte
 		key, end []byte
 		wkeys    [][]byte
 		wkeys    [][]byte
@@ -73,7 +93,6 @@ func TestIndexRange(t *testing.T) {
 		},
 		},
 	}
 	}
 	for i, tt := range tests {
 	for i, tt := range tests {
-		index := newTestTreeIndex()
 		keys, revs := index.Range(tt.key, tt.end, atRev)
 		keys, revs := index.Range(tt.key, tt.end, atRev)
 		if !reflect.DeepEqual(keys, tt.wkeys) {
 		if !reflect.DeepEqual(keys, tt.wkeys) {
 			t.Errorf("#%d: keys = %+v, want %+v", i, keys, tt.wkeys)
 			t.Errorf("#%d: keys = %+v, want %+v", i, keys, tt.wkeys)
@@ -85,139 +104,151 @@ func TestIndexRange(t *testing.T) {
 }
 }
 
 
 func TestIndexTombstone(t *testing.T) {
 func TestIndexTombstone(t *testing.T) {
-	index := newTestTreeIndex()
+	index := newTreeIndex()
+	index.Put([]byte("foo"), revision{main: 1})
 
 
-	err := index.Tombstone([]byte("foo"), revision{main: 7})
+	err := index.Tombstone([]byte("foo"), revision{main: 2})
 	if err != nil {
 	if err != nil {
 		t.Errorf("tombstone error = %v, want nil", err)
 		t.Errorf("tombstone error = %v, want nil", err)
 	}
 	}
-	_, _, _, err = index.Get([]byte("foo"), 7)
+
+	_, _, _, err = index.Get([]byte("foo"), 2)
 	if err != ErrRevisionNotFound {
 	if err != ErrRevisionNotFound {
 		t.Errorf("get error = %v, want nil", err)
 		t.Errorf("get error = %v, want nil", err)
 	}
 	}
-}
-
-func TestContinuousCompact(t *testing.T) {
-	index := newTestTreeIndex()
-
-	tests := []T{
-		{[]byte("foo"), 0, ErrRevisionNotFound, 0},
-		{[]byte("foo"), 1, nil, 1},
-		{[]byte("foo"), 3, nil, 1},
-		{[]byte("foo"), 5, nil, 5},
-		{[]byte("foo"), 6, nil, 5},
-
-		{[]byte("foo1"), 0, ErrRevisionNotFound, 0},
-		{[]byte("foo1"), 1, ErrRevisionNotFound, 0},
-		{[]byte("foo1"), 2, nil, 2},
-		{[]byte("foo1"), 5, nil, 2},
-		{[]byte("foo1"), 6, nil, 6},
-
-		{[]byte("foo2"), 0, ErrRevisionNotFound, 0},
-		{[]byte("foo2"), 1, ErrRevisionNotFound, 0},
-		{[]byte("foo2"), 3, nil, 3},
-		{[]byte("foo2"), 4, nil, 4},
-		{[]byte("foo2"), 6, nil, 4},
-	}
-	wa := map[revision]struct{}{
-		revision{main: 1}: {},
-	}
-	ga := index.Compact(1)
-	if !reflect.DeepEqual(ga, wa) {
-		t.Errorf("a = %v, want %v", ga, wa)
+	err = index.Tombstone([]byte("foo"), revision{main: 3})
+	if err != ErrRevisionNotFound {
+		t.Errorf("tombstone error = %v, want %v", err, ErrRevisionNotFound)
 	}
 	}
-	verify(t, index, tests)
+}
 
 
-	wa = map[revision]struct{}{
-		revision{main: 1}: {},
-		revision{main: 2}: {},
+func TestIndexCompact(t *testing.T) {
+	maxRev := int64(20)
+	tests := []struct {
+		key     []byte
+		remove  bool
+		rev     revision
+		created revision
+		ver     int64
+	}{
+		{[]byte("foo"), false, revision{main: 1}, revision{main: 1}, 1},
+		{[]byte("foo1"), false, revision{main: 2}, revision{main: 2}, 1},
+		{[]byte("foo2"), false, revision{main: 3}, revision{main: 3}, 1},
+		{[]byte("foo2"), false, revision{main: 4}, revision{main: 3}, 2},
+		{[]byte("foo"), false, revision{main: 5}, revision{main: 1}, 2},
+		{[]byte("foo1"), false, revision{main: 6}, revision{main: 2}, 2},
+		{[]byte("foo1"), true, revision{main: 7}, revision{}, 0},
+		{[]byte("foo2"), true, revision{main: 8}, revision{}, 0},
+		{[]byte("foo"), true, revision{main: 9}, revision{}, 0},
+		{[]byte("foo"), false, revision{10, 0}, revision{10, 0}, 1},
+		{[]byte("foo1"), false, revision{10, 1}, revision{10, 1}, 1},
+	}
+
+	// Continuous Compact
+	index := newTreeIndex()
+	for _, tt := range tests {
+		if tt.remove {
+			index.Tombstone(tt.key, tt.rev)
+		} else {
+			index.Put(tt.key, tt.rev)
+		}
 	}
 	}
-	ga = index.Compact(2)
-	if !reflect.DeepEqual(ga, wa) {
-		t.Errorf("a = %v, want %v", ga, wa)
+	for i := int64(1); i < maxRev; i++ {
+		am := index.Compact(i)
+
+		windex := newTreeIndex()
+		for _, tt := range tests {
+			if _, ok := am[tt.rev]; ok || tt.rev.GreaterThan(revision{main: i}) {
+				if tt.remove {
+					windex.Tombstone(tt.key, tt.rev)
+				} else {
+					windex.Restore(tt.key, tt.created, tt.rev, tt.ver)
+				}
+			}
+		}
+		if !index.Equal(windex) {
+			t.Errorf("#%d: not equal index", i)
+		}
 	}
 	}
-	verify(t, index, tests)
 
 
-	wa = map[revision]struct{}{
-		revision{main: 1}: {},
-		revision{main: 2}: {},
-		revision{main: 3}: {},
-	}
-	ga = index.Compact(3)
-	if !reflect.DeepEqual(ga, wa) {
-		t.Errorf("a = %v, want %v", ga, wa)
+	// Once Compact
+	for i := int64(1); i < maxRev; i++ {
+		index := newTreeIndex()
+		for _, tt := range tests {
+			if tt.remove {
+				index.Tombstone(tt.key, tt.rev)
+			} else {
+				index.Put(tt.key, tt.rev)
+			}
+		}
+		am := index.Compact(i)
+
+		windex := newTreeIndex()
+		for _, tt := range tests {
+			if _, ok := am[tt.rev]; ok || tt.rev.GreaterThan(revision{main: i}) {
+				if tt.remove {
+					windex.Tombstone(tt.key, tt.rev)
+				} else {
+					windex.Restore(tt.key, tt.created, tt.rev, tt.ver)
+				}
+			}
+		}
+		if !index.Equal(windex) {
+			t.Errorf("#%d: not equal index", i)
+		}
 	}
 	}
-	verify(t, index, tests)
+}
 
 
-	wa = map[revision]struct{}{
-		revision{main: 1}: {},
-		revision{main: 2}: {},
-		revision{main: 4}: {},
-	}
-	ga = index.Compact(4)
-	delete(wa, revision{main: 3})
-	tests[12] = T{[]byte("foo2"), 3, ErrRevisionNotFound, 0}
-	if !reflect.DeepEqual(wa, ga) {
-		t.Errorf("a = %v, want %v", ga, wa)
-	}
-	verify(t, index, tests)
+func TestIndexRestore(t *testing.T) {
+	key := []byte("foo")
 
 
-	wa = map[revision]struct{}{
-		revision{main: 2}: {},
-		revision{main: 4}: {},
-		revision{main: 5}: {},
-	}
-	ga = index.Compact(5)
-	delete(wa, revision{main: 1})
-	if !reflect.DeepEqual(ga, wa) {
-		t.Errorf("a = %v, want %v", ga, wa)
-	}
-	tests[1] = T{[]byte("foo"), 1, ErrRevisionNotFound, 0}
-	tests[2] = T{[]byte("foo"), 3, ErrRevisionNotFound, 0}
-	verify(t, index, tests)
-
-	wa = map[revision]struct{}{
-		revision{main: 4}: {},
-		revision{main: 5}: {},
-		revision{main: 6}: {},
-	}
-	ga = index.Compact(6)
-	delete(wa, revision{main: 2})
-	if !reflect.DeepEqual(ga, wa) {
-		t.Errorf("a = %v, want %v", ga, wa)
+	tests := []struct {
+		created  revision
+		modified revision
+		ver      int64
+	}{
+		{revision{1, 0}, revision{1, 0}, 1},
+		{revision{1, 0}, revision{1, 1}, 2},
+		{revision{1, 0}, revision{2, 0}, 3},
 	}
 	}
-	tests[7] = T{[]byte("foo1"), 2, ErrRevisionNotFound, 0}
-	tests[8] = T{[]byte("foo1"), 5, ErrRevisionNotFound, 0}
-	verify(t, index, tests)
-}
 
 
-func verify(t *testing.T, index index, tests []T) {
+	// Continuous Restore
+	index := newTreeIndex()
 	for i, tt := range tests {
 	for i, tt := range tests {
-		h, _, _, err := index.Get(tt.key, tt.rev)
-		if err != tt.werr {
-			t.Errorf("#%d: err = %v, want %v", i, err, tt.werr)
+		index.Restore(key, tt.created, tt.modified, tt.ver)
+
+		modified, created, ver, err := index.Get(key, tt.modified.main)
+		if modified != tt.modified {
+			t.Errorf("#%d: modified = %v, want %v", i, modified, tt.modified)
+		}
+		if created != tt.created {
+			t.Errorf("#%d: created = %v, want %v", i, created, tt.created)
 		}
 		}
-		if h.main != tt.wrev {
-			t.Errorf("#%d: rev = %d, want %d", i, h.main, tt.wrev)
+		if ver != tt.ver {
+			t.Errorf("#%d: ver = %d, want %d", i, ver, tt.ver)
+		}
+		if err != nil {
+			t.Errorf("#%d: err = %v, want nil", i, err)
 		}
 		}
 	}
 	}
-}
 
 
-type T struct {
-	key []byte
-	rev int64
-
-	werr error
-	wrev int64
-}
+	// Once Restore
+	for i, tt := range tests {
+		index := newTreeIndex()
+		index.Restore(key, tt.created, tt.modified, tt.ver)
 
 
-func newTestTreeIndex() index {
-	index := newTreeIndex()
-	index.Put([]byte("foo"), revision{main: 1})
-	index.Put([]byte("foo1"), revision{main: 2})
-	index.Put([]byte("foo2"), revision{main: 3})
-	index.Put([]byte("foo2"), revision{main: 4})
-	index.Put([]byte("foo"), revision{main: 5})
-	index.Put([]byte("foo1"), revision{main: 6})
-	return index
+		modified, created, ver, err := index.Get(key, tt.modified.main)
+		if modified != tt.modified {
+			t.Errorf("#%d: modified = %v, want %v", i, modified, tt.modified)
+		}
+		if created != tt.created {
+			t.Errorf("#%d: created = %v, want %v", i, created, tt.created)
+		}
+		if ver != tt.ver {
+			t.Errorf("#%d: ver = %d, want %d", i, ver, tt.ver)
+		}
+		if err != nil {
+			t.Errorf("#%d: err = %v, want nil", i, err)
+		}
+	}
 }
 }