1
2
3
4
5
6
7 package testutil
8
9 import (
10 "fmt"
11 "math/rand"
12
13 . "github.com/onsi/gomega"
14
15 "github.com/syndtr/goleveldb/leveldb/errors"
16 "github.com/syndtr/goleveldb/leveldb/iterator"
17 "github.com/syndtr/goleveldb/leveldb/util"
18 )
19
20 type DB interface{}
21
22 type Put interface {
23 TestPut(key []byte, value []byte) error
24 }
25
26 type Delete interface {
27 TestDelete(key []byte) error
28 }
29
30 type Find interface {
31 TestFind(key []byte) (rkey, rvalue []byte, err error)
32 }
33
34 type Get interface {
35 TestGet(key []byte) (value []byte, err error)
36 }
37
38 type Has interface {
39 TestHas(key []byte) (ret bool, err error)
40 }
41
42 type NewIterator interface {
43 TestNewIterator(slice *util.Range) iterator.Iterator
44 }
45
46 type DBAct int
47
48 func (a DBAct) String() string {
49 switch a {
50 case DBNone:
51 return "none"
52 case DBPut:
53 return "put"
54 case DBOverwrite:
55 return "overwrite"
56 case DBDelete:
57 return "delete"
58 case DBDeleteNA:
59 return "delete_na"
60 }
61 return "unknown"
62 }
63
64 const (
65 DBNone DBAct = iota
66 DBPut
67 DBOverwrite
68 DBDelete
69 DBDeleteNA
70 )
71
72 type DBTesting struct {
73 Rand *rand.Rand
74 DB interface {
75 Get
76 Put
77 Delete
78 }
79 PostFn func(t *DBTesting)
80 Deleted, Present KeyValue
81 Act, LastAct DBAct
82 ActKey, LastActKey []byte
83 }
84
85 func (t *DBTesting) post() {
86 if t.PostFn != nil {
87 t.PostFn(t)
88 }
89 }
90
91 func (t *DBTesting) setAct(act DBAct, key []byte) {
92 t.LastAct, t.Act = t.Act, act
93 t.LastActKey, t.ActKey = t.ActKey, key
94 }
95
96 func (t *DBTesting) text() string {
97 return fmt.Sprintf("last action was <%v> %q, <%v> %q", t.LastAct, t.LastActKey, t.Act, t.ActKey)
98 }
99
100 func (t *DBTesting) Text() string {
101 return "DBTesting " + t.text()
102 }
103
104 func (t *DBTesting) TestPresentKV(key, value []byte) {
105 rvalue, err := t.DB.TestGet(key)
106 Expect(err).ShouldNot(HaveOccurred(), "Get on key %q, %s", key, t.text())
107 Expect(rvalue).Should(Equal(value), "Value for key %q, %s", key, t.text())
108 }
109
110 func (t *DBTesting) TestAllPresent() {
111 t.Present.IterateShuffled(t.Rand, func(i int, key, value []byte) {
112 t.TestPresentKV(key, value)
113 })
114 }
115
116 func (t *DBTesting) TestDeletedKey(key []byte) {
117 _, err := t.DB.TestGet(key)
118 Expect(err).Should(Equal(errors.ErrNotFound), "Get on deleted key %q, %s", key, t.text())
119 }
120
121 func (t *DBTesting) TestAllDeleted() {
122 t.Deleted.IterateShuffled(t.Rand, func(i int, key, value []byte) {
123 t.TestDeletedKey(key)
124 })
125 }
126
127 func (t *DBTesting) TestAll() {
128 dn := t.Deleted.Len()
129 pn := t.Present.Len()
130 ShuffledIndex(t.Rand, dn+pn, 1, func(i int) {
131 if i >= dn {
132 key, value := t.Present.Index(i - dn)
133 t.TestPresentKV(key, value)
134 } else {
135 t.TestDeletedKey(t.Deleted.KeyAt(i))
136 }
137 })
138 }
139
140 func (t *DBTesting) Put(key, value []byte) {
141 if new := t.Present.PutU(key, value); new {
142 t.setAct(DBPut, key)
143 } else {
144 t.setAct(DBOverwrite, key)
145 }
146 t.Deleted.Delete(key)
147 err := t.DB.TestPut(key, value)
148 Expect(err).ShouldNot(HaveOccurred(), t.Text())
149 t.TestPresentKV(key, value)
150 t.post()
151 }
152
153 func (t *DBTesting) PutRandom() bool {
154 if t.Deleted.Len() > 0 {
155 i := t.Rand.Intn(t.Deleted.Len())
156 key, value := t.Deleted.Index(i)
157 t.Put(key, value)
158 return true
159 }
160 return false
161 }
162
163 func (t *DBTesting) Delete(key []byte) {
164 if exist, value := t.Present.Delete(key); exist {
165 t.setAct(DBDelete, key)
166 t.Deleted.PutU(key, value)
167 } else {
168 t.setAct(DBDeleteNA, key)
169 }
170 err := t.DB.TestDelete(key)
171 Expect(err).ShouldNot(HaveOccurred(), t.Text())
172 t.TestDeletedKey(key)
173 t.post()
174 }
175
176 func (t *DBTesting) DeleteRandom() bool {
177 if t.Present.Len() > 0 {
178 i := t.Rand.Intn(t.Present.Len())
179 t.Delete(t.Present.KeyAt(i))
180 return true
181 }
182 return false
183 }
184
185 func (t *DBTesting) RandomAct(round int) {
186 for i := 0; i < round; i++ {
187 if t.Rand.Int()%2 == 0 {
188 t.PutRandom()
189 } else {
190 t.DeleteRandom()
191 }
192 }
193 }
194
195 func DoDBTesting(t *DBTesting) {
196 if t.Rand == nil {
197 t.Rand = NewRand()
198 }
199
200 t.DeleteRandom()
201 t.PutRandom()
202 t.DeleteRandom()
203 t.DeleteRandom()
204 for i := t.Deleted.Len() / 2; i >= 0; i-- {
205 t.PutRandom()
206 }
207 t.RandomAct((t.Deleted.Len() + t.Present.Len()) * 10)
208
209
210 if db, ok := t.DB.(NewIterator); ok {
211 iter := db.TestNewIterator(nil)
212 Expect(iter.Error()).NotTo(HaveOccurred())
213
214 it := IteratorTesting{
215 KeyValue: t.Present,
216 Iter: iter,
217 }
218
219 DoIteratorTesting(&it)
220 iter.Release()
221 }
222 }
223
View as plain text