Skip to content

Commit

Permalink
replace manual evm rpc mock with mockery generated mock
Browse files Browse the repository at this point in the history
  • Loading branch information
ws4charlie committed Sep 11, 2024
1 parent c0d19c9 commit 19699f3
Show file tree
Hide file tree
Showing 13 changed files with 828 additions and 216 deletions.
85 changes: 58 additions & 27 deletions zetaclient/chains/evm/observer/inbound_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@ package observer_test
import (
"context"
"encoding/hex"
"errors"
"testing"

ethcommon "github.com/ethereum/go-ethereum/common"
ethtypes "github.com/ethereum/go-ethereum/core/types"
"github.com/onrik/ethrpc"
"github.com/rs/zerolog"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
zctx "github.com/zeta-chain/node/zetaclient/context"
"github.com/zeta-chain/node/zetaclient/keys"
Expand All @@ -17,6 +19,7 @@ import (
"github.com/zeta-chain/node/pkg/coin"
"github.com/zeta-chain/node/pkg/constant"
"github.com/zeta-chain/node/zetaclient/chains/evm"
"github.com/zeta-chain/node/zetaclient/chains/interfaces"
"github.com/zeta-chain/node/zetaclient/config"
"github.com/zeta-chain/node/zetaclient/testutils"
"github.com/zeta-chain/node/zetaclient/testutils/mocks"
Expand Down Expand Up @@ -461,42 +464,70 @@ func Test_ObserveTSSReceiveInBlock(t *testing.T) {
blockNumber := receipt.BlockNumber.Uint64()
block := testutils.LoadEVMBlock(t, TestDataDir, chainID, blockNumber, true)

// create mock client
evmClient := mocks.NewMockEvmClient()
evmJSONRPC := mocks.NewMockJSONRPCClient()
// create mock zetacore client
tss := mocks.NewTSSMainnet()
lastBlock := receipt.BlockNumber.Uint64() + confirmation

zetacoreClient := mocks.NewZetacoreClient(t).
WithKeys(&keys.Keys{}).
WithZetaChain().
WithPostVoteInbound("", "").
WithPostVoteInbound("", "")

ctx := context.Background()

t.Run("should observe TSS receive in block", func(t *testing.T) {
ob, _ := MockEVMObserver(t, chain, evmClient, evmJSONRPC, zetacoreClient, tss, lastBlock, chainParam)
// test cases
tests := []struct {
name string
evmClient interfaces.EVMRPCClient
jsonClient interfaces.EVMJSONRPCClient
errMsg string
}{
{
name: "should observe TSS receive in block",
evmClient: func() interfaces.EVMRPCClient {
// feed block number and receipt to mock client
evmClient := mocks.NewEVMRPCClient(t)
evmClient.On("BlockNumber", mock.Anything).Return(uint64(1000), nil)
evmClient.On("TransactionReceipt", mock.Anything, mock.Anything).Return(receipt, nil)
return evmClient
}(),
jsonClient: mocks.NewMockJSONRPCClient().WithBlock(block),
errMsg: "",
},
{
name: "should not observe on error getting block",
evmClient: func() interfaces.EVMRPCClient {
// feed block number to allow construction of observer
evmClient := mocks.NewEVMRPCClient(t)
evmClient.On("BlockNumber", mock.Anything).Return(uint64(1000), nil)
return evmClient
}(),
jsonClient: mocks.NewMockJSONRPCClient(), // no block
errMsg: "error getting block",
},
{
name: "should not observe on error getting receipt",
evmClient: func() interfaces.EVMRPCClient {
// feed block number but RPC error on getting receipt
evmClient := mocks.NewEVMRPCClient(t)
evmClient.On("BlockNumber", mock.Anything).Return(uint64(1000), nil)
evmClient.On("TransactionReceipt", mock.Anything, mock.Anything).Return(nil, errors.New("RPC error"))
return evmClient
}(),
jsonClient: mocks.NewMockJSONRPCClient().WithBlock(block),
errMsg: "error getting receipt",
},
}

// feed archived block and receipt
evmJSONRPC.WithBlock(block)
evmClient.WithReceipt(receipt)
err := ob.ObserveTSSReceiveInBlock(ctx, blockNumber)
require.NoError(t, err)
})
t.Run("should not observe on error getting block", func(t *testing.T) {
ob, _ := MockEVMObserver(t, chain, evmClient, evmJSONRPC, zetacoreClient, tss, lastBlock, chainParam)
err := ob.ObserveTSSReceiveInBlock(ctx, blockNumber)
// error getting block is expected because the mock JSONRPC contains no block
require.ErrorContains(t, err, "error getting block")
})
t.Run("should not observe on error getting receipt", func(t *testing.T) {
ob, _ := MockEVMObserver(t, chain, evmClient, evmJSONRPC, zetacoreClient, tss, lastBlock, chainParam)
evmJSONRPC.WithBlock(block)
err := ob.ObserveTSSReceiveInBlock(ctx, blockNumber)
// error getting block is expected because the mock evmClient contains no receipt
require.ErrorContains(t, err, "error getting receipt")
})
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
ob, _ := MockEVMObserver(t, chain, tt.evmClient, tt.jsonClient, zetacoreClient, tss, lastBlock, chainParam)
err := ob.ObserveTSSReceiveInBlock(context.Background(), blockNumber)
if tt.errMsg != "" {
require.ErrorContains(t, err, tt.errMsg)
} else {
require.NoError(t, err)
}
})
}
}

