cosmos-sdk/store/rootmulti/store_test.go

292 lines
7.9 KiB
Go
Raw Normal View History

2019-02-01 17:03:09 -08:00
package rootmulti
import (
"testing"
"github.com/stretchr/testify/require"
abci "github.com/tendermint/tendermint/abci/types"
"github.com/tendermint/tendermint/crypto/merkle"
dbm "github.com/tendermint/tm-db"
2018-01-15 17:10:46 -08:00
2019-02-05 10:39:22 -08:00
"github.com/cosmos/cosmos-sdk/store/errors"
"github.com/cosmos/cosmos-sdk/store/types"
)
2018-07-26 18:24:18 -07:00
func TestStoreType(t *testing.T) {
db := dbm.NewMemDB()
2019-02-01 17:03:09 -08:00
store := NewStore(db)
2018-07-26 18:24:18 -07:00
store.MountStoreWithDB(
2019-02-01 17:03:09 -08:00
types.NewKVStoreKey("store1"), types.StoreTypeIAVL, db)
2018-07-26 18:24:18 -07:00
}
func TestStoreMount(t *testing.T) {
db := dbm.NewMemDB()
2019-02-01 17:03:09 -08:00
store := NewStore(db)
2019-02-01 17:03:09 -08:00
key1 := types.NewKVStoreKey("store1")
key2 := types.NewKVStoreKey("store2")
dup1 := types.NewKVStoreKey("store1")
2019-02-01 17:03:09 -08:00
require.NotPanics(t, func() { store.MountStoreWithDB(key1, types.StoreTypeIAVL, db) })
require.NotPanics(t, func() { store.MountStoreWithDB(key2, types.StoreTypeIAVL, db) })
2019-02-01 17:03:09 -08:00
require.Panics(t, func() { store.MountStoreWithDB(key1, types.StoreTypeIAVL, db) })
require.Panics(t, func() { store.MountStoreWithDB(dup1, types.StoreTypeIAVL, db) })
}
func TestCacheMultiStoreWithVersion(t *testing.T) {
var db dbm.DB = dbm.NewMemDB()
ms := newMultiStoreWithMounts(db)
err := ms.LoadLatestVersion()
require.Nil(t, err)
commitID := types.CommitID{}
checkStore(t, ms, commitID, commitID)
k, v := []byte("wind"), []byte("blows")
store1 := ms.getStoreByName("store1").(types.KVStore)
store1.Set(k, v)
cID := ms.Commit()
require.Equal(t, int64(1), cID.Version)
// require failure when given an invalid or pruned version
_, err = ms.CacheMultiStoreWithVersion(cID.Version + 1)
require.Error(t, err)
// require a valid version can be cache-loaded
cms, err := ms.CacheMultiStoreWithVersion(cID.Version)
require.NoError(t, err)
// require a valid key lookup yields the correct value
kvStore := cms.GetKVStore(ms.keysByName["store1"])
require.NotNil(t, kvStore)
require.Equal(t, kvStore.Get(k), v)
// require we cannot commit (write) to a cache-versioned multi-store
require.Panics(t, func() {
kvStore.Set(k, []byte("newValue"))
cms.Write()
})
}
func TestHashStableWithEmptyCommit(t *testing.T) {
var db dbm.DB = dbm.NewMemDB()
ms := newMultiStoreWithMounts(db)
err := ms.LoadLatestVersion()
require.Nil(t, err)
commitID := types.CommitID{}
checkStore(t, ms, commitID, commitID)
k, v := []byte("wind"), []byte("blows")
store1 := ms.getStoreByName("store1").(types.KVStore)
store1.Set(k, v)
cID := ms.Commit()
require.Equal(t, int64(1), cID.Version)
hash := cID.Hash
// make an empty commit, it should update version, but not affect hash
cID = ms.Commit()
require.Equal(t, int64(2), cID.Version)
require.Equal(t, hash, cID.Hash)
}
func TestMultistoreCommitLoad(t *testing.T) {
var db dbm.DB = dbm.NewMemDB()
store := newMultiStoreWithMounts(db)
err := store.LoadLatestVersion()
require.Nil(t, err)
// New store has empty last commit.
2019-02-01 17:03:09 -08:00
commitID := types.CommitID{}
checkStore(t, store, commitID, commitID)
// Make sure we can get stores by name.
s1 := store.getStoreByName("store1")
require.NotNil(t, s1)
s3 := store.getStoreByName("store3")
require.NotNil(t, s3)
s77 := store.getStoreByName("store77")
require.Nil(t, s77)
2018-01-30 06:30:25 -08:00
// Make a few commits and check them.
nCommits := int64(3)
for i := int64(0); i < nCommits; i++ {
commitID = store.Commit()
expectedCommitID := getExpectedCommitID(store, i+1)
checkStore(t, store, expectedCommitID, commitID)
}
// Load the latest multistore again and check version.
store = newMultiStoreWithMounts(db)
err = store.LoadLatestVersion()
require.Nil(t, err)
commitID = getExpectedCommitID(store, nCommits)
checkStore(t, store, commitID, commitID)
// Commit and check version.
commitID = store.Commit()
expectedCommitID := getExpectedCommitID(store, nCommits+1)
checkStore(t, store, expectedCommitID, commitID)
// Load an older multistore and check version.
ver := nCommits - 1
store = newMultiStoreWithMounts(db)
err = store.LoadVersion(ver)
require.Nil(t, err)
commitID = getExpectedCommitID(store, ver)
checkStore(t, store, commitID, commitID)
// XXX: commit this older version
commitID = store.Commit()
expectedCommitID = getExpectedCommitID(store, ver+1)
checkStore(t, store, expectedCommitID, commitID)
// XXX: confirm old commit is overwritten and we have rolled back
// LatestVersion
store = newMultiStoreWithMounts(db)
err = store.LoadLatestVersion()
require.Nil(t, err)
commitID = getExpectedCommitID(store, ver+1)
checkStore(t, store, commitID, commitID)
}
2018-01-30 06:30:25 -08:00
func TestParsePath(t *testing.T) {
_, _, err := parsePath("foo")
require.Error(t, err)
2018-01-30 06:30:25 -08:00
store, subpath, err := parsePath("/foo")
require.NoError(t, err)
require.Equal(t, store, "foo")
require.Equal(t, subpath, "")
2018-01-30 06:30:25 -08:00
store, subpath, err = parsePath("/fizz/bang/baz")
require.NoError(t, err)
require.Equal(t, store, "fizz")
require.Equal(t, subpath, "/bang/baz")
2018-01-30 06:30:25 -08:00
substore, subsubpath, err := parsePath(subpath)
require.NoError(t, err)
require.Equal(t, substore, "bang")
require.Equal(t, subsubpath, "/baz")
2018-01-30 06:30:25 -08:00
}
2018-02-02 07:22:49 -08:00
func TestMultiStoreQuery(t *testing.T) {
db := dbm.NewMemDB()
multi := newMultiStoreWithMounts(db)
err := multi.LoadLatestVersion()
require.Nil(t, err)
2018-02-02 07:22:49 -08:00
k, v := []byte("wind"), []byte("blows")
k2, v2 := []byte("water"), []byte("flows")
// v3 := []byte("is cold")
cid := multi.Commit()
// Make sure we can get by name.
2018-02-02 07:22:49 -08:00
garbage := multi.getStoreByName("bad-name")
require.Nil(t, garbage)
2018-02-02 07:22:49 -08:00
// Set and commit data in one store.
2019-02-01 17:03:09 -08:00
store1 := multi.getStoreByName("store1").(types.KVStore)
2018-02-02 07:22:49 -08:00
store1.Set(k, v)
// ... and another.
2019-02-01 17:03:09 -08:00
store2 := multi.getStoreByName("store2").(types.KVStore)
2018-02-02 07:22:49 -08:00
store2.Set(k2, v2)
// Commit the multistore.
2018-02-02 07:22:49 -08:00
cid = multi.Commit()
ver := cid.Version
// Reload multistore from database
multi = newMultiStoreWithMounts(db)
err = multi.LoadLatestVersion()
require.Nil(t, err)
// Test bad path.
2018-02-02 07:22:49 -08:00
query := abci.RequestQuery{Path: "/key", Data: k, Height: ver}
qres := multi.Query(query)
2019-02-05 10:39:22 -08:00
require.EqualValues(t, errors.CodeUnknownRequest, qres.Code)
require.EqualValues(t, errors.CodespaceRoot, qres.Codespace)
2018-02-02 07:22:49 -08:00
query.Path = "h897fy32890rf63296r92"
qres = multi.Query(query)
2019-02-05 10:39:22 -08:00
require.EqualValues(t, errors.CodeUnknownRequest, qres.Code)
require.EqualValues(t, errors.CodespaceRoot, qres.Codespace)
2018-02-02 07:22:49 -08:00
// Test invalid store name.
2018-02-02 07:22:49 -08:00
query.Path = "/garbage/key"
qres = multi.Query(query)
2019-02-05 10:39:22 -08:00
require.EqualValues(t, errors.CodeUnknownRequest, qres.Code)
require.EqualValues(t, errors.CodespaceRoot, qres.Codespace)
2018-02-02 07:22:49 -08:00
// Test valid query with data.
2018-02-02 07:22:49 -08:00
query.Path = "/store1/key"
qres = multi.Query(query)
2019-02-05 10:39:22 -08:00
require.EqualValues(t, errors.CodeOK, qres.Code)
require.Equal(t, v, qres.Value)
2018-02-02 07:22:49 -08:00
// Test valid but empty query.
2018-02-02 07:22:49 -08:00
query.Path = "/store2/key"
query.Prove = true
qres = multi.Query(query)
2019-02-05 10:39:22 -08:00
require.EqualValues(t, errors.CodeOK, qres.Code)
require.Nil(t, qres.Value)
2018-02-02 07:22:49 -08:00
// Test store2 data.
2018-02-02 07:22:49 -08:00
query.Data = k2
qres = multi.Query(query)
2019-02-05 10:39:22 -08:00
require.EqualValues(t, errors.CodeOK, qres.Code)
require.Equal(t, v2, qres.Value)
2018-02-02 07:22:49 -08:00
}
//-----------------------------------------------------------------------
// utils
2019-02-01 17:03:09 -08:00
func newMultiStoreWithMounts(db dbm.DB) *Store {
store := NewStore(db)
2019-02-05 10:39:22 -08:00
store.pruningOpts = types.PruneSyncable
store.MountStoreWithDB(
2019-02-01 17:03:09 -08:00
types.NewKVStoreKey("store1"), types.StoreTypeIAVL, nil)
store.MountStoreWithDB(
2019-02-01 17:03:09 -08:00
types.NewKVStoreKey("store2"), types.StoreTypeIAVL, nil)
store.MountStoreWithDB(
2019-02-01 17:03:09 -08:00
types.NewKVStoreKey("store3"), types.StoreTypeIAVL, nil)
return store
}
2019-02-01 17:03:09 -08:00
func checkStore(t *testing.T, store *Store, expect, got types.CommitID) {
require.Equal(t, expect, got)
require.Equal(t, expect, store.LastCommitID())
}
2019-02-01 17:03:09 -08:00
func getExpectedCommitID(store *Store, ver int64) types.CommitID {
return types.CommitID{
Version: ver,
Hash: hashStores(store.stores),
}
}
2019-02-01 17:03:09 -08:00
func hashStores(stores map[types.StoreKey]types.CommitStore) []byte {
m := make(map[string][]byte, len(stores))
2018-01-15 17:10:46 -08:00
for key, store := range stores {
name := key.Name()
m[name] = storeInfo{
Name: name,
Core: storeCore{
CommitID: store.LastCommitID(),
// StoreType: store.GetStoreType(),
},
}.Hash()
}
return merkle.SimpleHashFromMap(m)
}