github.com/ethersphere/bee/v2@v2.2.0/pkg/statestore/test/store.go (about) 1 // Copyright 2020 The Swarm Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package test 6 7 import ( 8 "fmt" 9 "os" 10 "strings" 11 "testing" 12 13 "github.com/ethersphere/bee/v2/pkg/storage" 14 ) 15 16 const ( 17 key1 = "key1" // stores the serialized type 18 key2 = "key2" // stores a json array 19 ) 20 21 var ( 22 value1 = &Serializing{value: "value1"} 23 value2 = []string{"a", "b", "c"} 24 ) 25 26 type Serializing struct { 27 value string 28 marshalCalled bool 29 unmarshalCalled bool 30 } 31 32 func (st *Serializing) MarshalBinary() (data []byte, err error) { 33 d := []byte(st.value) 34 st.marshalCalled = true 35 36 return d, nil 37 } 38 39 func (st *Serializing) UnmarshalBinary(data []byte) (err error) { 40 st.value = string(data) 41 st.unmarshalCalled = true 42 return nil 43 } 44 45 // RunPersist is a specific test case for the persistent state store. 46 // It tests that values persist across sessions. 47 func RunPersist(t *testing.T, f func(t *testing.T, dir string) storage.StateStorer) { 48 t.Helper() 49 dir, err := os.MkdirTemp("", "statestore_test") 50 if err != nil { 51 t.Fatal(err) 52 } 53 defer os.RemoveAll(dir) 54 55 store := f(t, dir) 56 57 // insert some values 58 insert(t, store, "some_prefix", 1000) 59 60 // test that the iterator works 61 testStoreIterator(t, store, "some_prefix", 1000) 62 63 // close the store 64 if err := store.Close(); err != nil { 65 t.Fatal(err) 66 } 67 68 // bootstrap with the same old dir 69 persistedStore := f(t, dir) 70 defer persistedStore.Close() 71 72 // test that the iterator works 73 testStoreIterator(t, persistedStore, "some_prefix", 1000) 74 75 // insert some more random entries 76 insert(t, persistedStore, "some_other_prefix", 1000) 77 78 // check again 79 testStoreIterator(t, persistedStore, "some_other_prefix", 1000) 80 } 81 82 func Run(t *testing.T, f func(t *testing.T) storage.StateStorer) { 83 t.Helper() 84 85 t.Run("test_put_get", func(t *testing.T) { testPutGet(t, f) }) 86 t.Run("test_delete", func(t *testing.T) { testDelete(t, f) }) 87 t.Run("test_iterator", func(t *testing.T) { testIterator(t, f) }) 88 } 89 90 func testDelete(t *testing.T, f func(t *testing.T) storage.StateStorer) { 91 t.Helper() 92 93 // create a store 94 store := f(t) 95 96 // insert some values 97 insertValues(t, store, key1, key2, value1, value2) 98 99 // check that the persisted values match 100 testPersistedValues(t, store, key1, key2, value1, value2) 101 102 err := store.Delete(key1) 103 if err != nil { 104 t.Fatal(err) 105 } 106 err = store.Delete(key2) 107 if err != nil { 108 t.Fatal(err) 109 } 110 111 // check that the store is empty 112 testEmpty(t, store) 113 } 114 115 func testPutGet(t *testing.T, f func(t *testing.T) storage.StateStorer) { 116 t.Helper() 117 118 // create a store 119 store := f(t) 120 121 // insert some values 122 insertValues(t, store, key1, key2, value1, value2) 123 124 // check that the persisted values match 125 testPersistedValues(t, store, key1, key2, value1, value2) 126 } 127 128 func testIterator(t *testing.T, f func(t *testing.T) storage.StateStorer) { 129 t.Helper() 130 131 // create a store 132 store := f(t) 133 134 // insert some values 135 insert(t, store, "some_prefix", 1000) 136 137 // test that the iterator works 138 testStoreIterator(t, store, "some_prefix", 1000) 139 testStoreIterator(t, store, "no_prefix", 0) 140 } 141 142 func insertValues(t *testing.T, store storage.StateStorer, key1, key2 string, value1 *Serializing, value2 []string) { 143 t.Helper() 144 err := store.Put(key1, value1) 145 if err != nil { 146 t.Fatal(err) 147 } 148 149 if !value1.marshalCalled { 150 t.Fatal("binaryMarshaller not called on serialized type") 151 } 152 153 err = store.Put(key2, value2) 154 if err != nil { 155 t.Fatal(err) 156 } 157 } 158 159 func insert(t *testing.T, store storage.StateStorer, prefix string, count int) { 160 t.Helper() 161 162 for i := 0; i < count; i++ { 163 k := prefix + fmt.Sprint(i) 164 165 err := store.Put(k, i) 166 if err != nil { 167 t.Fatal(err) 168 } 169 } 170 } 171 172 func testPersistedValues(t *testing.T, store storage.StateStorer, key1, key2 string, value1 *Serializing, value2 []string) { 173 t.Helper() 174 175 v := &Serializing{} 176 err := store.Get(key1, v) 177 if err != nil { 178 t.Fatal(err) 179 } 180 181 if !v.unmarshalCalled { 182 t.Fatal("unmarshaler not called") 183 } 184 185 if v.value != value1.value { 186 t.Fatalf("expected persisted to be %s but got %s", value1.value, v.value) 187 } 188 189 s := []string{} 190 err = store.Get(key2, &s) 191 if err != nil { 192 t.Fatal(err) 193 } 194 195 for i, ss := range value2 { 196 if s[i] != ss { 197 t.Fatalf("deserialized data mismatch. expected %s but got %s", ss, s[i]) 198 } 199 } 200 } 201 202 func testStoreIterator(t *testing.T, store storage.StateStorer, prefix string, size int) { 203 t.Helper() 204 205 matching := 0 206 entriesIterFunction := func(key []byte, value []byte) (stop bool, err error) { 207 k := string(key) 208 if !strings.HasPrefix(k, prefix) { 209 return true, fmt.Errorf("iterator called callback with wrong key prefix. key: %s expected prefix: %s", k, prefix) 210 } 211 matching++ 212 return false, nil 213 } 214 215 err := store.Iterate(prefix, entriesIterFunction) 216 if err != nil { 217 t.Fatal(err) 218 } 219 220 if matching != size { 221 t.Fatalf("entry number mismatch. want %d got %d", size, matching) 222 } 223 } 224 225 func testEmpty(t *testing.T, store storage.StateStorer) { 226 t.Helper() 227 228 testStoreIterator(t, store, "", 0) 229 }