Skip to content

Commit fbc0466

Browse files
committed
test for TxnDatastore keytransform wrapper
1 parent 8083e8f commit fbc0466

File tree

2 files changed

+202
-32
lines changed

2 files changed

+202
-32
lines changed

keytransform/txndatastore_test.go

Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
package keytransform_test
2+
3+
import (
4+
"bytes"
5+
"context"
6+
"fmt"
7+
"sort"
8+
9+
. "gopkg.in/check.v1"
10+
11+
ds "github.com/ipfs/go-datastore"
12+
kt "github.com/ipfs/go-datastore/keytransform"
13+
dsq "github.com/ipfs/go-datastore/query"
14+
dstest "github.com/ipfs/go-datastore/test"
15+
)
16+
17+
var _ = Suite(&DSSuite{})
18+
19+
func (ks *DSSuite) TestWrapTxnDatastoreBasic(c *C) {
20+
ctx := context.Background()
21+
ms := ds.NewMapDatastore()
22+
mpds := dstest.NewTestTxnDatastore(ms, true)
23+
24+
kt.WrapTxnDatastore(mpds, pair)
25+
ktds := kt.WrapTxnDatastore(mpds, pair)
26+
ktdsTx, err := ktds.NewTransaction(ctx, false)
27+
c.Check(err, Equals, nil)
28+
29+
keys := strsToKeys([]string{
30+
"foo",
31+
"foo/bar",
32+
"foo/bar/baz",
33+
"foo/barb",
34+
"foo/bar/bazb",
35+
"foo/bar/baz/barb",
36+
})
37+
38+
for _, k := range keys {
39+
err := ktdsTx.Put(ctx, k, []byte(k.String()))
40+
c.Check(err, Equals, nil)
41+
}
42+
43+
for _, k := range keys {
44+
// underlying mapstore can only see committed results
45+
_, err := ms.Get(ctx, k)
46+
c.Check(err, Equals, ds.ErrNotFound)
47+
48+
_, err = ms.Get(ctx, ds.NewKey("abc").Child(k))
49+
c.Check(err, Equals, ds.ErrNotFound)
50+
51+
v1, err := ktdsTx.Get(ctx, k)
52+
c.Check(err, Equals, nil)
53+
c.Check(bytes.Equal(v1, []byte(k.String())), Equals, true)
54+
55+
// underlying TxnDatastore can only see committed results
56+
_, err = mpds.Get(ctx, ds.NewKey("abc").Child(k))
57+
c.Check(err, Equals, ds.ErrNotFound)
58+
}
59+
60+
run := func(d ds.Read, q dsq.Query) []ds.Key {
61+
r, err := d.Query(ctx, q)
62+
c.Check(err, Equals, nil)
63+
64+
e, err := r.Rest()
65+
c.Check(err, Equals, nil)
66+
67+
return ds.EntryKeys(e)
68+
}
69+
70+
listA := run(mpds, dsq.Query{})
71+
listB := run(ktdsTx, dsq.Query{})
72+
if len(listA) == len(listB) {
73+
c.Errorf("TxnDatastore and WrappedTxDatastore should not have equal Query results pre-commit")
74+
}
75+
76+
if err := ktds.Check(ctx); err != dstest.ErrTest {
77+
c.Errorf("Unexpected Check() error: %s", err)
78+
}
79+
80+
if err := ktds.CollectGarbage(ctx); err != dstest.ErrTest {
81+
c.Errorf("Unexpected CollectGarbage() error: %s", err)
82+
}
83+
84+
if err := ktds.Scrub(ctx); err != dstest.ErrTest {
85+
c.Errorf("Unexpected Scrub() error: %s", err)
86+
}
87+
88+
// Commit wrapped tx and compare
89+
err = ktdsTx.Commit(ctx)
90+
c.Check(err, Equals, nil)
91+
92+
for _, k := range keys {
93+
// results should be committed to the underlying mapstore
94+
_, err = ms.Get(ctx, k)
95+
c.Check(err, Equals, ds.ErrNotFound)
96+
97+
v0, err := ms.Get(ctx, ds.NewKey("abc").Child(k))
98+
c.Check(err, Equals, nil)
99+
c.Check(bytes.Equal(v0, []byte(k.String())), Equals, true)
100+
101+
v1, err := ktdsTx.Get(ctx, k)
102+
c.Check(err, Equals, nil)
103+
c.Check(bytes.Equal(v1, []byte(k.String())), Equals, true)
104+
105+
// results should be committed to the wrapped TxnDatastore
106+
v2, err := mpds.Get(ctx, ds.NewKey("abc").Child(k))
107+
c.Check(err, Equals, nil)
108+
c.Check(bytes.Equal(v2, []byte(k.String())), Equals, true)
109+
}
110+
111+
listA = run(mpds, dsq.Query{})
112+
listB = run(ktdsTx, dsq.Query{})
113+
listC := run(ms, dsq.Query{})
114+
c.Check(len(listA), Equals, len(listB))
115+
c.Check(len(listA), Equals, len(listC))
116+
117+
// sort them cause yeah.
118+
sort.Sort(ds.KeySlice(listA))
119+
sort.Sort(ds.KeySlice(listB))
120+
sort.Sort(ds.KeySlice(listC))
121+
122+
for i, kA := range listA {
123+
kB := listB[i]
124+
kC := listC[i]
125+
c.Check(pair.Invert(kA), Equals, kB)
126+
c.Check(kA, Equals, pair.Convert(kB))
127+
c.Check(kC, Equals, kA)
128+
}
129+
130+
c.Log("listA: ", listA)
131+
c.Log("listB: ", listB)
132+
c.Log("listC: ", listC)
133+
134+
// Create a new tx and add some uncommitted values to
135+
ktdsTx, err = ktds.NewTransaction(ctx, false)
136+
c.Check(err, Equals, nil)
137+
138+
unCommittedKeys := strsToKeys([]string{
139+
"foo",
140+
"foo/bar",
141+
"foo/bar/baz",
142+
})
143+
unCommittedKeysMap := make(map[ds.Key][]byte)
144+
for i, k := range unCommittedKeys {
145+
unCommittedKeysMap[k] = []byte(fmt.Sprintf("overwrite value %d", i))
146+
}
147+
for k, val := range unCommittedKeysMap {
148+
err := ktdsTx.Put(ctx, k, val)
149+
c.Check(err, Equals, nil)
150+
}
151+
152+
for _, k := range keys {
153+
// underlying mapstore will have only the committed results
154+
_, err = ms.Get(ctx, k)
155+
c.Check(err, Equals, ds.ErrNotFound)
156+
157+
v0, err := ms.Get(ctx, ds.NewKey("abc").Child(k))
158+
c.Check(err, Equals, nil)
159+
c.Check(bytes.Equal(v0, []byte(k.String())), Equals, true)
160+
161+
// tx will return a mixture of the pending results and committed results
162+
v1, err := ktdsTx.Get(ctx, k)
163+
c.Check(err, Equals, nil)
164+
if val, ok := unCommittedKeysMap[k]; ok {
165+
c.Check(bytes.Equal(v1, val), Equals, true)
166+
} else {
167+
c.Check(bytes.Equal(v1, []byte(k.String())), Equals, true)
168+
}
169+
170+
// underlying TxnDatastore will have only the committed results
171+
v2, err := mpds.Get(ctx, ds.NewKey("abc").Child(k))
172+
c.Check(err, Equals, nil)
173+
c.Check(bytes.Equal(v2, []byte(k.String())), Equals, true)
174+
}
175+
}

