From 8273880b053069814c5558873fe840accce61a7f Mon Sep 17 00:00:00 2001 From: Silas Davis <silas@monax.io> Date: Tue, 26 Jun 2018 18:31:53 +0100 Subject: [PATCH] Add substantive tests for EventsServer Signed-off-by: Silas Davis <silas@monax.io> --- Makefile | 1 + binary/word256.go | 1 - .../integration/events_server_test.go | 121 ++++++++++++------ .../integration/transactor_server_test.go | 33 +---- rpc/test/helpers.go | 40 ++++++ rpc/test/strange_loop.go | 2 +- rpc/test/strange_loop.sh | 2 +- rpc/test/strange_loop.sol | 6 + rpc/v0/integration/v0_test.go | 13 +- 9 files changed, 137 insertions(+), 82 deletions(-) diff --git a/Makefile b/Makefile index c7b33d45..2a40f335 100644 --- a/Makefile +++ b/Makefile @@ -175,6 +175,7 @@ test_keys: build_db .PHONY: test_integration test_integration: test_keys + @go test -tags integration ./rpc/rpcevents/integration @go test -tags integration ./rpc/rpctransactor/integration @go test -tags integration ./rpc/v0/integration @go test -tags integration ./rpc/tm/integration diff --git a/binary/word256.go b/binary/word256.go index bd2e5630..7d69e600 100644 --- a/binary/word256.go +++ b/binary/word256.go @@ -123,7 +123,6 @@ func Uint64FromWord256(word Word256) uint64 { } func Int64FromWord256(word Word256) int64 { - buf := word.Postfix(8) return GetInt64BE(buf) } diff --git a/rpc/rpcevents/integration/events_server_test.go b/rpc/rpcevents/integration/events_server_test.go index add06753..4d2e3152 100644 --- a/rpc/rpcevents/integration/events_server_test.go +++ b/rpc/rpcevents/integration/events_server_test.go @@ -19,69 +19,110 @@ package integration import ( "context" - "encoding/json" "testing" "time" + "encoding/json" + + "github.com/hyperledger/burrow/binary" + "github.com/hyperledger/burrow/crypto" + "github.com/hyperledger/burrow/execution/events" "github.com/hyperledger/burrow/execution/events/pbevents" - "github.com/hyperledger/burrow/execution/pbtransactor" "github.com/hyperledger/burrow/rpc" "github.com/hyperledger/burrow/rpc/test" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" tmTypes "github.com/tendermint/tendermint/types" - "github.com/tmthrgd/go-hex" ) -func TestEventSubscribe(t *testing.T) { - cli := test.NewEventsClient(t) - sub, err := cli.EventSubscribe(context.Background(), &pbevents.EventIdParam{ - EventId: tmTypes.EventNewBlock, - }) - require.NoError(t, err) - defer cli.EventUnsubscribe(context.Background(), sub) +const eventWait = 2 * time.Second - pollCh := make(chan *pbevents.PollResponse) - go func() { - poll := new(pbevents.PollResponse) - for len(poll.Events) == 0 { - poll, err = cli.EventPoll(context.Background(), sub) - require.NoError(t, err) - time.Sleep(1) - } - pollCh <- poll - }() - select { - case poll := <-pollCh: - require.True(t, len(poll.Events) > 0, "event poll should return at least 1 event") +func TestEventSubscribeNewBlock(t *testing.T) { + testEventSubscribe(t, tmTypes.EventNewBlock, nil, func(evs []*pbevents.Event) { + require.True(t, len(evs) > 0, "event poll should return at least 1 event") tendermintEvent := new(rpc.TendermintEvent) - tendermintEventJSON := poll.Events[0].GetTendermintEventJSON() + tendermintEventJSON := evs[0].GetTendermintEventJSON() require.NoError(t, json.Unmarshal([]byte(tendermintEventJSON), tendermintEvent)) newBlock, ok := tendermintEvent.TMEventData.(tmTypes.EventDataNewBlock) require.True(t, ok, "new block event expected") assert.Equal(t, genesisDoc.ChainID(), newBlock.Block.ChainID) - case <-time.After(3 * time.Second): - t.Fatal("timed out waiting for poll event") - } + }) } -func testEventsCall(t *testing.T, numTxs int) { +func TestEventSubscribeCall(t *testing.T) { cli := test.NewTransactorClient(t) + create := test.CreateContract(t, cli, inputAccount) + address, err := crypto.AddressFromBytes(create.CallData.Callee) + require.NoError(t, err) + testEventSubscribe(t, events.EventStringAccountCall(address), + func() { + t.Logf("Calling contract at: %v", address) + test.CallContract(t, cli, inputAccount, address.Bytes()) + }, + func(evs []*pbevents.Event) { + require.Len(t, evs, test.UpsieDownsieCallCount, "should see 30 recursive call events") + for i, ev := range evs { + assert.Equal(t, uint64(test.UpsieDownsieCallCount-i-1), ev.GetExecutionEvent().GetEventDataCall().GetStackDepth()) + } + }) +} - bc, err := hex.DecodeString(test.StrangeLoopByteCode) +func TestEventSubscribeLog(t *testing.T) { + cli := test.NewTransactorClient(t) + create := test.CreateContract(t, cli, inputAccount) + address, err := crypto.AddressFromBytes(create.CallData.Callee) + require.NoError(t, err) + testEventSubscribe(t, events.EventStringLogEvent(address), + func() { + t.Logf("Calling contract at: %v", address) + test.CallContract(t, cli, inputAccount, address.Bytes()) + }, + func(evs []*pbevents.Event) { + require.Len(t, evs, test.UpsieDownsieCallCount-2) + log := evs[0].GetExecutionEvent().GetEventDataLog() + depth := binary.Int64FromWord256(binary.LeftPadWord256(log.Topics[1])) + payload := string(log.Data) + assert.Equal(t, int64(18), depth) + assert.Contains(t, payload, "Upsie!") + }) +} +func testEventSubscribe(t *testing.T, eventID string, runner func(), eventsCallback func(evs []*pbevents.Event)) { + cli := test.NewEventsClient(t) + t.Logf("Subscribing to event: %s", eventID) + sub, err := cli.EventSubscribe(context.Background(), &pbevents.EventIdParam{ + EventId: eventID, + }) require.NoError(t, err) + defer cli.EventUnsubscribe(context.Background(), sub) - countCh := test.CommittedTxCount(t, kern.Emitter) - for i := 0; i < numTxs; i++ { - _, err := cli.Transact(context.Background(), &pbtransactor.TransactParam{ - InputAccount: inputAccount, - Address: nil, - Data: bc, - Fee: 2, - GasLimit: 10000, - }) - require.NoError(t, err) + if runner != nil { + go runner() + } + + pollCh := make(chan *pbevents.PollResponse) + errCh := make(chan error) + // Catch a single block of events + go func() { + for { + time.Sleep(eventWait) + poll, err := cli.EventPoll(context.Background(), sub) + if err != nil { + errCh <- err + return + } + if len(poll.Events) > 0 { + pollCh <- poll + } + } + }() + //var evs []*pbevents.Event + select { + case err := <-errCh: + require.NoError(t, err, "should be no error from EventPoll") + case poll := <-pollCh: + eventsCallback(poll.Events) + case <-time.After(2 * eventWait): + t.Fatal("timed out waiting for poll event") } - require.Equal(t, numTxs, <-countCh) } diff --git a/rpc/rpctransactor/integration/transactor_server_test.go b/rpc/rpctransactor/integration/transactor_server_test.go index 9eb2ca6b..c48cb128 100644 --- a/rpc/rpctransactor/integration/transactor_server_test.go +++ b/rpc/rpctransactor/integration/transactor_server_test.go @@ -19,12 +19,10 @@ package integration import ( "context" - "encoding/hex" "sync" "testing" "github.com/hyperledger/burrow/binary" - "github.com/hyperledger/burrow/execution/evm/abi" "github.com/hyperledger/burrow/execution/pbtransactor" "github.com/hyperledger/burrow/rpc" "github.com/hyperledger/burrow/rpc/test" @@ -62,9 +60,6 @@ func TestTransactCreate(t *testing.T) { numCreates := 50 wg := new(sync.WaitGroup) wg.Add(numGoroutines) - // Flip flops between sending private key and input address to test private key and address based signing - bc, err := hex.DecodeString(test.StrangeLoopByteCode) - require.NoError(t, err) countCh := test.CommittedTxCount(t, kern.Emitter) for i := 0; i < numGoroutines; i++ { go func() { @@ -72,7 +67,7 @@ func TestTransactCreate(t *testing.T) { create, err := cli.Transact(context.Background(), &pbtransactor.TransactParam{ InputAccount: inputAccount(i), Address: nil, - Data: bc, + Data: test.StrangeLoopBytecode, Fee: 2, GasLimit: 10000, }) @@ -90,13 +85,11 @@ func TestTransactCreate(t *testing.T) { func BenchmarkTransactCreateContract(b *testing.B) { cli := newClient(b) - bc, err := hex.DecodeString(test.StrangeLoopByteCode) - require.NoError(b, err) for i := 0; i < b.N; i++ { create, err := cli.Transact(context.Background(), &pbtransactor.TransactParam{ InputAccount: inputAccount(i), Address: nil, - Data: bc, + Data: test.StrangeLoopBytecode, Fee: 2, GasLimit: 10000, }) @@ -107,31 +100,13 @@ func BenchmarkTransactCreateContract(b *testing.B) { func TestTransactAndHold(t *testing.T) { cli := newClient(t) - bc, err := hex.DecodeString(test.StrangeLoopByteCode) - require.NoError(t, err) numGoroutines := 5 numRuns := 2 countCh := test.CommittedTxCount(t, kern.Emitter) for i := 0; i < numGoroutines; i++ { for j := 0; j < numRuns; j++ { - create, err := cli.TransactAndHold(context.Background(), &pbtransactor.TransactParam{ - InputAccount: inputAccount(i), - Address: nil, - Data: bc, - Fee: 2, - GasLimit: 10000, - }) - require.NoError(t, err) - assert.Equal(t, uint64(0), create.StackDepth) - functionID := abi.FunctionID("UpsieDownsie()") - call, err := cli.TransactAndHold(context.Background(), &pbtransactor.TransactParam{ - InputAccount: inputAccount(i), - Address: create.CallData.Callee, - Data: functionID[:], - Fee: 2, - GasLimit: 10000, - }) - require.NoError(t, err) + create := test.CreateContract(t, cli, inputAccount(i)) + call := test.CallContract(t, cli, inputAccount(i), create.CallData.Callee) depth := binary.Uint64FromWord256(binary.LeftPadWord256(call.Return)) // Would give 23 if taken from wrong frame assert.Equal(t, 18, int(depth)) diff --git a/rpc/test/helpers.go b/rpc/test/helpers.go index b04a6e27..18ded24e 100644 --- a/rpc/test/helpers.go +++ b/rpc/test/helpers.go @@ -7,12 +7,22 @@ import ( "github.com/hyperledger/burrow/consensus/tendermint" "github.com/hyperledger/burrow/event" "github.com/hyperledger/burrow/execution/events/pbevents" + "github.com/hyperledger/burrow/execution/evm/abi" "github.com/hyperledger/burrow/execution/pbtransactor" "github.com/hyperledger/burrow/rpc" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/tmthrgd/go-hex" "google.golang.org/grpc" ) +var StrangeLoopBytecode = hex.MustDecodeString(strangeLoopBytecodeHex) + +// Recursive call count for UpsieDownsie() function call from strange_loop.sol +// Equals initial call, then depth from 17 -> 34, one for the bounce, then depth from 34 -> 23, +// so... (I didn't say it had to make sense): +const UpsieDownsieCallCount = 1 + (34 - 17) + 1 + (34 - 23) + // Helpers func NewTransactorClient(t testing.TB) pbtransactor.TransactorClient { conn, err := grpc.Dial(rpc.DefaultGRPCConfig().ListenAddress, grpc.WithInsecure()) @@ -58,3 +68,33 @@ func CommittedTxCount(t *testing.T, em event.Emitter) chan int { }() return outCh } + +func CreateContract(t testing.TB, cli pbtransactor.TransactorClient, + inputAccount *pbtransactor.InputAccount) *pbevents.EventDataCall { + + create, err := cli.TransactAndHold(context.Background(), &pbtransactor.TransactParam{ + InputAccount: inputAccount, + Address: nil, + Data: StrangeLoopBytecode, + Fee: 2, + GasLimit: 10000, + }) + require.NoError(t, err) + assert.Equal(t, uint64(0), create.StackDepth) + return create +} + +func CallContract(t testing.TB, cli pbtransactor.TransactorClient, + inputAccount *pbtransactor.InputAccount, contractAddress []byte) (call *pbevents.EventDataCall) { + + functionID := abi.FunctionID("UpsieDownsie()") + call, err := cli.TransactAndHold(context.Background(), &pbtransactor.TransactParam{ + InputAccount: inputAccount, + Address: contractAddress, + Data: functionID[:], + Fee: 2, + GasLimit: 10000, + }) + require.NoError(t, err) + return call +} diff --git a/rpc/test/strange_loop.go b/rpc/test/strange_loop.go index 7d30938f..10590c4f 100644 --- a/rpc/test/strange_loop.go +++ b/rpc/test/strange_loop.go @@ -1,3 +1,3 @@ package test -const StrangeLoopByteCode = "60606040526017600055602260015560116002556001600360006101000a81548160ff021916908315150217905550341561003957600080fd5b6102c9806100486000396000f300606060405260043610610041576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063ebb384dd14610046575b600080fd5b341561005157600080fd5b61005961006f565b6040518082815260200191505060405180910390f35b60006002549050600360009054906101000a900460ff16156101cf57600154600254121561012e5760026000815480929190600101919050555060025490503073ffffffffffffffffffffffffffffffffffffffff1663ebb384dd6040518163ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401602060405180830381600087803b151561011157600080fd5b5af1151561011e57600080fd5b50505060405180519050506101ca565b6000600360006101000a81548160ff02191690831515021790555060025490503073ffffffffffffffffffffffffffffffffffffffff1663ebb384dd6040518163ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401602060405180830381600087803b15156101b157600080fd5b5af115156101be57600080fd5b50505060405180519050505b610299565b6000546002541315610273576002600081548092919060019003919050555060025490503073ffffffffffffffffffffffffffffffffffffffff1663ebb384dd6040518163ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401602060405180830381600087803b151561025657600080fd5b5af1151561026357600080fd5b5050506040518051905050610298565b6001600360006101000a81548160ff021916908315150217905550600254905061029a565b5b5b905600a165627a7a7230582071446a8de59540361bd59bb4f5a84f884006f53e50c1c89d2bfbdb72f92fd4700029" +const strangeLoopBytecodeHex = "60606040526017600055602260015560116002556001600360006101000a81548160ff021916908315150217905550341561003957600080fd5b61039f806100486000396000f300606060405260043610610041576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063ebb384dd14610046575b600080fd5b341561005157600080fd5b61005961006f565b6040518082815260200191505060405180910390f35b60006002549050600360009054906101000a900460ff161561023a576001546002541215610199576002600081548092919060010191905055506002547f6488c53a044f5cc88f6f830b84ae7a701762a11b40a91eb0451a870b0f560a4b6040518080602001828103825260068152602001807f557073696521000000000000000000000000000000000000000000000000000081525060200191505060405180910390a260025490503073ffffffffffffffffffffffffffffffffffffffff1663ebb384dd6040518163ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401602060405180830381600087803b151561017c57600080fd5b5af1151561018957600080fd5b5050506040518051905050610235565b6000600360006101000a81548160ff02191690831515021790555060025490503073ffffffffffffffffffffffffffffffffffffffff1663ebb384dd6040518163ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401602060405180830381600087803b151561021c57600080fd5b5af1151561022957600080fd5b50505060405180519050505b61036f565b600054600254131561034957600260008154809291906001900391905055506002547f6488c53a044f5cc88f6f830b84ae7a701762a11b40a91eb0451a870b0f560a4b6040518080602001828103825260088152602001807f446f776e7369652100000000000000000000000000000000000000000000000081525060200191505060405180910390a260025490503073ffffffffffffffffffffffffffffffffffffffff1663ebb384dd6040518163ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401602060405180830381600087803b151561032c57600080fd5b5af1151561033957600080fd5b505050604051805190505061036e565b6001600360006101000a81548160ff0219169083151502179055506002549050610370565b5b5b905600a165627a7a7230582052e0533ea43cd4d1a18ebcfb80ad6d09e217a7615d9faf935ce110c467f7c0b80029" diff --git a/rpc/test/strange_loop.sh b/rpc/test/strange_loop.sh index d0cf04ee..edbdf044 100755 --- a/rpc/test/strange_loop.sh +++ b/rpc/test/strange_loop.sh @@ -2,4 +2,4 @@ script_dir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" -echo -e "package integration\n\nconst strangeLoopBytecode = \"$(solc --bin rpc/v0/integration/strange_loop.sol | tail -1)\"" > "${script_dir}/strange_loop.go" +echo -e "package test\n\nconst strangeLoopBytecodeHex = \"$(solc --bin "$script_dir/strange_loop.sol" | tail -1)\"" > "${script_dir}/strange_loop.go" diff --git a/rpc/test/strange_loop.sol b/rpc/test/strange_loop.sol index 2a3e07f2..5c2d0bc4 100644 --- a/rpc/test/strange_loop.sol +++ b/rpc/test/strange_loop.sol @@ -5,12 +5,17 @@ contract StrangeLoop { int bottom = 34; int depth = 17; bool down = true; + // indexed puts it in topic + event ChangeLevel( + string direction, + int indexed newDepth); function UpsieDownsie() public returns (int i) { i = depth; if (down) { if (depth < bottom) { depth++; + emit ChangeLevel("Upsie!", depth); i = depth; this.UpsieDownsie(); } else { @@ -20,6 +25,7 @@ contract StrangeLoop { } } else if (depth > top) { depth--; + emit ChangeLevel("Downsie!", depth); i = depth; this.UpsieDownsie(); } else { diff --git a/rpc/v0/integration/v0_test.go b/rpc/v0/integration/v0_test.go index 484e9dd9..3e57114c 100644 --- a/rpc/v0/integration/v0_test.go +++ b/rpc/v0/integration/v0_test.go @@ -18,7 +18,6 @@ package integration import ( - "encoding/hex" "sync" "testing" @@ -60,8 +59,6 @@ func TestTransactCreate(t *testing.T) { wg.Add(numGoroutines) cli := v0.NewV0Client("http://localhost:1337/rpc") // Flip flops between sending private key and input address to test private key and address based signing - bc, err := hex.DecodeString(test.StrangeLoopByteCode) - require.NoError(t, err) countCh := test.CommittedTxCount(t, kern.Emitter) for i := 0; i < numGoroutines; i++ { go func() { @@ -69,7 +66,7 @@ func TestTransactCreate(t *testing.T) { create, err := cli.Transact(v0.TransactParam{ InputAccount: inputAccount(i), Address: nil, - Data: bc, + Data: test.StrangeLoopBytecode, Fee: 2, GasLimit: 10000, }) @@ -88,13 +85,11 @@ func TestTransactCreate(t *testing.T) { func BenchmarkTransactCreateContract(b *testing.B) { cli := v0.NewV0Client("http://localhost:1337/rpc") - bc, err := hex.DecodeString(test.StrangeLoopByteCode) - require.NoError(b, err) for i := 0; i < b.N; i++ { create, err := cli.Transact(v0.TransactParam{ InputAccount: inputAccount(i), Address: nil, - Data: bc, + Data: test.StrangeLoopBytecode, Fee: 2, GasLimit: 10000, }) @@ -105,8 +100,6 @@ func BenchmarkTransactCreateContract(b *testing.B) { func TestTransactAndHold(t *testing.T) { cli := v0.NewV0Client("http://localhost:1337/rpc") - bc, err := hex.DecodeString(test.StrangeLoopByteCode) - require.NoError(t, err) numGoroutines := 5 numRuns := 2 @@ -116,7 +109,7 @@ func TestTransactAndHold(t *testing.T) { create, err := cli.TransactAndHold(v0.TransactParam{ InputAccount: inputAccount(i), Address: nil, - Data: bc, + Data: test.StrangeLoopBytecode, Fee: 2, GasLimit: 10000, }) -- GitLab