From 88f8141ab872a688702706c4ca73008a1d6b0985 Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Fri, 1 Jul 2016 20:22:58 -0400 Subject: [PATCH 1/7] cleanup cli, drop expr --- cmd/tmsp-cli/tmsp-cli.go | 35 +++++++++++------------- example/dummy/dummy.go | 1 + tests/test.sh | 12 -------- tests/test_counter/test.sh | 13 +++++++++ tests/{ => test_counter}/test_counter.go | 0 5 files changed, 30 insertions(+), 31 deletions(-) delete mode 100755 tests/test.sh create mode 100755 tests/test_counter/test.sh rename tests/{ => test_counter}/test_counter.go (100%) diff --git a/cmd/tmsp-cli/tmsp-cli.go b/cmd/tmsp-cli/tmsp-cli.go index 373266efc..f30979117 100644 --- a/cmd/tmsp-cli/tmsp-cli.go +++ b/cmd/tmsp-cli/tmsp-cli.go @@ -2,6 +2,7 @@ package main import ( "bufio" + "encoding/hex" "errors" "fmt" "io" @@ -10,7 +11,6 @@ import ( "github.com/codegangsta/cli" . "github.com/tendermint/go-common" - "github.com/tendermint/go-wire/expr" "github.com/tendermint/tmsp/client" "github.com/tendermint/tmsp/types" ) @@ -195,12 +195,7 @@ func cmdAppendTx(c *cli.Context) error { if len(args) != 1 { return errors.New("Command append_tx takes 1 argument") } - txExprString := c.Args()[0] - txBytes, err := expr.Compile(txExprString) - if err != nil { - return err - } - + txBytes := stringOrHexToBytes(c.Args()[0]) res := client.AppendTxSync(txBytes) printResponse(res, string(res.Data), true) return nil @@ -212,12 +207,7 @@ func cmdCheckTx(c *cli.Context) error { if len(args) != 1 { return errors.New("Command check_tx takes 1 argument") } - txExprString := c.Args()[0] - txBytes, err := expr.Compile(txExprString) - if err != nil { - return err - } - + txBytes := stringOrHexToBytes(c.Args()[0]) res := client.CheckTxSync(txBytes) printResponse(res, string(res.Data), true) return nil @@ -236,12 +226,7 @@ func cmdQuery(c *cli.Context) error { if len(args) != 1 { return errors.New("Command query takes 1 argument") } - queryExprString := args[0] - queryBytes, err := expr.Compile(queryExprString) - if err != nil { - return err - } - + queryBytes := stringOrHexToBytes(c.Args()[0]) res := client.QuerySync(queryBytes) printResponse(res, string(res.Data), true) return nil @@ -264,3 +249,15 @@ func printResponse(res types.Result, s string, printCode bool) { } } + +// NOTE: s is interpreted as a string unless prefixed with 0x +func stringOrHexToBytes(s string) []byte { + if len(s) > 2 && s[:2] == "0x" { + b, err := hex.DecodeString(s[2:]) + if err != nil { + fmt.Println("Error decoding hex argument:", err.Error()) + } + return b + } + return []byte(s) +} diff --git a/example/dummy/dummy.go b/example/dummy/dummy.go index 3fa237f04..ca3a8c03a 100644 --- a/example/dummy/dummy.go +++ b/example/dummy/dummy.go @@ -28,6 +28,7 @@ func (app *DummyApplication) SetOption(key string, value string) (log string) { return "" } +// tx is either "key=value" or just arbitrary bytes func (app *DummyApplication) AppendTx(tx []byte) types.Result { parts := strings.Split(string(tx), "=") if len(parts) == 2 { diff --git a/tests/test.sh b/tests/test.sh deleted file mode 100755 index ebdab0c80..000000000 --- a/tests/test.sh +++ /dev/null @@ -1,12 +0,0 @@ - -ROOT=$GOPATH/src/github.com/tendermint/tmsp -cd $ROOT - -# test golang counter -COUNTER_APP="counter" go run $ROOT/tests/test_counter.go - -# test golang counter via grpc -COUNTER_APP="counter -tmsp=grpc" go run $ROOT/tests/test_counter.go -tmsp=grpc - -# test nodejs counter -COUNTER_APP="node ../js-tmsp/example/app.js" go run $ROOT/tests/test_counter.go diff --git a/tests/test_counter/test.sh b/tests/test_counter/test.sh new file mode 100755 index 000000000..c1a0f58bb --- /dev/null +++ b/tests/test_counter/test.sh @@ -0,0 +1,13 @@ +# These tests spawn the counter app and server by execing the COUNTER_APP command and run some simple client tests against it + +ROOT=$GOPATH/src/github.com/tendermint/tmsp/tests/test_counter +cd $ROOT + +# test golang counter +COUNTER_APP="counter" go run test_counter.go + +# test golang counter via grpc +COUNTER_APP="counter -tmsp=grpc" go run test_counter.go -tmsp=grpc + +# test nodejs counter +COUNTER_APP="node $GOPATH/src/github.com/tendermint/js-tmsp/example/app.js" go run test_counter.go diff --git a/tests/test_counter.go b/tests/test_counter/test_counter.go similarity index 100% rename from tests/test_counter.go rename to tests/test_counter/test_counter.go From 732634112b2643ad1d704d0c8deeb537811ede0f Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Wed, 6 Jul 2016 16:57:02 -0400 Subject: [PATCH 2/7] run grpc finishAsyncCall in go routine --- client/grpc_client.go | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/client/grpc_client.go b/client/grpc_client.go index a1c514102..5937b5c57 100644 --- a/client/grpc_client.go +++ b/client/grpc_client.go @@ -90,7 +90,10 @@ func (cli *grpcClient) Error() error { } //---------------------------------------- -// async calls are really sync. +// GRPC calls are synchronous, but some callbacks expect to be called asynchronously +// (eg. the mempool expects to be able to lock to remove bad txs from cache). +// To accomodate, we finish each call in its own go-routine, +// which is expensive, but easy - if you want something better, use the socket protocol! // maybe one day, if people really want it, we use grpc streams, // but hopefully not :D @@ -199,15 +202,20 @@ func (cli *grpcClient) finishAsyncCall(req *types.Request, res *types.Response) reqres.Done() // Release waiters reqres.SetDone() // so reqRes.SetCallback will run the callback - // Notify reqRes listener if set - if cb := reqres.GetCallback(); cb != nil { - cb(res) - } + // go routine for callbacks + go func() { + // Notify reqRes listener if set + if cb := reqres.GetCallback(); cb != nil { + fmt.Println("CALLING reqres CB") + cb(res) + } - // Notify client listener if set - if cli.resCb != nil { - cli.resCb(reqres.Request, res) - } + // Notify client listener if set + if cli.resCb != nil { + fmt.Println("CALLING client CB") + cli.resCb(reqres.Request, res) + } + }() return reqres } From 49a67aee8a7984a68eabe2c45ff6eb0ff51e31f9 Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Wed, 6 Jul 2016 17:01:20 -0400 Subject: [PATCH 3/7] add circle.yml. disable js test --- README.md | 2 ++ circle.yml | 24 ++++++++++++++++++++++++ client/grpc_client.go | 2 -- tests/test_counter/test.sh | 2 +- 4 files changed, 27 insertions(+), 3 deletions(-) create mode 100644 circle.yml diff --git a/README.md b/README.md index 6c8420839..617e581ba 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ # Tendermint Socket Protocol (TMSP) +[![CircleCI](https://circleci.com/gh/tendermint/tmsp.svg?style=svg)](https://circleci.com/gh/tendermint/tmsp) + Blockchains are a system for creating shared multi-master application state. **TMSP** is a socket protocol enabling a blockchain consensus engine, running in one process, to manage a blockchain application state, running in another. diff --git a/circle.yml b/circle.yml new file mode 100644 index 000000000..548dcc3e9 --- /dev/null +++ b/circle.yml @@ -0,0 +1,24 @@ +machine: + environment: + GOPATH: /home/ubuntu/.go_workspace + REPO: $GOPATH/src/github.com/$CIRCLE_PROJECT_USERNAME/$CIRCLE_PROJECT_REPONAME + hosts: + circlehost: 127.0.0.1 + localhost: 127.0.0.1 + +checkout: + post: + - rm -rf $REPO + - mkdir -p $HOME/.go_workspace/src/github.com/$CIRCLE_PROJECT_USERNAME + - mv $HOME/$CIRCLE_PROJECT_REPONAME $REPO + # - git submodule sync + # - git submodule update --init # use submodules + +dependencies: + override: + - "cd $REPO && go get -t ./..." + +test: + override: + - "cd $REPO && go test ./..." + - "cd $REPO && bash tests/test_counter/test.sh" diff --git a/client/grpc_client.go b/client/grpc_client.go index 5937b5c57..813be658a 100644 --- a/client/grpc_client.go +++ b/client/grpc_client.go @@ -206,13 +206,11 @@ func (cli *grpcClient) finishAsyncCall(req *types.Request, res *types.Response) go func() { // Notify reqRes listener if set if cb := reqres.GetCallback(); cb != nil { - fmt.Println("CALLING reqres CB") cb(res) } // Notify client listener if set if cli.resCb != nil { - fmt.Println("CALLING client CB") cli.resCb(reqres.Request, res) } }() diff --git a/tests/test_counter/test.sh b/tests/test_counter/test.sh index c1a0f58bb..7acd5d146 100755 --- a/tests/test_counter/test.sh +++ b/tests/test_counter/test.sh @@ -10,4 +10,4 @@ COUNTER_APP="counter" go run test_counter.go COUNTER_APP="counter -tmsp=grpc" go run test_counter.go -tmsp=grpc # test nodejs counter -COUNTER_APP="node $GOPATH/src/github.com/tendermint/js-tmsp/example/app.js" go run test_counter.go +#COUNTER_APP="node $GOPATH/src/github.com/tendermint/js-tmsp/example/app.js" go run test_counter.go From ba11348508939e9d273cdc1cc476c5c611e14e66 Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Fri, 22 Jul 2016 01:23:13 -0400 Subject: [PATCH 4/7] update make test --- Makefile | 1 + circle.yml | 3 +-- tests/test_counter/test.sh | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 20fb8a236..0f8adc5b6 100644 --- a/Makefile +++ b/Makefile @@ -10,6 +10,7 @@ install: get_deps test: go test github.com/tendermint/tmsp/... + bash tests/test_counter/test.sh get_deps: go get -d github.com/tendermint/tmsp/... diff --git a/circle.yml b/circle.yml index 548dcc3e9..33e50dc71 100644 --- a/circle.yml +++ b/circle.yml @@ -20,5 +20,4 @@ dependencies: test: override: - - "cd $REPO && go test ./..." - - "cd $REPO && bash tests/test_counter/test.sh" + - "cd $REPO && make test" diff --git a/tests/test_counter/test.sh b/tests/test_counter/test.sh index 7acd5d146..4883a5e0e 100755 --- a/tests/test_counter/test.sh +++ b/tests/test_counter/test.sh @@ -10,4 +10,5 @@ COUNTER_APP="counter" go run test_counter.go COUNTER_APP="counter -tmsp=grpc" go run test_counter.go -tmsp=grpc # test nodejs counter +# TODO: fix node app #COUNTER_APP="node $GOPATH/src/github.com/tendermint/js-tmsp/example/app.js" go run test_counter.go From a263323d5c816030ff75eb9808028d8e6d747ffa Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Sat, 23 Jul 2016 17:37:09 -0400 Subject: [PATCH 5/7] update readme. --verbose makes batch look like console --- README.md | 23 +++++++++++++++++++++++ cmd/tmsp-cli/tmsp-cli.go | 36 ++++++++++++++++++++++++++---------- 2 files changed, 49 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 617e581ba..11559c9ac 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,29 @@ Other implementations: * [cpp-tmsp](https://github.com/mdyring/cpp-tmsp) by Martin Dyring-Andersen * [js-tmsp](https://github.com/tendermint/js-tmsp) +## Contents + +This repository holds a number of important pieces: + +- `types/types.proto` + - the protobuf file definig TMSP message types, and the optional grpc interface. + - use `protoc --go_out=plugins=grpc:./types types/types.proto` to generate the `types/types.pb.go` file + - see `protoc --help` and [the grpc docs](www.grpc.io/docs) for examples and details of other languages + +- golang implementation of TMSP client and server + - two implementations: + - asynchronous, ordered message passing over unix or tcp + - grpc + - TendermintCore runs a client, and the application runs a server + +- `cmd/tmsp-cli` + - command line tool wrapping the client for probing/testing a TMSP application + +- examples: + - the `cmd/counter` application, which illustrates nonce checking in txs + - the `cmd/dummy` application, which illustrates a simple key-value merkle tree + + ## Message format Since this is a streaming protocol, all messages are encoded with a length-prefix followed by the message encoded in Protobuf3. Protobuf3 doesn't have an official length-prefix standard, so we use our own. The first byte represents the length of the big-endian encoded length. diff --git a/cmd/tmsp-cli/tmsp-cli.go b/cmd/tmsp-cli/tmsp-cli.go index f30979117..964dbe69c 100644 --- a/cmd/tmsp-cli/tmsp-cli.go +++ b/cmd/tmsp-cli/tmsp-cli.go @@ -22,6 +22,7 @@ func main() { app := cli.NewApp() app.Name = "tmsp-cli" app.Usage = "tmsp-cli [command] [args...]" + app.Version = "0.2" app.Flags = []cli.Flag{ cli.StringFlag{ Name: "address", @@ -33,6 +34,10 @@ func main() { Value: "socket", Usage: "socket or grpc", }, + cli.BoolFlag{ + Name: "verbose", + Usage: "print the command and results as if it were a console session", + }, } app.Commands = []cli.Command{ { @@ -133,7 +138,10 @@ func cmdBatch(app *cli.App, c *cli.Context) error { } else if err != nil { return err } - args := []string{"tmsp"} + args := []string{"tmsp-cli"} + if c.GlobalBool("verbose") { + args = append(args, "--verbose") + } args = append(args, strings.Split(string(line), " ")...) app.Run(args) } @@ -151,7 +159,7 @@ func cmdConsole(app *cli.App, c *cli.Context) error { return err } - args := []string{"tmsp"} + args := []string{"tmsp-cli"} args = append(args, strings.Split(string(line), " ")...) if err := app.Run(args); err != nil { return err @@ -167,14 +175,14 @@ func cmdEcho(c *cli.Context) error { return errors.New("Command echo takes 1 argument") } res := client.EchoSync(args[0]) - printResponse(res, string(res.Data), false) + printResponse(c, res, string(res.Data), false) return nil } // Get some info from the application func cmdInfo(c *cli.Context) error { res := client.InfoSync() - printResponse(res, string(res.Data), false) + printResponse(c, res, string(res.Data), false) return nil } @@ -185,7 +193,7 @@ func cmdSetOption(c *cli.Context) error { return errors.New("Command set_option takes 2 arguments (key, value)") } res := client.SetOptionSync(args[0], args[1]) - printResponse(res, Fmt("%s=%s", args[0], args[1]), false) + printResponse(c, res, Fmt("%s=%s", args[0], args[1]), false) return nil } @@ -197,7 +205,7 @@ func cmdAppendTx(c *cli.Context) error { } txBytes := stringOrHexToBytes(c.Args()[0]) res := client.AppendTxSync(txBytes) - printResponse(res, string(res.Data), true) + printResponse(c, res, string(res.Data), true) return nil } @@ -209,14 +217,14 @@ func cmdCheckTx(c *cli.Context) error { } txBytes := stringOrHexToBytes(c.Args()[0]) res := client.CheckTxSync(txBytes) - printResponse(res, string(res.Data), true) + printResponse(c, res, string(res.Data), true) return nil } // Get application Merkle root hash func cmdCommit(c *cli.Context) error { res := client.CommitSync() - printResponse(res, Fmt("%X", res.Data), false) + printResponse(c, res, Fmt("%X", res.Data), false) return nil } @@ -228,13 +236,17 @@ func cmdQuery(c *cli.Context) error { } queryBytes := stringOrHexToBytes(c.Args()[0]) res := client.QuerySync(queryBytes) - printResponse(res, string(res.Data), true) + printResponse(c, res, string(res.Data), true) return nil } //-------------------------------------------------------------------------------- -func printResponse(res types.Result, s string, printCode bool) { +func printResponse(c *cli.Context, res types.Result, s string, printCode bool) { + if c.GlobalBool("verbose") { + fmt.Println(">", c.Command.Name, strings.Join(c.Args(), " ")) + } + if printCode { fmt.Printf("-> code: %s\n", res.Code.String()) } @@ -248,6 +260,10 @@ func printResponse(res types.Result, s string, printCode bool) { fmt.Printf("-> log: %s\n", res.Log) } + if c.GlobalBool("verbose") { + fmt.Println("") + } + } // NOTE: s is interpreted as a string unless prefixed with 0x From 3b329039d8b0dfaf5bfaf24724e2bd9d68d3c581 Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Sat, 23 Jul 2016 18:54:58 -0400 Subject: [PATCH 6/7] better testing. cli test for tutorial --- Makefile | 2 +- README.md | 3 +- tests/test.sh | 8 +++ .../test_counter.go => test_app/app.go} | 62 ++++--------------- tests/test_app/main.go | 48 ++++++++++++++ tests/test_app/test.sh | 17 +++++ tests/test_cli/ex1.tmsp | 10 +++ tests/test_cli/ex1.tmsp.out | 31 ++++++++++ tests/test_cli/ex2.tmsp | 8 +++ tests/test_cli/ex2.tmsp.out | 26 ++++++++ tests/test_cli/test.sh | 29 +++++++++ tests/test_counter/test.sh | 14 ----- 12 files changed, 191 insertions(+), 67 deletions(-) create mode 100644 tests/test.sh rename tests/{test_counter/test_counter.go => test_app/app.go} (51%) create mode 100644 tests/test_app/main.go create mode 100755 tests/test_app/test.sh create mode 100644 tests/test_cli/ex1.tmsp create mode 100644 tests/test_cli/ex1.tmsp.out create mode 100644 tests/test_cli/ex2.tmsp create mode 100644 tests/test_cli/ex2.tmsp.out create mode 100644 tests/test_cli/test.sh delete mode 100755 tests/test_counter/test.sh diff --git a/Makefile b/Makefile index 0f8adc5b6..b47dc0e21 100644 --- a/Makefile +++ b/Makefile @@ -10,7 +10,7 @@ install: get_deps test: go test github.com/tendermint/tmsp/... - bash tests/test_counter/test.sh + bash tests/test.sh get_deps: go get -d github.com/tendermint/tmsp/... diff --git a/README.md b/README.md index 11559c9ac..ba7513833 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ This repository holds a number of important pieces: - `types/types.proto` - the protobuf file definig TMSP message types, and the optional grpc interface. - - use `protoc --go_out=plugins=grpc:./types types/types.proto` to generate the `types/types.pb.go` file + - use `protoc --go_out=plugins=grpc:. types.proto` to from the `types` dir to generate the `types/types.pb.go` file - see `protoc --help` and [the grpc docs](www.grpc.io/docs) for examples and details of other languages - golang implementation of TMSP client and server @@ -29,6 +29,7 @@ This repository holds a number of important pieces: - `cmd/tmsp-cli` - command line tool wrapping the client for probing/testing a TMSP application + - use `tmsp-cli --version` to get the TMSP version - examples: - the `cmd/counter` application, which illustrates nonce checking in txs diff --git a/tests/test.sh b/tests/test.sh new file mode 100644 index 000000000..4087cdceb --- /dev/null +++ b/tests/test.sh @@ -0,0 +1,8 @@ +#! /bin/bash + +# test the counter using a go test script +bash tests/test_app/test.sh + +# test the cli against the examples in the tutorial at tendermint.com +bash tests/test_cli/test.sh + diff --git a/tests/test_counter/test_counter.go b/tests/test_app/app.go similarity index 51% rename from tests/test_counter/test_counter.go rename to tests/test_app/app.go index 2f78b6964..2a1bf15ad 100644 --- a/tests/test_counter/test_counter.go +++ b/tests/test_app/app.go @@ -2,8 +2,6 @@ package main import ( "bytes" - "flag" - "fmt" "os" "time" @@ -13,57 +11,19 @@ import ( "github.com/tendermint/tmsp/types" ) -var tmspPtr = flag.String("tmsp", "socket", "socket or grpc") - -func main() { - flag.Parse() - - // Run tests - testBasic() - - fmt.Println("Success!") -} - -func testBasic() { - fmt.Println("Running basic tests") - appProc := startApp() - defer appProc.StopProcess(true) - client := startClient() - defer client.Stop() - - setOption(client, "serial", "on") - commit(client, nil) - appendTx(client, []byte("abc"), types.CodeType_BadNonce, nil) - commit(client, nil) - appendTx(client, []byte{0x00}, types.CodeType_OK, nil) - commit(client, []byte{0, 0, 0, 0, 0, 0, 0, 1}) - appendTx(client, []byte{0x00}, types.CodeType_BadNonce, nil) - appendTx(client, []byte{0x01}, types.CodeType_OK, nil) - appendTx(client, []byte{0x00, 0x02}, types.CodeType_OK, nil) - appendTx(client, []byte{0x00, 0x03}, types.CodeType_OK, nil) - appendTx(client, []byte{0x00, 0x00, 0x04}, types.CodeType_OK, nil) - appendTx(client, []byte{0x00, 0x00, 0x06}, types.CodeType_BadNonce, nil) - commit(client, []byte{0, 0, 0, 0, 0, 0, 0, 5}) -} - //---------------------------------------- -func startApp() *process.Process { - counterApp := os.Getenv("COUNTER_APP") - if counterApp == "" { - panic("No COUNTER_APP specified") - } - +func StartApp(tmspApp string) *process.Process { // Start the app //outBuf := NewBufferCloser(nil) - proc, err := process.StartProcess("counter_app", + proc, err := process.StartProcess("tmsp_app", "bash", - []string{"-c", counterApp}, + []string{"-c", tmspApp}, nil, os.Stdout, ) if err != nil { - panic("running counter_app: " + err.Error()) + panic("running tmsp_app: " + err.Error()) } // TODO a better way to handle this? @@ -72,16 +32,16 @@ func startApp() *process.Process { return proc } -func startClient() tmspcli.Client { +func StartClient(tmspType string) tmspcli.Client { // Start client - client, err := tmspcli.NewClient("tcp://127.0.0.1:46658", *tmspPtr, true) + client, err := tmspcli.NewClient("tcp://127.0.0.1:46658", tmspType, true) if err != nil { - panic("connecting to counter_app: " + err.Error()) + panic("connecting to tmsp_app: " + err.Error()) } return client } -func setOption(client tmspcli.Client, key, value string) { +func SetOption(client tmspcli.Client, key, value string) { res := client.SetOptionSync(key, value) _, _, log := res.Code, res.Data, res.Log if res.IsErr() { @@ -89,7 +49,7 @@ func setOption(client tmspcli.Client, key, value string) { } } -func commit(client tmspcli.Client, hashExp []byte) { +func Commit(client tmspcli.Client, hashExp []byte) { res := client.CommitSync() _, data, log := res.Code, res.Data, res.Log if res.IsErr() { @@ -101,7 +61,7 @@ func commit(client tmspcli.Client, hashExp []byte) { } } -func appendTx(client tmspcli.Client, txBytes []byte, codeExp types.CodeType, dataExp []byte) { +func AppendTx(client tmspcli.Client, txBytes []byte, codeExp types.CodeType, dataExp []byte) { res := client.AppendTxSync(txBytes) code, data, log := res.Code, res.Data, res.Log if code != codeExp { @@ -114,7 +74,7 @@ func appendTx(client tmspcli.Client, txBytes []byte, codeExp types.CodeType, dat } } -func checkTx(client tmspcli.Client, txBytes []byte, codeExp types.CodeType, dataExp []byte) { +func CheckTx(client tmspcli.Client, txBytes []byte, codeExp types.CodeType, dataExp []byte) { res := client.CheckTxSync(txBytes) code, data, log := res.Code, res.Data, res.Log if res.IsErr() { diff --git a/tests/test_app/main.go b/tests/test_app/main.go new file mode 100644 index 000000000..ada637181 --- /dev/null +++ b/tests/test_app/main.go @@ -0,0 +1,48 @@ +package main + +import ( + "fmt" + "os" + + "github.com/tendermint/tmsp/types" +) + +var tmspType string + +func init() { + tmspType = os.Getenv("TMSP") + if tmspType == "" { + tmspType = "socket" + } +} + +func main() { + testCounter() +} + +func testCounter() { + tmspApp := os.Getenv("TMSP_APP") + if tmspApp == "" { + panic("No TMSP_APP specified") + } + + fmt.Printf("Running %s test with tmsp=%s\n", tmspApp, tmspType) + appProc := StartApp(tmspApp) + defer appProc.StopProcess(true) + client := StartClient(tmspType) + defer client.Stop() + + SetOption(client, "serial", "on") + Commit(client, nil) + AppendTx(client, []byte("abc"), types.CodeType_BadNonce, nil) + Commit(client, nil) + AppendTx(client, []byte{0x00}, types.CodeType_OK, nil) + Commit(client, []byte{0, 0, 0, 0, 0, 0, 0, 1}) + AppendTx(client, []byte{0x00}, types.CodeType_BadNonce, nil) + AppendTx(client, []byte{0x01}, types.CodeType_OK, nil) + AppendTx(client, []byte{0x00, 0x02}, types.CodeType_OK, nil) + AppendTx(client, []byte{0x00, 0x03}, types.CodeType_OK, nil) + AppendTx(client, []byte{0x00, 0x00, 0x04}, types.CodeType_OK, nil) + AppendTx(client, []byte{0x00, 0x00, 0x06}, types.CodeType_BadNonce, nil) + Commit(client, []byte{0, 0, 0, 0, 0, 0, 0, 5}) +} diff --git a/tests/test_app/test.sh b/tests/test_app/test.sh new file mode 100755 index 000000000..4c28a831b --- /dev/null +++ b/tests/test_app/test.sh @@ -0,0 +1,17 @@ +#! /bin/bash +set -e + +# These tests spawn the counter app and server by execing the TMSP_APP command and run some simple client tests against it + +ROOT=$GOPATH/src/github.com/tendermint/tmsp/tests/test_app +cd $ROOT + +# test golang counter +TMSP_APP="counter" go run *.go + +# test golang counter via grpc +TMSP_APP="counter -tmsp=grpc" TMSP="grpc" go run *.go + +# test nodejs counter +# TODO: fix node app +#TMSP_APP="node $GOPATH/src/github.com/tendermint/js-tmsp/example/app.js" go test -test.run TestCounter diff --git a/tests/test_cli/ex1.tmsp b/tests/test_cli/ex1.tmsp new file mode 100644 index 000000000..de61c8b2f --- /dev/null +++ b/tests/test_cli/ex1.tmsp @@ -0,0 +1,10 @@ +echo hello +info +commit +append_tx abc +info +commit +query abc +append_tx def=xyz +commit +query def diff --git a/tests/test_cli/ex1.tmsp.out b/tests/test_cli/ex1.tmsp.out new file mode 100644 index 000000000..89bd61c2f --- /dev/null +++ b/tests/test_cli/ex1.tmsp.out @@ -0,0 +1,31 @@ +> echo hello +-> data: {hello} + +> info +-> data: {size:0} + +> commit + +> append_tx abc +-> code: OK + +> info +-> data: {size:1} + +> commit +-> data: {750502FC7E84BBD788ED589624F06CFA871845D1} + +> query abc +-> code: OK +-> data: {Index=0 value=abc exists=true} + +> append_tx def=xyz +-> code: OK + +> commit +-> data: {76393B8A182E450286B0694C629ECB51B286EFD5} + +> query def +-> code: OK +-> data: {Index=1 value=xyz exists=true} + diff --git a/tests/test_cli/ex2.tmsp b/tests/test_cli/ex2.tmsp new file mode 100644 index 000000000..e9550db80 --- /dev/null +++ b/tests/test_cli/ex2.tmsp @@ -0,0 +1,8 @@ +set_option serial on +check_tx 0x00 +check_tx 0xff +append_tx 0x00 +check_tx 0x00 +append_tx 0x01 +append_tx 0x04 +info diff --git a/tests/test_cli/ex2.tmsp.out b/tests/test_cli/ex2.tmsp.out new file mode 100644 index 000000000..3aa7744bb --- /dev/null +++ b/tests/test_cli/ex2.tmsp.out @@ -0,0 +1,26 @@ +> set_option serial on +-> data: {serial=on} + +> check_tx 0x00 +-> code: OK + +> check_tx 0xff +-> code: OK + +> append_tx 0x00 +-> code: OK + +> check_tx 0x00 +-> code: BadNonce +-> log: Invalid nonce. Expected >= 1, got 0 + +> append_tx 0x01 +-> code: OK + +> append_tx 0x04 +-> code: BadNonce +-> log: Invalid nonce. Expected 2, got 4 + +> info +-> data: {hashes:0, txs:2} + diff --git a/tests/test_cli/test.sh b/tests/test_cli/test.sh new file mode 100644 index 000000000..f8920958a --- /dev/null +++ b/tests/test_cli/test.sh @@ -0,0 +1,29 @@ +#! /bin/bash + +function testExample() { + N=$1 + INPUT=$2 + APP=$3 + + echo "Example $N" + $APP &> /dev/null & + sleep 2 + tmsp-cli --verbose batch < $INPUT > "${INPUT}.out.new" + killall "$APP" > /dev/null + + pre=`shasum < "${INPUT}.out"` + post=`shasum < "${INPUT}.out.new"` + + if [[ "$pre" != "$post" ]]; then + echo "You broke the tutorial" + exit 1 + fi + + rm "${INPUT}".out.new +} + +testExample 1 tests/test_cli/ex1.tmsp dummy +testExample 2 tests/test_cli/ex2.tmsp counter + +echo "" +echo "PASS" diff --git a/tests/test_counter/test.sh b/tests/test_counter/test.sh deleted file mode 100755 index 4883a5e0e..000000000 --- a/tests/test_counter/test.sh +++ /dev/null @@ -1,14 +0,0 @@ -# These tests spawn the counter app and server by execing the COUNTER_APP command and run some simple client tests against it - -ROOT=$GOPATH/src/github.com/tendermint/tmsp/tests/test_counter -cd $ROOT - -# test golang counter -COUNTER_APP="counter" go run test_counter.go - -# test golang counter via grpc -COUNTER_APP="counter -tmsp=grpc" go run test_counter.go -tmsp=grpc - -# test nodejs counter -# TODO: fix node app -#COUNTER_APP="node $GOPATH/src/github.com/tendermint/js-tmsp/example/app.js" go run test_counter.go From fbbf82ec64c338bf9f66ad43b5d0c32d807ddcda Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Sat, 23 Jul 2016 19:05:46 -0400 Subject: [PATCH 7/7] update README.md --- README.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index ba7513833..fc5c7bb22 100644 --- a/README.md +++ b/README.md @@ -17,13 +17,14 @@ Other implementations: This repository holds a number of important pieces: - `types/types.proto` - - the protobuf file definig TMSP message types, and the optional grpc interface. - - use `protoc --go_out=plugins=grpc:. types.proto` to from the `types` dir to generate the `types/types.pb.go` file - - see `protoc --help` and [the grpc docs](www.grpc.io/docs) for examples and details of other languages + - the protobuf file defining TMSP message types, and the optional grpc interface. + - run `protoc --go_out=plugins=grpc:. types.proto` in the `types` dir to generate the `types/types.pb.go` file + - see `protoc --help` and [the grpc docs](https://www.grpc.io/docs) for examples and details of other languages - golang implementation of TMSP client and server - two implementations: - - asynchronous, ordered message passing over unix or tcp + - asynchronous, ordered message passing over unix or tcp; + - messages are serialized using protobuf and length prefixed - grpc - TendermintCore runs a client, and the application runs a server @@ -42,6 +43,8 @@ Since this is a streaming protocol, all messages are encoded with a length-prefi For example, if the Protobuf3 encoded TMSP message is `0xDEADBEEF` (4 bytes), the length-prefixed message is `0x0104DEADBEEF`. If the Protobuf3 encoded TMSP message is 65535 bytes long, the length-prefixed message would be like `0x02FFFF...`. +Note this prefixing does not apply for grpc. + ## Message types TMSP requests/responses are simple Protobuf messages. Check out the [schema file](https://github.com/tendermint/tmsp/blob/master/types/types.proto).