Start writing test scaffold to test server

This commit is contained in:
Ethan Frey 2018-02-21 16:04:54 +01:00 committed by rigelrozanski
parent f93947f3ab
commit 1f31fbeea8
6 changed files with 245 additions and 4 deletions

120
mock/app.go Normal file
View File

@ -0,0 +1,120 @@
package mock
import (
"encoding/json"
"fmt"
abci "github.com/tendermint/abci/types"
dbm "github.com/tendermint/tmlibs/db"
"github.com/tendermint/tmlibs/log"
bam "github.com/cosmos/cosmos-sdk/baseapp"
sdk "github.com/cosmos/cosmos-sdk/types"
)
// NewApp creates a simple mock kvstore app for testing.
// It should work similar to a real app.
// Make sure rootDir is empty before running the test,
// in order to guarantee consistent results
func NewApp(logger log.Logger, rootDir string) (abci.Application, error) {
db, err := dbm.NewGoLevelDB("mock", rootDir)
if err != nil {
return nil, err
}
// Capabilities key to access the main KVStore.
capKeyMainStore := sdk.NewKVStoreKey("main")
// Create BaseApp.
baseApp := bam.NewBaseApp("kvstore", logger, db)
// Set mounts for BaseApp's MultiStore.
baseApp.MountStoresIAVL(capKeyMainStore)
// Set Tx decoder
baseApp.SetTxDecoder(decodeTx)
baseApp.SetInitChainer(InitChainer(capKeyMainStore))
// Set a handler Route.
baseApp.Router().AddRoute("kvstore", KVStoreHandler(capKeyMainStore))
// Load latest version.
if err := baseApp.LoadLatestVersion(capKeyMainStore); err != nil {
return nil, err
}
return baseApp, nil
}
// KVStoreHandler is a simple handler that takes kvstoreTx and writes
// them to the db
func KVStoreHandler(storeKey sdk.StoreKey) sdk.Handler {
return func(ctx sdk.Context, msg sdk.Msg) sdk.Result {
dTx, ok := msg.(kvstoreTx)
if !ok {
panic("KVStoreHandler should only receive kvstoreTx")
}
// tx is already unmarshalled
key := dTx.key
value := dTx.value
store := ctx.KVStore(storeKey)
store.Set(key, value)
return sdk.Result{
Code: 0,
Log: fmt.Sprintf("set %s=%s", key, value),
}
}
}
type KV struct {
Key string `json:"key"`
Value string `json:"value"`
}
type GenesisJSON struct {
Values []KV `json:"values"`
}
// InitChainer returns a function that can initialize the chain
// with key/value pairs
func InitChainer(key sdk.StoreKey) func(sdk.Context, abci.RequestInitChain) abci.ResponseInitChain {
return func(ctx sdk.Context, req abci.RequestInitChain) abci.ResponseInitChain {
stateJSON := req.AppStateBytes
genesisState := new(GenesisJSON)
err := json.Unmarshal(stateJSON, genesisState)
if err != nil {
panic(err) // TODO https://github.com/cosmos/cosmos-sdk/issues/468
// return sdk.ErrGenesisParse("").TraceCause(err, "")
}
for _, val := range genesisState.Values {
store := ctx.KVStore(key)
store.Set([]byte(val.Key), []byte(val.Value))
}
return abci.ResponseInitChain{}
}
}
// GenInitOptions can be passed into InitCmd,
// returns a static string of a few key-values that can be parsed
// by InitChainer
func GenInitOptions(args []string) (json.RawMessage, error) {
opts := []byte(`{
"values": [
{
"key": "hello",
"value": "goodbye"
},
{
"key": "foo",
"value": "bar"
}
]
}`)
return opts, nil
}

27
mock/helpers.go Normal file
View File

@ -0,0 +1,27 @@
package mock
import (
"io/ioutil"
"os"
abci "github.com/tendermint/abci/types"
"github.com/tendermint/tmlibs/log"
)
// SetupApp returns an application as well as a clean-up function
// to be used to quickly setup a test case with an app
func SetupApp() (abci.Application, func(), error) {
logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout)).
With("module", "mock")
rootDir, err := ioutil.TempDir("mock-sdk", "")
if err != nil {
return nil, nil, err
}
cleanup := func() {
os.RemoveAll(rootDir)
}
app, err := NewApp(logger, rootDir)
return app, cleanup, err
}

76
mock/tx.go Normal file
View File

@ -0,0 +1,76 @@
package mock
import (
"bytes"
sdk "github.com/cosmos/cosmos-sdk/types"
crypto "github.com/tendermint/go-crypto"
)
// An sdk.Tx which is its own sdk.Msg.
type kvstoreTx struct {
key []byte
value []byte
bytes []byte
}
func (tx kvstoreTx) Get(key interface{}) (value interface{}) {
switch k := key.(type) {
case string:
switch k {
case "key":
return tx.key
case "value":
return tx.value
}
}
return nil
}
func (tx kvstoreTx) Type() string {
return "kvstore"
}
func (tx kvstoreTx) GetMsg() sdk.Msg {
return tx
}
func (tx kvstoreTx) GetSignBytes() []byte {
return tx.bytes
}
// Should the app be calling this? Or only handlers?
func (tx kvstoreTx) ValidateBasic() sdk.Error {
return nil
}
func (tx kvstoreTx) GetSigners() []crypto.Address {
return nil
}
func (tx kvstoreTx) GetSignatures() []sdk.StdSignature {
return nil
}
func (tx kvstoreTx) GetFeePayer() crypto.Address {
return nil
}
// takes raw transaction bytes and decodes them into an sdk.Tx. An sdk.Tx has
// all the signatures and can be used to authenticate.
func decodeTx(txBytes []byte) (sdk.Tx, sdk.Error) {
var tx sdk.Tx
split := bytes.Split(txBytes, []byte("="))
if len(split) == 1 {
k := split[0]
tx = kvstoreTx{k, k, txBytes}
} else if len(split) == 2 {
k, v := split[0], split[1]
tx = kvstoreTx{k, v, txBytes}
} else {
return nil, sdk.ErrTxParse("too many =")
}
return tx, nil
}

View File

@ -62,10 +62,6 @@ func GenerateCoinKey() (crypto.Address, string, error) {
return nil, "", err
}
// debug
bz, err := json.Marshal(info.PubKey)
fmt.Printf("PubKey: %s\n", string(bz))
addr := info.PubKey.Address()
return addr, secret, nil
}

7
server/init_test.go Normal file
View File

@ -0,0 +1,7 @@
package server
import "testing"
func TestInit(t *testing.T) {
}

15
server/start_test.go Normal file
View File

@ -0,0 +1,15 @@
package server
import (
"testing"
)
func TestStart(t *testing.T) {
// app, cleanup, err := mock.SetupApp()
// if cleanup != nil {
// defer cleanup()
// }
// require.NoError(t, err)
// // TODO: init and start
}