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  }