test/test_util.go

Lines changed: 27 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -197,34 +197,52 @@ type testTxnDatastore struct {
197197
*dstore.MapDatastore
198198
}
199199

200-
func NewTestTxnDatastore(testErrors bool) *testTxnDatastore {
200+
func NewTestTxnDatastore(ms *dstore.MapDatastore, testErrors bool) *testTxnDatastore {
201+
if ms == nil {
202+
ms = dstore.NewMapDatastore()
203+
}
201204
return &testTxnDatastore{
202205
testErrors: testErrors,
203-
MapDatastore: dstore.NewMapDatastore(),
206+
MapDatastore: ms,
204207
}
205208
}
206209

207-
func (t *testTxnDatastore) NewTransaction(ctx context.Context, readOnly bool) (dstore.Txn, error) {
210+
func (t *testTxnDatastore) Check(_ context.Context) error {
208211
if t.testErrors {
209-
return nil, ErrTest
212+
return ErrTest
210213
}
214+
return nil
215+
}
216+
217+
func (t *testTxnDatastore) Scrub(_ context.Context) error {
218+
if t.testErrors {
219+
return ErrTest
220+
}
221+
return nil
222+
}
223+
224+
func (t *testTxnDatastore) CollectGarbage(_ context.Context) error {
225+
if t.testErrors {
226+
return ErrTest
227+
}
228+
return nil
229+
}
230+
231+
func (t *testTxnDatastore) NewTransaction(ctx context.Context, readOnly bool) (dstore.Txn, error) {
211232
return newTestTx(t.testErrors, t.MapDatastore), nil
212233
}
213234

214235
var _ dstore.Txn = (*testTxn)(nil)
215236

216237
type testTxn struct {
217-
testTxErrors bool
218-
219238
dirty map[dstore.Key][]byte
220239
committed *dstore.MapDatastore
221240
}
222241

223242
func newTestTx(testTxErrors bool, committed *dstore.MapDatastore) *testTxn {
224243
return &testTxn{
225-
testTxErrors: testTxErrors,
226-
dirty: make(map[dstore.Key][]byte),
227-
committed: committed,
244+
dirty: make(map[dstore.Key][]byte),
245+
committed: committed,
228246
}
229247
}
230248

@@ -237,19 +255,13 @@ func newTestTx(testTxErrors bool, committed *dstore.MapDatastore) *testTxn {
237255
// whereas Query considers both the dirty transaction and the underlying committed datastore.
238256

239257
func (t *testTxn) Get(ctx context.Context, key dstore.Key) ([]byte, error) {
240-
if t.testTxErrors {
241-
return nil, ErrTest
242-
}
243258
if val, ok := t.dirty[key]; ok {
244259
return val, nil
245260
}
246261
return t.committed.Get(ctx, key)
247262
}
248263

249264
func (t *testTxn) Has(ctx context.Context, key dstore.Key) (bool, error) {
250-
if t.testTxErrors {
251-
return false, ErrTest
252-
}
253265
if _, ok := t.dirty[key]; ok {
254266
return true, nil
255267
}
@@ -258,9 +270,6 @@ func (t *testTxn) Has(ctx context.Context, key dstore.Key) (bool, error) {
258270
}
259271

260272
func (t *testTxn) GetSize(ctx context.Context, key dstore.Key) (int, error) {
261-
if t.testTxErrors {
262-
return 0, ErrTest
263-
}
264273
if val, ok := t.dirty[key]; ok {
265274
return len(val), nil
266275
}
@@ -269,10 +278,6 @@ func (t *testTxn) GetSize(ctx context.Context, key dstore.Key) (int, error) {
269278
}
270279

271280
func (t *testTxn) Query(ctx context.Context, q dsq.Query) (dsq.Results, error) {
272-
if t.testTxErrors {
273-
return nil, ErrTest
274-
}
275-
276281
// not entirely sure if Query is *supposed* to access both uncommitted and committed data, but if so I think this
277282
// is the simplest way of handling it and the overhead should be fine for testing purposes
278283
transientStore := dstore.NewMapDatastore()
@@ -320,28 +325,18 @@ func (t *testTxn) Query(ctx context.Context, q dsq.Query) (dsq.Results, error) {
320325
}
321326

322327
func (t *testTxn) Put(ctx context.Context, key dstore.Key, value []byte) error {
323-
if t.testTxErrors {
324-
return ErrTest
325-
}
326328
t.dirty[key] = value
327329
return nil
328330
}
329331

330332
func (t *testTxn) Delete(ctx context.Context, key dstore.Key) error {
331-
if t.testTxErrors {
332-
return ErrTest
333-
}
334333
if _, ok := t.dirty[key]; ok {
335334
delete(t.dirty, key)
336335
}
337336
return t.committed.Delete(ctx, key)
338337
}
339338

340339
func (t *testTxn) Commit(ctx context.Context) error {
341-
if t.testTxErrors {
342-
return ErrTest
343-
}
344-
345340
batch, err := t.committed.Batch(ctx)
346341
if err != nil {
347342
return err

0 commit comments

Comments
 (0)