github.com/trustbloc/kms-go@v1.1.2/internal/mock/storage/mock_store.go (about) 1 /* 2 Copyright SecureKey Technologies Inc. All Rights Reserved. 3 SPDX-License-Identifier: Apache-2.0 4 */ 5 6 package storage 7 8 import ( 9 "errors" 10 "fmt" 11 "strings" 12 "sync" 13 14 "github.com/trustbloc/kms-go/spi/storage" 15 ) 16 17 const ( 18 expressionTagNameOnlyLength = 1 19 expressionTagNameAndValueLength = 2 20 ) 21 22 var ( 23 errInvalidQueryExpressionFormat = errors.New("invalid expression format. " + 24 "it must be in the following format: TagName:TagValue") 25 errIteratorExhausted = errors.New("iterator is exhausted") 26 ) 27 28 // MockStoreProvider mock store provider. 29 type MockStoreProvider struct { 30 Store *MockStore 31 Custom storage.Store 32 ErrOpenStoreHandle error 33 ErrSetStoreConfig error 34 ErrClose error 35 ErrCloseStore error 36 FailNamespace string 37 } 38 39 // NewMockStoreProvider new store provider instance. 40 func NewMockStoreProvider() *MockStoreProvider { 41 return &MockStoreProvider{Store: &MockStore{ 42 Store: make(map[string]DBEntry), 43 }} 44 } 45 46 // NewCustomMockStoreProvider new mock store provider instance 47 // from existing mock store. 48 func NewCustomMockStoreProvider(customStore storage.Store) *MockStoreProvider { 49 return &MockStoreProvider{Custom: customStore} 50 } 51 52 // OpenStore opens and returns a store for given name space. 53 func (s *MockStoreProvider) OpenStore(name string) (storage.Store, error) { 54 if name == s.FailNamespace { 55 return nil, fmt.Errorf("failed to open store for name space %s", name) 56 } 57 58 if s.Custom != nil { 59 return s.Custom, s.ErrOpenStoreHandle 60 } 61 62 return s.Store, s.ErrOpenStoreHandle 63 } 64 65 // SetStoreConfig always return a nil error. 66 func (s *MockStoreProvider) SetStoreConfig(name string, config storage.StoreConfiguration) error { 67 return s.ErrSetStoreConfig 68 } 69 70 // GetStoreConfig is not implemented. 71 func (s *MockStoreProvider) GetStoreConfig(name string) (storage.StoreConfiguration, error) { 72 panic("implement me") 73 } 74 75 // GetOpenStores is not implemented. 76 func (s *MockStoreProvider) GetOpenStores() []storage.Store { 77 panic("implement me") 78 } 79 80 // Close closes all stores created under this store provider. 81 func (s *MockStoreProvider) Close() error { 82 return s.ErrClose 83 } 84 85 // CloseStore closes store for given name space. 86 func (s *MockStoreProvider) CloseStore(name string) error { 87 return s.ErrCloseStore 88 } 89 90 // DBEntry is a value plus optional tags that are associated with some key. 91 type DBEntry struct { 92 Value []byte 93 Tags []storage.Tag 94 } 95 96 // MockStore mock store. 97 type MockStore struct { 98 Store map[string]DBEntry 99 lock sync.RWMutex 100 ErrPut error 101 ErrGet error 102 ErrDelete error 103 ErrQuery error 104 ErrNext error 105 ErrValue error 106 ErrKey error 107 ErrBatch error 108 ErrClose error 109 } 110 111 // Put stores the key and the record. 112 func (s *MockStore) Put(k string, v []byte, tags ...storage.Tag) error { 113 if k == "" { 114 return errors.New("key is mandatory") 115 } 116 117 if s.ErrPut != nil { 118 return s.ErrPut 119 } 120 121 s.lock.Lock() 122 s.Store[k] = DBEntry{ 123 Value: v, 124 Tags: tags, 125 } 126 s.lock.Unlock() 127 128 return s.ErrPut 129 } 130 131 // Get fetches the record based on key. 132 func (s *MockStore) Get(k string) ([]byte, error) { 133 if s.ErrGet != nil { 134 return nil, s.ErrGet 135 } 136 137 s.lock.RLock() 138 defer s.lock.RUnlock() 139 140 entry, ok := s.Store[k] 141 if !ok { 142 return nil, storage.ErrDataNotFound 143 } 144 145 return entry.Value, s.ErrGet 146 } 147 148 // GetTags is not implemented. 149 func (s *MockStore) GetTags(key string) ([]storage.Tag, error) { 150 panic("implement me") 151 } 152 153 // GetBulk is not implemented. 154 func (s *MockStore) GetBulk(keys ...string) ([][]byte, error) { 155 panic("implement me") 156 } 157 158 // Query returns all data that satisfies the expression. Expression format: TagName:TagValue. 159 // If TagValue is not provided, then all data associated with the TagName will be returned. 160 // For now, expression can only be a single tag Name + Value pair. 161 func (s *MockStore) Query(expression string, _ ...storage.QueryOption) (storage.Iterator, error) { 162 if s.ErrQuery != nil { 163 return nil, s.ErrQuery 164 } 165 166 if expression == "" { 167 return nil, errInvalidQueryExpressionFormat 168 } 169 170 expressionSplit := strings.Split(expression, ":") 171 switch len(expressionSplit) { 172 case expressionTagNameOnlyLength: 173 expressionTagName := expressionSplit[0] 174 175 s.lock.RLock() 176 defer s.lock.RUnlock() 177 178 keys, dbEntries := s.getMatchingKeysAndDBEntries(expressionTagName, "") 179 180 return &iterator{keys: keys, dbEntries: dbEntries, errNext: s.ErrNext, errValue: s.ErrValue, errKey: s.ErrKey}, nil 181 case expressionTagNameAndValueLength: 182 expressionTagName := expressionSplit[0] 183 expressionTagValue := expressionSplit[1] 184 185 s.lock.RLock() 186 defer s.lock.RUnlock() 187 188 keys, dbEntries := s.getMatchingKeysAndDBEntries(expressionTagName, expressionTagValue) 189 190 return &iterator{keys: keys, dbEntries: dbEntries, errNext: s.ErrNext, errValue: s.ErrValue, errKey: s.ErrKey}, nil 191 default: 192 return nil, errInvalidQueryExpressionFormat 193 } 194 } 195 196 // Delete will delete record with k key. 197 func (s *MockStore) Delete(k string) error { 198 s.lock.Lock() 199 delete(s.Store, k) 200 s.lock.Unlock() 201 202 return s.ErrDelete 203 } 204 205 // Batch stores a batch of operations. 206 func (s *MockStore) Batch(operations []storage.Operation) error { 207 if s.ErrBatch != nil { 208 return s.ErrBatch 209 } 210 211 s.lock.Lock() 212 defer s.lock.Unlock() 213 214 for _, op := range operations { 215 s.Store[op.Key] = DBEntry{ 216 Value: op.Value, 217 Tags: op.Tags, 218 } 219 } 220 221 return nil 222 } 223 224 // Flush is not implemented. 225 func (s *MockStore) Flush() error { 226 panic("implement me") 227 } 228 229 // Close is not implemented. 230 func (s *MockStore) Close() error { 231 return s.ErrClose 232 } 233 234 func (s *MockStore) getMatchingKeysAndDBEntries(tagName, tagValue string) ([]string, []DBEntry) { 235 var matchAnyValue bool 236 if tagValue == "" { 237 matchAnyValue = true 238 } 239 240 var keys []string 241 242 var dbEntries []DBEntry 243 244 for key, dbEntry := range s.Store { 245 for _, tag := range dbEntry.Tags { 246 if tag.Name == tagName && (matchAnyValue || tag.Value == tagValue) { 247 keys = append(keys, key) 248 dbEntries = append(dbEntries, dbEntry) 249 250 break 251 } 252 } 253 } 254 255 return keys, dbEntries 256 } 257 258 type iterator struct { 259 currentIndex int 260 currentKey string 261 currentDBEntry DBEntry 262 keys []string 263 dbEntries []DBEntry 264 errNext error 265 errValue error 266 errKey error 267 } 268 269 func (m *iterator) Next() (bool, error) { 270 if m.errNext != nil { 271 return false, m.errNext 272 } 273 274 if len(m.dbEntries) == m.currentIndex || len(m.dbEntries) == 0 { 275 m.dbEntries = nil 276 return false, nil 277 } 278 279 m.currentKey = m.keys[m.currentIndex] 280 m.currentDBEntry = m.dbEntries[m.currentIndex] 281 m.currentIndex++ 282 283 return true, nil 284 } 285 286 func (m *iterator) Key() (string, error) { 287 if m.errKey != nil { 288 return "", m.errKey 289 } 290 291 if len(m.dbEntries) == 0 { 292 return "", errIteratorExhausted 293 } 294 295 return m.currentKey, nil 296 } 297 298 func (m *iterator) Value() ([]byte, error) { 299 if m.errValue != nil { 300 return nil, m.errValue 301 } 302 303 if len(m.dbEntries) == 0 { 304 return nil, errIteratorExhausted 305 } 306 307 return m.currentDBEntry.Value, nil 308 } 309 310 func (m *iterator) Tags() ([]storage.Tag, error) { 311 if len(m.dbEntries) == 0 { 312 return nil, errIteratorExhausted 313 } 314 315 return m.currentDBEntry.Tags, nil 316 } 317 318 func (m *iterator) TotalItems() (int, error) { 319 return -1, errors.New("not implemented") 320 } 321 322 func (m *iterator) Close() error { 323 return nil 324 }