mirror of
https://github.com/fluencelabs/tendermint
synced 2025-06-28 20:21:47 +00:00
Merge pull request #3 from tendermint/console
tmsp cli enhancements and simple tests
This commit is contained in:
22
cmd/counter/main.go
Normal file
22
cmd/counter/main.go
Normal file
@ -0,0 +1,22 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
. "github.com/tendermint/go-common"
|
||||
"github.com/tendermint/tmsp/example"
|
||||
"github.com/tendermint/tmsp/server"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
// Start the listener
|
||||
_, err := server.StartListener("tcp://127.0.0.1:8080", example.NewCounterApplication())
|
||||
if err != nil {
|
||||
Exit(err.Error())
|
||||
}
|
||||
|
||||
// Wait forever
|
||||
TrapSignal(func() {
|
||||
// Cleanup
|
||||
})
|
||||
|
||||
}
|
144
cmd/tmsp/cli.go
144
cmd/tmsp/cli.go
@ -1,9 +1,13 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
. "github.com/tendermint/go-common"
|
||||
"github.com/tendermint/go-wire"
|
||||
@ -12,6 +16,9 @@ import (
|
||||
"github.com/codegangsta/cli"
|
||||
)
|
||||
|
||||
// connection is a global variable so it can be reused by the console
|
||||
var conn net.Conn
|
||||
|
||||
func main() {
|
||||
app := cli.NewApp()
|
||||
app.Name = "cli"
|
||||
@ -24,6 +31,34 @@ func main() {
|
||||
},
|
||||
}
|
||||
app.Commands = []cli.Command{
|
||||
{
|
||||
Name: "batch",
|
||||
Usage: "Run a batch of tmsp commands against an application",
|
||||
Action: func(c *cli.Context) {
|
||||
cmdBatch(app, c)
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "console",
|
||||
Usage: "Start an interactive tmsp console for multiple commands",
|
||||
Action: func(c *cli.Context) {
|
||||
cmdConsole(app, c)
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "info",
|
||||
Usage: "Get some info about the application",
|
||||
Action: func(c *cli.Context) {
|
||||
cmdInfo(c)
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "set_option",
|
||||
Usage: "Set an option on the application",
|
||||
Action: func(c *cli.Context) {
|
||||
cmdSetOption(c)
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "append_tx",
|
||||
Usage: "Append a new tx to application",
|
||||
@ -53,46 +88,115 @@ func main() {
|
||||
},
|
||||
},
|
||||
}
|
||||
app.Before = before
|
||||
app.Run(os.Args)
|
||||
|
||||
}
|
||||
|
||||
func before(c *cli.Context) error {
|
||||
if conn == nil {
|
||||
var err error
|
||||
conn, err = Connect(c.GlobalString("address"))
|
||||
if err != nil {
|
||||
Exit(err.Error())
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
|
||||
func cmdBatch(app *cli.App, c *cli.Context) {
|
||||
bufReader := bufio.NewReader(os.Stdin)
|
||||
for {
|
||||
line, more, err := bufReader.ReadLine()
|
||||
if more {
|
||||
Exit("input line is too long")
|
||||
} else if err == io.EOF {
|
||||
break
|
||||
} else if err != nil {
|
||||
Exit(err.Error())
|
||||
}
|
||||
args := []string{"tmsp"}
|
||||
args = append(args, strings.Split(string(line), " ")...)
|
||||
app.Run(args)
|
||||
}
|
||||
}
|
||||
|
||||
func cmdConsole(app *cli.App, c *cli.Context) {
|
||||
for {
|
||||
fmt.Printf("> ")
|
||||
bufReader := bufio.NewReader(os.Stdin)
|
||||
line, more, err := bufReader.ReadLine()
|
||||
if more {
|
||||
Exit("input is too long")
|
||||
} else if err != nil {
|
||||
Exit(err.Error())
|
||||
}
|
||||
|
||||
args := []string{"tmsp"}
|
||||
args = append(args, strings.Split(string(line), " ")...)
|
||||
app.Run(args)
|
||||
}
|
||||
}
|
||||
|
||||
// Get some info from the application
|
||||
func cmdInfo(c *cli.Context) {
|
||||
res, err := makeRequest(conn, types.RequestInfo{})
|
||||
if err != nil {
|
||||
Exit(err.Error())
|
||||
}
|
||||
fmt.Println(res)
|
||||
}
|
||||
|
||||
// Set an option on the application
|
||||
func cmdSetOption(c *cli.Context) {
|
||||
args := c.Args()
|
||||
if len(args) != 2 {
|
||||
Exit("set_option takes 2 arguments (key, value)")
|
||||
}
|
||||
_, err := makeRequest(conn, types.RequestSetOption{args[0], args[1]})
|
||||
if err != nil {
|
||||
Exit(err.Error())
|
||||
}
|
||||
fmt.Printf("%s=%s\n", args[0], args[1])
|
||||
}
|
||||
|
||||
// Append a new tx to application
|
||||
func cmdAppendTx(c *cli.Context) {
|
||||
args := c.Args() // Args to AppendTx
|
||||
conn, err := Connect(c.GlobalString("address"))
|
||||
args := c.Args()
|
||||
if len(args) != 1 {
|
||||
Exit("append_tx takes 1 argument")
|
||||
}
|
||||
txString := args[0]
|
||||
tx := []byte(txString)
|
||||
if len(txString) > 2 && strings.HasPrefix(txString, "0x") {
|
||||
var err error
|
||||
tx, err = hex.DecodeString(txString[2:])
|
||||
if err != nil {
|
||||
Exit(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
res, err := makeRequest(conn, types.RequestAppendTx{tx})
|
||||
if err != nil {
|
||||
Exit(err.Error())
|
||||
}
|
||||
res, err := makeRequest(conn, types.RequestAppendTx{[]byte(args[0])})
|
||||
if err != nil {
|
||||
Exit(err.Error())
|
||||
}
|
||||
fmt.Println("Sent tx:", args[0], "response:", res)
|
||||
fmt.Println("Sent tx:", txString, "response:", res)
|
||||
}
|
||||
|
||||
// Get application Merkle root hash
|
||||
func cmdGetHash(c *cli.Context) {
|
||||
conn, err := Connect(c.GlobalString("address"))
|
||||
if err != nil {
|
||||
Exit(err.Error())
|
||||
}
|
||||
res, err := makeRequest(conn, types.RequestGetHash{})
|
||||
if err != nil {
|
||||
Exit(err.Error())
|
||||
}
|
||||
fmt.Println("Got hash:", Fmt("%X", res.(types.ResponseGetHash).Hash))
|
||||
fmt.Printf("%X\n", res.(types.ResponseGetHash).Hash)
|
||||
}
|
||||
|
||||
// Commit the application state
|
||||
func cmdCommit(c *cli.Context) {
|
||||
conn, err := Connect(c.GlobalString("address"))
|
||||
if err != nil {
|
||||
Exit(err.Error())
|
||||
}
|
||||
_, err = makeRequest(conn, types.RequestCommit{})
|
||||
_, err := makeRequest(conn, types.RequestCommit{})
|
||||
if err != nil {
|
||||
Exit(err.Error())
|
||||
}
|
||||
@ -101,11 +205,7 @@ func cmdCommit(c *cli.Context) {
|
||||
|
||||
// Roll back the application state to the latest commit
|
||||
func cmdRollback(c *cli.Context) {
|
||||
conn, err := Connect(c.GlobalString("address"))
|
||||
if err != nil {
|
||||
Exit(err.Error())
|
||||
}
|
||||
_, err = makeRequest(conn, types.RequestRollback{})
|
||||
_, err := makeRequest(conn, types.RequestRollback{})
|
||||
if err != nil {
|
||||
Exit(err.Error())
|
||||
}
|
||||
|
@ -69,7 +69,7 @@ func (appC *CounterAppContext) AppendTx(tx []byte) ([]types.Event, types.RetCode
|
||||
|
||||
func (appC *CounterAppContext) GetHash() ([]byte, types.RetCode) {
|
||||
hash := make([]byte, 32)
|
||||
binary.PutVarint(hash, int64(appC.hashCount))
|
||||
binary.PutVarint(hash, int64(appC.txCount))
|
||||
appC.hashCount += 1
|
||||
return hash, 0
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ package server
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"strings"
|
||||
|
||||
@ -86,7 +87,11 @@ func handleRequests(appC types.AppContext, closeConn chan error, conn net.Conn,
|
||||
var req types.Request
|
||||
wire.ReadBinaryPtr(&req, bufReader, 0, &n, &err)
|
||||
if err != nil {
|
||||
closeConn <- fmt.Errorf("Error in handleRequests: %v", err.Error())
|
||||
if err == io.EOF {
|
||||
closeConn <- fmt.Errorf("Connection closed by client")
|
||||
} else {
|
||||
closeConn <- fmt.Errorf("Error in handleRequests: %v", err.Error())
|
||||
}
|
||||
return
|
||||
}
|
||||
count++
|
||||
|
100
test.sh
Normal file
100
test.sh
Normal file
@ -0,0 +1,100 @@
|
||||
#! /bin/bash
|
||||
|
||||
# Make sure the tmsp cli can connect to the dummy
|
||||
echo "Dummy test ..."
|
||||
dummy &> /dev/null &
|
||||
PID=`echo $!`
|
||||
sleep 1
|
||||
RESULT_HASH=`tmsp get_hash`
|
||||
if [[ "$RESULT_HASH" != "" ]]; then
|
||||
echo "Expected nothing but got: $RESULT_HASH"
|
||||
exit 1
|
||||
fi
|
||||
echo "... Pass!"
|
||||
echo ""
|
||||
|
||||
# Add a tx, get hash, commit, get hash
|
||||
# hashes should be non-empty and identical
|
||||
echo "Dummy batch test ..."
|
||||
OUTPUT=`(tmsp batch) <<STDIN
|
||||
append_tx abc
|
||||
get_hash
|
||||
commit
|
||||
get_hash
|
||||
STDIN`
|
||||
|
||||
HASH1=`echo "$OUTPUT" | tail -n 3 | head -n 1`
|
||||
HASH2=`echo "$OUTPUT" | tail -n 1`
|
||||
|
||||
if [[ "$HASH1" == "" ]]; then
|
||||
echo "Expected non empty hash!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ "$HASH1" != "$HASH2" ]]; then
|
||||
echo "Expected hashes before and after commit to match: $HASH1, $HASH2"
|
||||
exit 1
|
||||
fi
|
||||
echo "... Pass!"
|
||||
echo ""
|
||||
|
||||
# Start a new connection and ensure the hash is the same
|
||||
echo "New connection test ..."
|
||||
RESULT_HASH=`tmsp get_hash`
|
||||
if [[ "$HASH1" != "$RESULT_HASH" ]]; then
|
||||
echo "Expected hash to persist as $HASH1 for new connection. Got $RESULT_HASH"
|
||||
exit 1
|
||||
fi
|
||||
echo "... Pass!"
|
||||
echo ""
|
||||
|
||||
|
||||
kill $PID
|
||||
sleep 1
|
||||
|
||||
# test the counter app
|
||||
echo "Counter test ..."
|
||||
counter &> /dev/null &
|
||||
PID=`echo $!`
|
||||
sleep 1
|
||||
OUTPUT=`(tmsp batch) <<STDIN
|
||||
set_option serial on
|
||||
get_hash
|
||||
append_tx abc
|
||||
STDIN`
|
||||
|
||||
# why can't we pick up the non-zero exit code here?
|
||||
# echo $?
|
||||
|
||||
HASH1=`echo "$OUTPUT" | tail -n +2 | head -n 1`
|
||||
if [[ "${HASH1:0:2}" != "00" ]]; then
|
||||
echo "Expected opening hash to lead with 00. Got $HASH1"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
OUTPUT=`(tmsp batch) <<STDIN
|
||||
set_option serial on
|
||||
append_tx 0x00
|
||||
get_hash
|
||||
append_tx 0x02
|
||||
get_hash
|
||||
STDIN`
|
||||
|
||||
HASH1=`echo "$OUTPUT" | tail -n +3 | head -n 1`
|
||||
HASH2=`echo "$OUTPUT" | tail -n +5 | head -n 1`
|
||||
|
||||
if [[ "${HASH1:0:2}" != "02" ]]; then
|
||||
echo "Expected hash to lead with 02. Got $HASH1"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ "${HASH2:0:2}" != "04" ]]; then
|
||||
echo "Expected hash to lead with 04. Got $HASH2"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "... Pass!"
|
||||
echo ""
|
||||
|
||||
kill $PID
|
||||
|
Reference in New Issue
Block a user