Browse Source

Merge pull request #3 from tendermint/console

tmsp cli enhancements and simple tests
pull/1780/head
Jae Kwon 9 years ago
parent
commit
4fc7aa234f
5 changed files with 249 additions and 22 deletions
  1. +22
    -0
      cmd/counter/main.go
  2. +120
    -20
      cmd/tmsp/cli.go
  3. +1
    -1
      example/counter.go
  4. +6
    -1
      server/server.go
  5. +100
    -0
      test.sh

+ 22
- 0
cmd/counter/main.go View 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
})
}

+ 120
- 20
cmd/tmsp/cli.go View File

@ -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
}
//--------------------------------------------------------------------------------
// Append a new tx to application
func cmdAppendTx(c *cli.Context) {
args := c.Args() // Args to AppendTx
conn, err := Connect(c.GlobalString("address"))
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())
}
res, err := makeRequest(conn, types.RequestAppendTx{[]byte(args[0])})
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.Println("Sent tx:", args[0], "response:", res)
fmt.Printf("%s=%s\n", args[0], args[1])
}
// Get application Merkle root hash
func cmdGetHash(c *cli.Context) {
conn, err := Connect(c.GlobalString("address"))
// Append a new tx to application
func cmdAppendTx(c *cli.Context) {
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())
}
fmt.Println("Sent tx:", txString, "response:", res)
}
// Get application Merkle root hash
func cmdGetHash(c *cli.Context) {
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())
}


+ 1
- 1
example/counter.go View File

@ -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
}


+ 6
- 1
server/server.go View File

@ -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
- 0
test.sh View 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

Loading…
Cancel
Save