func makeAppContext(t *testing.T) (context.Context, *zctx.AppContext) {
Expand Down
20 changes: 11 additions & 9 deletions zetaclient/chains/evm/observer/observer_gas_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ func TestPostGasPrice(t *testing.T) {
t.Run("Pre EIP-1559 doesn't support priorityFee", func(t *testing.T) {
// ARRANGE
// Given ETH rpc mock
ethRPC := mocks.NewMockEvmClient().WithBlockNumber(blockNumber)
ethRPC := mocks.NewEVMRPCClient(t)
ethRPC.On("BlockNumber", mock.Anything).Return(uint64(blockNumber), nil)

// Given zetacore client mock
zetacoreClient := mocks.NewZetacoreClient(t).WithZetaChain()
Expand All @@ -37,10 +38,11 @@ func TestPostGasPrice(t *testing.T) {
observer, _ := MockEVMObserver(t, chain, ethRPC, nil, zetacoreClient, nil, blockNumber, chainParam)

// Given empty baseFee from RPC
ethRPC.WithHeader(&ethtypes.Header{BaseFee: nil})
ethRPC.On("HeaderByNumber", anything, anything).Return(&ethtypes.Header{BaseFee: nil}, nil)

// Given gas price from RPC
ethRPC.WithSuggestGasPrice(big.NewInt(3 * gwei))
// Given gasPrice and priorityFee from RPC
ethRPC.On("SuggestGasPrice", anything).Return(big.NewInt(3*gwei), nil)
ethRPC.On("SuggestGasTipCap", anything).Return(big.NewInt(0), nil)

// Given mock collector for zetacore call
// PostVoteGasPrice(ctx, chain, gasPrice, priorityFee, blockNum)
Expand Down Expand Up @@ -69,7 +71,8 @@ func TestPostGasPrice(t *testing.T) {
t.Run("Post EIP-1559 supports priorityFee", func(t *testing.T) {
// ARRANGE
// Given ETH rpc mock
ethRPC := mocks.NewMockEvmClient().WithBlockNumber(blockNumber)
ethRPC := mocks.NewEVMRPCClient(t)
ethRPC.On("BlockNumber", mock.Anything).Return(uint64(blockNumber), nil)

// Given zetacore client mock
zetacoreClient := mocks.NewZetacoreClient(t).WithZetaChain()
Expand All @@ -82,12 +85,11 @@ func TestPostGasPrice(t *testing.T) {
observer, _ := MockEVMObserver(t, chain, ethRPC, nil, zetacoreClient, nil, blockNumber, chainParam)

// Given 1 gwei baseFee from RPC
ethRPC.WithHeader(&ethtypes.Header{BaseFee: big.NewInt(gwei)})
ethRPC.On("HeaderByNumber", anything, anything).Return(&ethtypes.Header{BaseFee: big.NewInt(gwei)}, nil)

// Given gasPrice and priorityFee from RPC
ethRPC.
WithSuggestGasPrice(big.NewInt(3 * gwei)).
WithSuggestGasTipCap(big.NewInt(2 * gwei))
ethRPC.On("SuggestGasPrice", anything).Return(big.NewInt(3*gwei), nil)
ethRPC.On("SuggestGasTipCap", anything).Return(big.NewInt(2*gwei), nil)

// Given mock collector for zetacore call
// PostVoteGasPrice(ctx, chain, gasPrice, priorityFee, blockNum)
Expand Down
48 changes: 32 additions & 16 deletions zetaclient/chains/evm/observer/observer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
lru "github.com/hashicorp/golang-lru"
"github.com/onrik/ethrpc"
"github.com/rs/zerolog"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
"github.com/zeta-chain/node/pkg/ptr"
zctx "github.com/zeta-chain/node/zetaclient/context"
Expand Down Expand Up @@ -97,7 +98,9 @@ func MockEVMObserver(

// use default mock evm client if not provided
if evmClient == nil {
evmClient = mocks.NewMockEvmClient().WithBlockNumber(1000)
evmClientDefault := mocks.NewEVMRPCClient(t)
evmClientDefault.On("BlockNumber", mock.Anything).Return(uint64(1000), nil)
evmClient = evmClientDefault
}

// use default mock zetacore client if not provided
Expand Down Expand Up @@ -137,6 +140,10 @@ func Test_NewObserver(t *testing.T) {
chain := chains.Ethereum
params := mocks.MockChainParams(chain.ChainId, 10)

// create evm client with mocked block number 1000
evmClient := mocks.NewEVMRPCClient(t)
evmClient.On("BlockNumber", mock.Anything).Return(uint64(1000), nil)

// test cases
tests := []struct {
name string
Expand All @@ -158,7 +165,7 @@ func Test_NewObserver(t *testing.T) {
Endpoint: "http://localhost:8545",
},
chainParams: params,
evmClient: mocks.NewMockEvmClient().WithBlockNumber(1000),
evmClient: evmClient,
tss: mocks.NewTSSMainnet(),
logger: base.Logger{},
ts: nil,
Expand All @@ -171,12 +178,17 @@ func Test_NewObserver(t *testing.T) {
Endpoint: "http://localhost:8545",
},
chainParams: params,
evmClient: mocks.NewMockEvmClient().WithError(fmt.Errorf("error RPC")),
tss: mocks.NewTSSMainnet(),
logger: base.Logger{},
ts: nil,
fail: true,
message: "error RPC",
evmClient: func() interfaces.EVMRPCClient {
// create mock evm client with RPC error
evmClient := mocks.NewEVMRPCClient(t)
evmClient.On("BlockNumber", mock.Anything).Return(uint64(0), fmt.Errorf("error RPC"))
return evmClient
}(),
tss: mocks.NewTSSMainnet(),
logger: base.Logger{},
ts: nil,
fail: true,
message: "error RPC",
},
{
name: "should fail on invalid ENV var",
Expand All @@ -185,7 +197,7 @@ func Test_NewObserver(t *testing.T) {
Endpoint: "http://localhost:8545",
},
chainParams: params,
evmClient: mocks.NewMockEvmClient().WithBlockNumber(1000),
evmClient: evmClient,
tss: mocks.NewTSSMainnet(),
before: func() {
envVar := base.EnvVarLatestBlockByChain(chain)
Expand All @@ -205,8 +217,7 @@ func Test_NewObserver(t *testing.T) {
// run tests
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// create AppContext, client and tss
//zetacoreCtx, _ := getAppContext(tt.evmCfg.Chain, tt.evmCfg.Endpoint, &params)
// create mock zetacore client
zetacoreClient := mocks.NewZetacoreClient(t)

database, err := db.NewFromSqliteInMemory(true)
Expand Down Expand Up @@ -252,7 +263,8 @@ func Test_LoadLastBlockScanned(t *testing.T) {
params := mocks.MockChainParams(chain.ChainId, 10)

// create observer using mock evm client
evmClient := mocks.NewMockEvmClient().WithBlockNumber(100)
evmClient := mocks.NewEVMRPCClient(t)
evmClient.On("BlockNumber", mock.Anything).Return(uint64(100), nil)
ob, _ := MockEVMObserver(t, chain, evmClient, nil, nil, nil, 1, params)

t.Run("should load last block scanned", func(t *testing.T) {
Expand Down Expand Up @@ -281,8 +293,12 @@ func Test_LoadLastBlockScanned(t *testing.T) {
// reset last block scanned to 0 so that it will be loaded from RPC
obOther.WithLastBlockScanned(0)

// set RPC error
evmClient.WithError(fmt.Errorf("error RPC"))
// create mock evm client with RPC error
evmClient := mocks.NewEVMRPCClient(t)
evmClient.On("BlockNumber", mock.Anything).Return(uint64(0), fmt.Errorf("error RPC"))

// attach mock evm client to observer
obOther.WithEvmClient(evmClient)

// load last block scanned
err := obOther.LoadLastBlockScanned(ctx)
Expand Down Expand Up @@ -369,12 +385,12 @@ func Test_HeaderCache(t *testing.T) {
ob.WithHeaderCache(headerCache)

// create mock evm client
evmClient := mocks.NewMockEvmClient()
evmClient := mocks.NewEVMRPCClient(t)
ob.WithEvmClient(evmClient)

// feed block header to evm client
header := &ethtypes.Header{Number: big.NewInt(100)}
evmClient.WithHeader(header)
evmClient.On("HeaderByNumber", mock.Anything, mock.Anything).Return(header, nil)

// get block header from observer
resHeader, err := ob.GetBlockHeaderCached(ctx, uint64(100))
Expand Down
74 changes: 74 additions & 0 deletions zetaclient/chains/evm/observer/outbound_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ import (
"testing"

ethcommon "github.com/ethereum/go-ethereum/common"
lru "github.com/hashicorp/golang-lru"
"github.com/rs/zerolog"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
"github.com/zeta-chain/node/pkg/chains"
"github.com/zeta-chain/node/pkg/coin"
Expand Down Expand Up @@ -413,6 +415,78 @@ func Test_ParseERC20WithdrawnEvent(t *testing.T) {
})
}

func Test_FilterTSSOutbound(t *testing.T) {
// load archived evm block
// https://etherscan.io/block/19363323
chain := chains.Ethereum
chainID := chain.ChainId
chainParam := mocks.MockChainParams(chainID, 1)

// load archived evm block
// https://etherscan.io/block/19363323
blockNumber := uint64(19363323)
block := testutils.LoadEVMBlock(t, TestDataDir, chainID, blockNumber, true)

// the outbound to be tested
outboundNonce := uint64(7260)
outboundHash := ethcommon.HexToHash("0xd13b593eb62b5500a00e288cc2fb2c8af1339025c0e6bc6183b8bef2ebbed0d3")
tx, receipt := testutils.LoadEVMOutboundNReceipt(t, TestDataDir, chainID, outboundHash.Hex(), coin.CoinType_Gas)

ctx := context.Background()

t.Run("should filter TSS outbound", func(t *testing.T) {
// create mock evm client with preloaded block, tx and receipt
evmClient := mocks.NewEVMRPCClient(t)
evmClient.On("BlockNumber", mock.Anything).Return(blockNumber+1, nil) // +1 confirmations
evmClient.On("TransactionByHash", mock.Anything, outboundHash).Return(tx, false, nil)
evmClient.On("TransactionReceipt", mock.Anything, outboundHash).Return(receipt, nil)

// create evm observer for testing
tss := mocks.NewTSSMainnet()
ob, _ := MockEVMObserver(t, chain, evmClient, nil, nil, tss, 1, chainParam)

// feed archived block to observer cache
blockCache, err := lru.New(1000)
require.NoError(t, err)
blockCache.Add(blockNumber, block)
ob.WithBlockCache(blockCache)

// filter TSS outbound
ob.FilterTSSOutbound(ctx, blockNumber, blockNumber)

// tx should be confirmed after filtering
found := ob.IsTxConfirmed(outboundNonce)
require.True(t, found)

// retrieve tx and receipt
receipt, tx := ob.GetTxNReceipt(outboundNonce)
require.NotNil(t, tx)
require.NotNil(t, receipt)
require.Equal(t, outboundHash, tx.Hash())
require.Equal(t, outboundNonce, tx.Nonce())
})

t.Run("should filter nothing on RPC error", func(t *testing.T) {
// create mock evm client block number
evmClient := mocks.NewEVMRPCClient(t)
evmClient.On("BlockNumber", mock.Anything).Return(blockNumber+1, nil)

// create evm JSON-RPC client without block to simulate RPC error
evmJSONRPC := mocks.NewMockJSONRPCClient()

// create evm observer for testing
tss := mocks.NewTSSMainnet()
ob, _ := MockEVMObserver(t, chain, evmClient, evmJSONRPC, nil, tss, 1, chainParam)

// filter TSS outbound
ob.FilterTSSOutbound(ctx, blockNumber, blockNumber)

// tx should be confirmed after filtering
found := ob.IsTxConfirmed(outboundNonce)
require.False(t, found)
})
}

// TODO: create mocks for gateway and ERC20CustodyV2 and uncomment these tests
// https://github.com/zeta-chain/node/issues/2669
//
Expand Down
5 changes: 3 additions & 2 deletions zetaclient/chains/evm/signer/sign_test.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
package signer

import (
"math/big"
"testing"

ethtypes "github.com/ethereum/go-ethereum/core/types"
"github.com/rs/zerolog"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/zeta-chain/node/zetaclient/testutils/mocks"
"math/big"
"testing"
)

func TestSigner_SignConnectorOnReceive(t *testing.T) {
Expand Down
Loading

0 comments on commit 19699f3

Please sign in to comment.