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