github.com/koko1123/flow-go-1@v0.29.6/storage/badger/operation/common_test.go (about)

     1  // (c) 2019 Dapper Labs - ALL RIGHTS RESERVED
     2  
     3  package operation
     4  
     5  import (
     6  	"bytes"
     7  	"fmt"
     8  	"math/rand"
     9  	"reflect"
    10  	"testing"
    11  	"time"
    12  
    13  	"github.com/dgraph-io/badger/v3"
    14  	"github.com/stretchr/testify/assert"
    15  	"github.com/stretchr/testify/require"
    16  	"github.com/vmihailenco/msgpack/v4"
    17  
    18  	"github.com/koko1123/flow-go-1/model/flow"
    19  	"github.com/koko1123/flow-go-1/storage"
    20  	"github.com/koko1123/flow-go-1/utils/unittest"
    21  )
    22  
    23  func init() {
    24  	rand.Seed(time.Now().UnixNano())
    25  }
    26  
    27  type Entity struct {
    28  	ID uint64
    29  }
    30  
    31  type UnencodeableEntity Entity
    32  
    33  var errCantEncode = fmt.Errorf("encoding not supported")
    34  var errCantDecode = fmt.Errorf("decoding not supported")
    35  
    36  func (a UnencodeableEntity) MarshalJSON() ([]byte, error) {
    37  	return nil, errCantEncode
    38  }
    39  
    40  func (a *UnencodeableEntity) UnmarshalJSON(b []byte) error {
    41  	return errCantDecode
    42  }
    43  
    44  func (a UnencodeableEntity) MarshalMsgpack() ([]byte, error) {
    45  	return nil, errCantEncode
    46  }
    47  
    48  func (a UnencodeableEntity) UnmarshalMsgpack(b []byte) error {
    49  	return errCantDecode
    50  }
    51  
    52  func TestInsertValid(t *testing.T) {
    53  	unittest.RunWithBadgerDB(t, func(db *badger.DB) {
    54  		e := Entity{ID: 1337}
    55  		key := []byte{0x01, 0x02, 0x03}
    56  		val, _ := msgpack.Marshal(e)
    57  
    58  		err := db.Update(insert(key, e))
    59  		require.NoError(t, err)
    60  
    61  		var act []byte
    62  		_ = db.View(func(tx *badger.Txn) error {
    63  			item, err := tx.Get(key)
    64  			require.NoError(t, err)
    65  			act, err = item.ValueCopy(nil)
    66  			require.NoError(t, err)
    67  			return nil
    68  		})
    69  
    70  		assert.Equal(t, val, act)
    71  	})
    72  }
    73  
    74  func TestInsertDuplicate(t *testing.T) {
    75  	unittest.RunWithBadgerDB(t, func(db *badger.DB) {
    76  		e := Entity{ID: 1337}
    77  		key := []byte{0x01, 0x02, 0x03}
    78  		val, _ := msgpack.Marshal(e)
    79  
    80  		// persist first time
    81  		err := db.Update(insert(key, e))
    82  		require.NoError(t, err)
    83  
    84  		e2 := Entity{ID: 1338}
    85  
    86  		// persist again
    87  		err = db.Update(insert(key, e2))
    88  		require.Error(t, err)
    89  		require.ErrorIs(t, err, storage.ErrAlreadyExists)
    90  
    91  		// ensure old value did not update
    92  		var act []byte
    93  		_ = db.View(func(tx *badger.Txn) error {
    94  			item, err := tx.Get(key)
    95  			require.NoError(t, err)
    96  			act, err = item.ValueCopy(nil)
    97  			require.NoError(t, err)
    98  			return nil
    99  		})
   100  
   101  		assert.Equal(t, val, act)
   102  	})
   103  }
   104  
   105  func TestInsertEncodingError(t *testing.T) {
   106  	unittest.RunWithBadgerDB(t, func(db *badger.DB) {
   107  		e := Entity{ID: 1337}
   108  		key := []byte{0x01, 0x02, 0x03}
   109  
   110  		err := db.Update(insert(key, UnencodeableEntity(e)))
   111  
   112  		require.ErrorIs(t, err, errCantEncode)
   113  	})
   114  }
   115  
   116  func TestUpdateValid(t *testing.T) {
   117  	unittest.RunWithBadgerDB(t, func(db *badger.DB) {
   118  		e := Entity{ID: 1337}
   119  		key := []byte{0x01, 0x02, 0x03}
   120  		val, _ := msgpack.Marshal(e)
   121  
   122  		_ = db.Update(func(tx *badger.Txn) error {
   123  			err := tx.Set(key, []byte{})
   124  			require.NoError(t, err)
   125  			return nil
   126  		})
   127  
   128  		err := db.Update(update(key, e))
   129  		require.NoError(t, err)
   130  
   131  		var act []byte
   132  		_ = db.View(func(tx *badger.Txn) error {
   133  			item, err := tx.Get(key)
   134  			require.NoError(t, err)
   135  			act, err = item.ValueCopy(nil)
   136  			require.NoError(t, err)
   137  			return nil
   138  		})
   139  
   140  		assert.Equal(t, val, act)
   141  	})
   142  }
   143  
   144  func TestUpdateMissing(t *testing.T) {
   145  	unittest.RunWithBadgerDB(t, func(db *badger.DB) {
   146  		e := Entity{ID: 1337}
   147  		key := []byte{0x01, 0x02, 0x03}
   148  
   149  		err := db.Update(update(key, e))
   150  		require.ErrorIs(t, err, storage.ErrNotFound)
   151  
   152  		// ensure nothing was written
   153  		_ = db.View(func(tx *badger.Txn) error {
   154  			_, err := tx.Get(key)
   155  			require.Equal(t, badger.ErrKeyNotFound, err)
   156  			return nil
   157  		})
   158  	})
   159  }
   160  
   161  func TestUpdateEncodingError(t *testing.T) {
   162  	unittest.RunWithBadgerDB(t, func(db *badger.DB) {
   163  		e := Entity{ID: 1337}
   164  		key := []byte{0x01, 0x02, 0x03}
   165  		val, _ := msgpack.Marshal(e)
   166  
   167  		_ = db.Update(func(tx *badger.Txn) error {
   168  			err := tx.Set(key, val)
   169  			require.NoError(t, err)
   170  			return nil
   171  		})
   172  
   173  		err := db.Update(update(key, UnencodeableEntity(e)))
   174  		require.ErrorIs(t, err, errCantEncode)
   175  
   176  		// ensure value did not change
   177  		var act []byte
   178  		_ = db.View(func(tx *badger.Txn) error {
   179  			item, err := tx.Get(key)
   180  			require.NoError(t, err)
   181  			act, err = item.ValueCopy(nil)
   182  			require.NoError(t, err)
   183  			return nil
   184  		})
   185  
   186  		assert.Equal(t, val, act)
   187  	})
   188  }
   189  
   190  func TestUpsertEntry(t *testing.T) {
   191  	unittest.RunWithBadgerDB(t, func(db *badger.DB) {
   192  		e := Entity{ID: 1337}
   193  		key := []byte{0x01, 0x02, 0x03}
   194  		val, _ := msgpack.Marshal(e)
   195  
   196  		// first upsert an non-existed entry
   197  		err := db.Update(insert(key, e))
   198  		require.NoError(t, err)
   199  
   200  		var act []byte
   201  		_ = db.View(func(tx *badger.Txn) error {
   202  			item, err := tx.Get(key)
   203  			require.NoError(t, err)
   204  			act, err = item.ValueCopy(nil)
   205  			require.NoError(t, err)
   206  			return nil
   207  		})
   208  
   209  		assert.Equal(t, val, act)
   210  
   211  		// next upsert the value with the same key
   212  		newEntity := Entity{ID: 1338}
   213  		newVal, _ := msgpack.Marshal(newEntity)
   214  		err = db.Update(upsert(key, newEntity))
   215  		require.NoError(t, err)
   216  
   217  		_ = db.View(func(tx *badger.Txn) error {
   218  			item, err := tx.Get(key)
   219  			require.NoError(t, err)
   220  			act, err = item.ValueCopy(nil)
   221  			require.NoError(t, err)
   222  			return nil
   223  		})
   224  
   225  		assert.Equal(t, newVal, act)
   226  	})
   227  }
   228  
   229  func TestRetrieveValid(t *testing.T) {
   230  	unittest.RunWithBadgerDB(t, func(db *badger.DB) {
   231  		e := Entity{ID: 1337}
   232  		key := []byte{0x01, 0x02, 0x03}
   233  		val, _ := msgpack.Marshal(e)
   234  
   235  		_ = db.Update(func(tx *badger.Txn) error {
   236  			err := tx.Set(key, val)
   237  			require.NoError(t, err)
   238  			return nil
   239  		})
   240  
   241  		var act Entity
   242  		err := db.View(retrieve(key, &act))
   243  		require.NoError(t, err)
   244  
   245  		assert.Equal(t, e, act)
   246  	})
   247  }
   248  
   249  func TestRetrieveMissing(t *testing.T) {
   250  	unittest.RunWithBadgerDB(t, func(db *badger.DB) {
   251  		key := []byte{0x01, 0x02, 0x03}
   252  
   253  		var act Entity
   254  		err := db.View(retrieve(key, &act))
   255  		require.ErrorIs(t, err, storage.ErrNotFound)
   256  	})
   257  }
   258  
   259  func TestRetrieveUnencodeable(t *testing.T) {
   260  	unittest.RunWithBadgerDB(t, func(db *badger.DB) {
   261  		e := Entity{ID: 1337}
   262  		key := []byte{0x01, 0x02, 0x03}
   263  		val, _ := msgpack.Marshal(e)
   264  
   265  		_ = db.Update(func(tx *badger.Txn) error {
   266  			err := tx.Set(key, val)
   267  			require.NoError(t, err)
   268  			return nil
   269  		})
   270  
   271  		var act *UnencodeableEntity
   272  		err := db.View(retrieve(key, &act))
   273  		require.ErrorIs(t, err, errCantDecode)
   274  	})
   275  }
   276  
   277  func TestLookup(t *testing.T) {
   278  	expected := []flow.Identifier{
   279  		{0x01},
   280  		{0x02},
   281  		{0x03},
   282  		{0x04},
   283  	}
   284  	actual := []flow.Identifier{}
   285  
   286  	iterationFunc := lookup(&actual)
   287  
   288  	for _, e := range expected {
   289  		checkFunc, createFunc, handleFunc := iterationFunc()
   290  		assert.True(t, checkFunc([]byte{0x00}))
   291  		target := createFunc()
   292  		assert.IsType(t, &flow.Identifier{}, target)
   293  
   294  		// set the value to target. Need to use reflection here since target is not strongly typed
   295  		reflect.ValueOf(target).Elem().Set(reflect.ValueOf(e))
   296  
   297  		assert.NoError(t, handleFunc())
   298  	}
   299  
   300  	assert.Equal(t, expected, actual)
   301  }
   302  
   303  func TestIterate(t *testing.T) {
   304  	unittest.RunWithBadgerDB(t, func(db *badger.DB) {
   305  		keys := [][]byte{{0x00}, {0x12}, {0xf0}, {0xff}}
   306  		vals := []bool{false, false, true, true}
   307  		expected := []bool{false, true}
   308  
   309  		_ = db.Update(func(tx *badger.Txn) error {
   310  			for i, key := range keys {
   311  				enc, err := msgpack.Marshal(vals[i])
   312  				require.NoError(t, err)
   313  				err = tx.Set(key, enc)
   314  				require.NoError(t, err)
   315  			}
   316  			return nil
   317  		})
   318  
   319  		actual := make([]bool, 0, len(keys))
   320  		iterationFunc := func() (checkFunc, createFunc, handleFunc) {
   321  			check := func(key []byte) bool {
   322  				return !bytes.Equal(key, []byte{0x12})
   323  			}
   324  			var val bool
   325  			create := func() interface{} {
   326  				return &val
   327  			}
   328  			handle := func() error {
   329  				actual = append(actual, val)
   330  				return nil
   331  			}
   332  			return check, create, handle
   333  		}
   334  
   335  		err := db.View(iterate(keys[0], keys[2], iterationFunc))
   336  		require.Nil(t, err)
   337  
   338  		assert.Equal(t, expected, actual)
   339  	})
   340  }
   341  
   342  func TestTraverse(t *testing.T) {
   343  	unittest.RunWithBadgerDB(t, func(db *badger.DB) {
   344  		keys := [][]byte{{0x42, 0x00}, {0xff}, {0x42, 0x56}, {0x00}, {0x42, 0xff}}
   345  		vals := []bool{false, false, true, false, true}
   346  		expected := []bool{false, true}
   347  
   348  		_ = db.Update(func(tx *badger.Txn) error {
   349  			for i, key := range keys {
   350  				enc, err := msgpack.Marshal(vals[i])
   351  				require.NoError(t, err)
   352  				err = tx.Set(key, enc)
   353  				require.NoError(t, err)
   354  			}
   355  			return nil
   356  		})
   357  
   358  		actual := make([]bool, 0, len(keys))
   359  		iterationFunc := func() (checkFunc, createFunc, handleFunc) {
   360  			check := func(key []byte) bool {
   361  				return !bytes.Equal(key, []byte{0x42, 0x56})
   362  			}
   363  			var val bool
   364  			create := func() interface{} {
   365  				return &val
   366  			}
   367  			handle := func() error {
   368  				actual = append(actual, val)
   369  				return nil
   370  			}
   371  			return check, create, handle
   372  		}
   373  
   374  		err := db.View(traverse([]byte{0x42}, iterationFunc))
   375  		require.Nil(t, err)
   376  
   377  		assert.Equal(t, expected, actual)
   378  	})
   379  }
   380  
   381  func TestRemove(t *testing.T) {
   382  	unittest.RunWithBadgerDB(t, func(db *badger.DB) {
   383  		e := Entity{ID: 1337}
   384  		key := []byte{0x01, 0x02, 0x03}
   385  		val, _ := msgpack.Marshal(e)
   386  
   387  		_ = db.Update(func(tx *badger.Txn) error {
   388  			err := tx.Set(key, val)
   389  			require.NoError(t, err)
   390  			return nil
   391  		})
   392  
   393  		t.Run("should be able to remove", func(t *testing.T) {
   394  			_ = db.Update(func(txn *badger.Txn) error {
   395  				err := remove(key)(txn)
   396  				assert.NoError(t, err)
   397  
   398  				_, err = txn.Get(key)
   399  				assert.ErrorIs(t, err, badger.ErrKeyNotFound)
   400  
   401  				return nil
   402  			})
   403  		})
   404  
   405  		t.Run("should error when removing non-existing value", func(t *testing.T) {
   406  			nonexistantKey := append(key, 0x01)
   407  			_ = db.Update(func(txn *badger.Txn) error {
   408  				err := remove(nonexistantKey)(txn)
   409  				assert.ErrorIs(t, err, storage.ErrNotFound)
   410  				assert.Error(t, err)
   411  				return nil
   412  			})
   413  		})
   414  	})
   415  }
   416  
   417  func TestRemoveByPrefix(t *testing.T) {
   418  	t.Run("should no-op when removing non-existing value", func(t *testing.T) {
   419  		unittest.RunWithBadgerDB(t, func(db *badger.DB) {
   420  			e := Entity{ID: 1337}
   421  			key := []byte{0x01, 0x02, 0x03}
   422  			val, _ := msgpack.Marshal(e)
   423  
   424  			_ = db.Update(func(tx *badger.Txn) error {
   425  				err := tx.Set(key, val)
   426  				assert.NoError(t, err)
   427  				return nil
   428  			})
   429  
   430  			nonexistantKey := append(key, 0x01)
   431  			err := db.Update(removeByPrefix(nonexistantKey))
   432  			assert.NoError(t, err)
   433  
   434  			var act Entity
   435  			err = db.View(retrieve(key, &act))
   436  			require.NoError(t, err)
   437  
   438  			assert.Equal(t, e, act)
   439  		})
   440  	})
   441  
   442  	t.Run("should be able to remove", func(t *testing.T) {
   443  		unittest.RunWithBadgerDB(t, func(db *badger.DB) {
   444  			e := Entity{ID: 1337}
   445  			key := []byte{0x01, 0x02, 0x03}
   446  			val, _ := msgpack.Marshal(e)
   447  
   448  			_ = db.Update(func(tx *badger.Txn) error {
   449  				err := tx.Set(key, val)
   450  				assert.NoError(t, err)
   451  				return nil
   452  			})
   453  
   454  			_ = db.Update(func(txn *badger.Txn) error {
   455  				prefix := []byte{0x01, 0x02}
   456  				err := removeByPrefix(prefix)(txn)
   457  				assert.NoError(t, err)
   458  
   459  				_, err = txn.Get(key)
   460  				assert.Error(t, err)
   461  				assert.IsType(t, badger.ErrKeyNotFound, err)
   462  
   463  				return nil
   464  			})
   465  		})
   466  	})
   467  
   468  	t.Run("should be able to remove by key", func(t *testing.T) {
   469  		unittest.RunWithBadgerDB(t, func(db *badger.DB) {
   470  			e := Entity{ID: 1337}
   471  			key := []byte{0x01, 0x02, 0x03}
   472  			val, _ := msgpack.Marshal(e)
   473  
   474  			_ = db.Update(func(tx *badger.Txn) error {
   475  				err := tx.Set(key, val)
   476  				assert.NoError(t, err)
   477  				return nil
   478  			})
   479  
   480  			_ = db.Update(func(txn *badger.Txn) error {
   481  				err := removeByPrefix(key)(txn)
   482  				assert.NoError(t, err)
   483  
   484  				_, err = txn.Get(key)
   485  				assert.Error(t, err)
   486  				assert.IsType(t, badger.ErrKeyNotFound, err)
   487  
   488  				return nil
   489  			})
   490  		})
   491  	})
   492  }
   493  
   494  func TestIterateBoundaries(t *testing.T) {
   495  
   496  	// create range of keys covering all boundaries around our start/end values
   497  	start := []byte{0x10}
   498  	end := []byte{0x20}
   499  	keys := [][]byte{
   500  		// before start -> not included in range
   501  		{0x09, 0xff},
   502  		// shares prefix with start -> included in range
   503  		{0x10, 0x00},
   504  		{0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
   505  		{0x10, 0xff},
   506  		{0x10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
   507  		// prefix between start and end -> included in range
   508  		{0x11, 0x00},
   509  		{0x19, 0xff},
   510  		// shares prefix with end -> included in range
   511  		{0x20, 0x00},
   512  		{0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
   513  		{0x20, 0xff},
   514  		{0x20, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
   515  		// after end -> not included in range
   516  		{0x21, 0x00},
   517  	}
   518  
   519  	// set the maximum current DB key range
   520  	for _, key := range keys {
   521  		if uint32(len(key)) > max {
   522  			max = uint32(len(key))
   523  		}
   524  	}
   525  
   526  	// keys within the expected range
   527  	keysInRange := keys[1:11]
   528  
   529  	unittest.RunWithBadgerDB(t, func(db *badger.DB) {
   530  
   531  		// insert the keys into the database
   532  		_ = db.Update(func(tx *badger.Txn) error {
   533  			for _, key := range keys {
   534  				err := tx.Set(key, []byte{0x00})
   535  				if err != nil {
   536  					return err
   537  				}
   538  			}
   539  			return nil
   540  		})
   541  
   542  		// define iteration function that simply appends all traversed keys
   543  		var found [][]byte
   544  		iteration := func() (checkFunc, createFunc, handleFunc) {
   545  			check := func(key []byte) bool {
   546  				found = append(found, key)
   547  				return false
   548  			}
   549  			create := func() interface{} {
   550  				return nil
   551  			}
   552  			handle := func() error {
   553  				return fmt.Errorf("shouldn't handle anything")
   554  			}
   555  			return check, create, handle
   556  		}
   557  
   558  		// iterate forward and check boundaries are included correctly
   559  		found = nil
   560  		err := db.View(iterate(start, end, iteration))
   561  		for i, f := range found {
   562  			t.Logf("forward %d: %x", i, f)
   563  		}
   564  		require.NoError(t, err, "should iterate forward without error")
   565  		assert.ElementsMatch(t, keysInRange, found, "forward iteration should go over correct keys")
   566  
   567  		// iterate backward and check boundaries are included correctly
   568  		found = nil
   569  		err = db.View(iterate(end, start, iteration))
   570  		for i, f := range found {
   571  			t.Logf("backward %d: %x", i, f)
   572  		}
   573  		require.NoError(t, err, "should iterate backward without error")
   574  		assert.ElementsMatch(t, keysInRange, found, "backward iteration should go over correct keys")
   575  	})
   576  }