github.com/evdatsion/aphelion-dpos-bft@v0.32.1/libs/db/common_test.go (about)

     1  package db
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/binary"
     6  	"fmt"
     7  	"io/ioutil"
     8  	"sync"
     9  	"testing"
    10  
    11  	"github.com/stretchr/testify/assert"
    12  	"github.com/stretchr/testify/require"
    13  	cmn "github.com/evdatsion/aphelion-dpos-bft/libs/common"
    14  )
    15  
    16  //----------------------------------------
    17  // Helper functions.
    18  
    19  func checkValue(t *testing.T, db DB, key []byte, valueWanted []byte) {
    20  	valueGot := db.Get(key)
    21  	assert.Equal(t, valueWanted, valueGot)
    22  }
    23  
    24  func checkValid(t *testing.T, itr Iterator, expected bool) {
    25  	valid := itr.Valid()
    26  	require.Equal(t, expected, valid)
    27  }
    28  
    29  func checkNext(t *testing.T, itr Iterator, expected bool) {
    30  	itr.Next()
    31  	valid := itr.Valid()
    32  	require.Equal(t, expected, valid)
    33  }
    34  
    35  func checkNextPanics(t *testing.T, itr Iterator) {
    36  	assert.Panics(t, func() { itr.Next() }, "checkNextPanics expected panic but didn't")
    37  }
    38  
    39  func checkDomain(t *testing.T, itr Iterator, start, end []byte) {
    40  	ds, de := itr.Domain()
    41  	assert.Equal(t, start, ds, "checkDomain domain start incorrect")
    42  	assert.Equal(t, end, de, "checkDomain domain end incorrect")
    43  }
    44  
    45  func checkItem(t *testing.T, itr Iterator, key []byte, value []byte) {
    46  	k, v := itr.Key(), itr.Value()
    47  	assert.Exactly(t, key, k)
    48  	assert.Exactly(t, value, v)
    49  }
    50  
    51  func checkInvalid(t *testing.T, itr Iterator) {
    52  	checkValid(t, itr, false)
    53  	checkKeyPanics(t, itr)
    54  	checkValuePanics(t, itr)
    55  	checkNextPanics(t, itr)
    56  }
    57  
    58  func checkKeyPanics(t *testing.T, itr Iterator) {
    59  	assert.Panics(t, func() { itr.Key() }, "checkKeyPanics expected panic but didn't")
    60  }
    61  
    62  func checkValuePanics(t *testing.T, itr Iterator) {
    63  	assert.Panics(t, func() { itr.Value() }, "checkValuePanics expected panic but didn't")
    64  }
    65  
    66  func newTempDB(t *testing.T, backend DBBackendType) (db DB, dbDir string) {
    67  	dirname, err := ioutil.TempDir("", "db_common_test")
    68  	require.Nil(t, err)
    69  	return NewDB("testdb", backend, dirname), dirname
    70  }
    71  
    72  //----------------------------------------
    73  // mockDB
    74  
    75  // NOTE: not actually goroutine safe.
    76  // If you want something goroutine safe, maybe you just want a MemDB.
    77  type mockDB struct {
    78  	mtx   sync.Mutex
    79  	calls map[string]int
    80  }
    81  
    82  func newMockDB() *mockDB {
    83  	return &mockDB{
    84  		calls: make(map[string]int),
    85  	}
    86  }
    87  
    88  func (mdb *mockDB) Mutex() *sync.Mutex {
    89  	return &(mdb.mtx)
    90  }
    91  
    92  func (mdb *mockDB) Get([]byte) []byte {
    93  	mdb.calls["Get"]++
    94  	return nil
    95  }
    96  
    97  func (mdb *mockDB) Has([]byte) bool {
    98  	mdb.calls["Has"]++
    99  	return false
   100  }
   101  
   102  func (mdb *mockDB) Set([]byte, []byte) {
   103  	mdb.calls["Set"]++
   104  }
   105  
   106  func (mdb *mockDB) SetSync([]byte, []byte) {
   107  	mdb.calls["SetSync"]++
   108  }
   109  
   110  func (mdb *mockDB) SetNoLock([]byte, []byte) {
   111  	mdb.calls["SetNoLock"]++
   112  }
   113  
   114  func (mdb *mockDB) SetNoLockSync([]byte, []byte) {
   115  	mdb.calls["SetNoLockSync"]++
   116  }
   117  
   118  func (mdb *mockDB) Delete([]byte) {
   119  	mdb.calls["Delete"]++
   120  }
   121  
   122  func (mdb *mockDB) DeleteSync([]byte) {
   123  	mdb.calls["DeleteSync"]++
   124  }
   125  
   126  func (mdb *mockDB) DeleteNoLock([]byte) {
   127  	mdb.calls["DeleteNoLock"]++
   128  }
   129  
   130  func (mdb *mockDB) DeleteNoLockSync([]byte) {
   131  	mdb.calls["DeleteNoLockSync"]++
   132  }
   133  
   134  func (mdb *mockDB) Iterator(start, end []byte) Iterator {
   135  	mdb.calls["Iterator"]++
   136  	return &mockIterator{}
   137  }
   138  
   139  func (mdb *mockDB) ReverseIterator(start, end []byte) Iterator {
   140  	mdb.calls["ReverseIterator"]++
   141  	return &mockIterator{}
   142  }
   143  
   144  func (mdb *mockDB) Close() {
   145  	mdb.calls["Close"]++
   146  }
   147  
   148  func (mdb *mockDB) NewBatch() Batch {
   149  	mdb.calls["NewBatch"]++
   150  	return &memBatch{db: mdb}
   151  }
   152  
   153  func (mdb *mockDB) Print() {
   154  	mdb.calls["Print"]++
   155  	fmt.Printf("mockDB{%v}", mdb.Stats())
   156  }
   157  
   158  func (mdb *mockDB) Stats() map[string]string {
   159  	mdb.calls["Stats"]++
   160  
   161  	res := make(map[string]string)
   162  	for key, count := range mdb.calls {
   163  		res[key] = fmt.Sprintf("%d", count)
   164  	}
   165  	return res
   166  }
   167  
   168  //----------------------------------------
   169  // mockIterator
   170  
   171  type mockIterator struct{}
   172  
   173  func (mockIterator) Domain() (start []byte, end []byte) {
   174  	return nil, nil
   175  }
   176  
   177  func (mockIterator) Valid() bool {
   178  	return false
   179  }
   180  
   181  func (mockIterator) Next() {
   182  }
   183  
   184  func (mockIterator) Key() []byte {
   185  	return nil
   186  }
   187  
   188  func (mockIterator) Value() []byte {
   189  	return nil
   190  }
   191  
   192  func (mockIterator) Close() {
   193  }
   194  
   195  func benchmarkRandomReadsWrites(b *testing.B, db DB) {
   196  	b.StopTimer()
   197  
   198  	// create dummy data
   199  	const numItems = int64(1000000)
   200  	internal := map[int64]int64{}
   201  	for i := 0; i < int(numItems); i++ {
   202  		internal[int64(i)] = int64(0)
   203  	}
   204  
   205  	// fmt.Println("ok, starting")
   206  	b.StartTimer()
   207  
   208  	for i := 0; i < b.N; i++ {
   209  		// Write something
   210  		{
   211  			idx := int64(cmn.RandInt()) % numItems
   212  			internal[idx]++
   213  			val := internal[idx]
   214  			idxBytes := int642Bytes(int64(idx))
   215  			valBytes := int642Bytes(int64(val))
   216  			//fmt.Printf("Set %X -> %X\n", idxBytes, valBytes)
   217  			db.Set(idxBytes, valBytes)
   218  		}
   219  
   220  		// Read something
   221  		{
   222  			idx := int64(cmn.RandInt()) % numItems
   223  			valExp := internal[idx]
   224  			idxBytes := int642Bytes(int64(idx))
   225  			valBytes := db.Get(idxBytes)
   226  			//fmt.Printf("Get %X -> %X\n", idxBytes, valBytes)
   227  			if valExp == 0 {
   228  				if !bytes.Equal(valBytes, nil) {
   229  					b.Errorf("Expected %v for %v, got %X", nil, idx, valBytes)
   230  					break
   231  				}
   232  			} else {
   233  				if len(valBytes) != 8 {
   234  					b.Errorf("Expected length 8 for %v, got %X", idx, valBytes)
   235  					break
   236  				}
   237  				valGot := bytes2Int64(valBytes)
   238  				if valExp != valGot {
   239  					b.Errorf("Expected %v for %v, got %v", valExp, idx, valGot)
   240  					break
   241  				}
   242  			}
   243  		}
   244  
   245  	}
   246  }
   247  
   248  func int642Bytes(i int64) []byte {
   249  	buf := make([]byte, 8)
   250  	binary.BigEndian.PutUint64(buf, uint64(i))
   251  	return buf
   252  }
   253  
   254  func bytes2Int64(buf []byte) int64 {
   255  	return int64(binary.BigEndian.Uint64(buf))
   256  }