Skip to content
File

Blob: kv/memory/kv_test.go

go182 lines
1package memory
2 
3import (
4 "context"
5 "crypto/rand"
6 "testing"
7 "time"
8 
9 "go.miragespace.co/specter/spec/chord"
10 "go.miragespace.co/specter/spec/protocol"
11 
12 "github.com/stretchr/testify/require"
13)
14 
15func TestMissingReadsDoNotStore(t *testing.T) {
16 for _, name := range []string{"empty", "hash collision"} {
17 t.Run(name, func(t *testing.T) {
18 as := require.New(t)
19 ctx := context.Background()
20 kv := WithHashFn(func([]byte) uint64 { return 0 })
21 if name == "hash collision" {
22 as.NoError(kv.Put(ctx, []byte("existing"), []byte("value")))
23 }
24 buckets := kv.s.Len()
25 key := []byte("missing")
26 
27 value, err := kv.Get(ctx, key)
28 as.NoError(err)
29 as.Nil(value)
30 children, err := kv.PrefixList(ctx, key)
31 as.NoError(err)
32 as.Equal([][]byte{}, children)
33 contains, err := kv.PrefixContains(ctx, key, []byte("child"))
34 as.NoError(err)
35 as.False(contains)
36 exported, err := kv.Export(ctx, [][]byte{key, key})
37 as.NoError(err)
38 as.Equal([]*protocol.KVTransfer{
39 {PrefixChildren: [][]byte{}},
40 {PrefixChildren: [][]byte{}},
41 }, exported)
42 
43 as.Equal(buckets, kv.s.Len())
44 if bucket, ok := kv.s.Load(0); ok {
45 as.Equal(1, bucket.Len())
46 value, err := kv.Get(ctx, []byte("existing"))
47 as.NoError(err)
48 as.Equal([]byte("value"), value)
49 }
50 })
51 }
52}
53 
54func TestAllKeys(t *testing.T) {
55 as := require.New(t)
56 
57 kv := WithHashFn(chord.Hash)
58 
59 key := make([]byte, 64)
60 value := make([]byte, 8)
61 
62 num := 10000
63 for range num {
64 rand.Read(key)
65 rand.Read(value)
66 kv.Put(context.Background(), key, value)
67 }
68 
69 keys, err := kv.RangeKeys(context.Background(), 0, 0)
70 as.NoError(err)
71 as.Len(keys, num)
72}
73 
74func TestOrderedKeys(t *testing.T) {
75 as := require.New(t)
76 
77 kv := WithHashFn(chord.Hash)
78 
79 key := make([]byte, 64)
80 value := make([]byte, 8)
81 
82 num := 10000
83 for range num {
84 rand.Read(key)
85 rand.Read(value)
86 kv.Put(context.Background(), key, value)
87 }
88 
89 keys, err := kv.RangeKeys(context.Background(), 0, 0)
90 as.NoError(err)
91 
92 var prev uint64 = 0
93 for _, key := range keys {
94 id := chord.Hash(key)
95 as.LessOrEqual(prev, id)
96 prev = id
97 }
98}
99 
100func TestLocalOperations(t *testing.T) {
101 as := require.New(t)
102 
103 kv := WithHashFn(chord.Hash)
104 
105 num := 32
106 length := 8
107 keys := make([][]byte, num)
108 values := make([]*protocol.KVTransfer, num)
109 
110 for i := range keys {
111 keys[i] = make([]byte, length)
112 values[i] = &protocol.KVTransfer{
113 SimpleValue: make([]byte, length),
114 PrefixChildren: make([][]byte, 0),
115 }
116 rand.Read(keys[i])
117 rand.Read(values[i].SimpleValue)
118 }
119 
120 as.Nil(kv.Import(context.Background(), keys, values))
121 
122 ret, err := kv.Export(context.Background(), keys)
123 as.NoError(err)
124 as.EqualValues(values, ret)
125 
126 err = kv.RemoveKeys(context.Background(), keys)
127 as.NoError(err)
128 
129 ret, err = kv.Export(context.Background(), keys)
130 as.NoError(err)
131 as.NotEqualValues(values, ret)
132}
133 
134func TestComplexImportExport(t *testing.T) {
135 as := require.New(t)
136 
137 kv := WithHashFn(chord.Hash)
138 
139 key := make([]byte, 8)
140 rand.Read(key)
141 
142 plainValue := make([]byte, 16)
143 rand.Read(plainValue)
144 child := make([]byte, 32)
145 rand.Read(child)
146 
147 as.NoError(kv.Put(context.Background(), key, plainValue))
148 as.NoError(kv.PrefixAppend(context.Background(), key, child))
149 tk, err := kv.Acquire(context.Background(), key, time.Second)
150 as.NoError(err)
151 
152 val, err := kv.Get(context.Background(), key)
153 as.NoError(err)
154 as.EqualValues(plainValue, val)
155 
156 vals, err := kv.PrefixList(context.Background(), key)
157 as.NoError(err)
158 as.Len(vals, 1)
159 as.EqualValues(child, vals[0])
160 
161 keys, err := kv.RangeKeys(context.Background(), 0, 0)
162 as.NoError(err)
163 exp, err := kv.Export(context.Background(), keys)
164 as.NoError(err)
165 
166 kv2 := WithHashFn(chord.Hash)
167 as.NoError(kv2.Import(context.Background(), keys, exp))
168 
169 val, err = kv2.Get(context.Background(), key)
170 as.NoError(err)
171 as.EqualValues(plainValue, val)
172 
173 vals, err = kv2.PrefixList(context.Background(), key)
174 as.NoError(err)
175 as.Len(vals, 1)
176 as.EqualValues(child, vals[0])
177 
178 tk2, err := kv2.Renew(context.Background(), key, time.Second, tk)
179 as.NoError(err)
180 as.NoError(kv2.Release(context.Background(), key, tk2))
181}