Skip to content

Commit 889f564

Browse files
ethclient: better test suite for ethclient package (#22127)
This commit extends the ethclient test suite and increases code coverage of the ethclient package from ~15% to >55%. These tests act as early smoke tests to signal issues in the RPC-interface. E.g. if a functionality like eth_chainId or eth_call breaks, the test will break.
1 parent 6b88ab7 commit 889f564

File tree

1 file changed

+231
-28
lines changed

1 file changed

+231
-28
lines changed

ethclient/ethclient_test.go

Lines changed: 231 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
package ethclient
1818

1919
import (
20+
"bytes"
2021
"context"
2122
"errors"
2223
"fmt"
@@ -35,6 +36,7 @@ import (
3536
"github.com/ethereum/go-ethereum/eth"
3637
"github.com/ethereum/go-ethereum/node"
3738
"github.com/ethereum/go-ethereum/params"
39+
"github.com/ethereum/go-ethereum/rpc"
3840
)
3941

4042
// Verify that Client implements the ethereum interfaces.
@@ -229,12 +231,48 @@ func generateTestChain() (*core.Genesis, []*types.Block) {
229231
return genesis, blocks
230232
}
231233

232-
func TestHeader(t *testing.T) {
234+
func TestEthClient(t *testing.T) {
233235
backend, chain := newTestBackend(t)
234236
client, _ := backend.Attach()
235237
defer backend.Close()
236238
defer client.Close()
237239

240+
tests := map[string]struct {
241+
test func(t *testing.T)
242+
}{
243+
"TestHeader": {
244+
func(t *testing.T) { testHeader(t, chain, client) },
245+
},
246+
"TestBalanceAt": {
247+
func(t *testing.T) { testBalanceAt(t, client) },
248+
},
249+
"TestTxInBlockInterrupted": {
250+
func(t *testing.T) { testTransactionInBlockInterrupted(t, client) },
251+
},
252+
"TestChainID": {
253+
func(t *testing.T) { testChainID(t, client) },
254+
},
255+
"TestGetBlock": {
256+
func(t *testing.T) { testGetBlock(t, client) },
257+
},
258+
"TestStatusFunctions": {
259+
func(t *testing.T) { testStatusFunctions(t, client) },
260+
},
261+
"TestCallContract": {
262+
func(t *testing.T) { testCallContract(t, client) },
263+
},
264+
"TestAtFunctions": {
265+
func(t *testing.T) { testAtFunctions(t, client) },
266+
},
267+
}
268+
269+
t.Parallel()
270+
for name, tt := range tests {
271+
t.Run(name, tt.test)
272+
}
273+
}
274+
275+
func testHeader(t *testing.T, chain []*types.Block, client *rpc.Client) {
238276
tests := map[string]struct {
239277
block *big.Int
240278
want *types.Header
@@ -273,12 +311,7 @@ func TestHeader(t *testing.T) {
273311
}
274312
}
275313

276-
func TestBalanceAt(t *testing.T) {
277-
backend, _ := newTestBackend(t)
278-
client, _ := backend.Attach()
279-
defer backend.Close()
280-
defer client.Close()
281-
314+
func testBalanceAt(t *testing.T, client *rpc.Client) {
282315
tests := map[string]struct {
283316
account common.Address
284317
block *big.Int
@@ -319,31 +352,32 @@ func TestBalanceAt(t *testing.T) {
319352
}
320353
}
321354

322-
func TestTransactionInBlockInterrupted(t *testing.T) {
323-
backend, _ := newTestBackend(t)
324-
client, _ := backend.Attach()
325-
defer backend.Close()
326-
defer client.Close()
327-
355+
func testTransactionInBlockInterrupted(t *testing.T, client *rpc.Client) {
328356
ec := NewClient(client)
357+
358+
// Get current block by number
359+
block, err := ec.BlockByNumber(context.Background(), nil)
360+
if err != nil {
361+
t.Fatalf("unexpected error: %v", err)
362+
}
363+
// Test tx in block interupted
329364
ctx, cancel := context.WithCancel(context.Background())
330365
cancel()
331-
tx, err := ec.TransactionInBlock(ctx, common.Hash{1}, 1)
366+
tx, err := ec.TransactionInBlock(ctx, block.Hash(), 1)
332367
if tx != nil {
333368
t.Fatal("transaction should be nil")
334369
}
335-
if err == nil {
336-
t.Fatal("error should not be nil")
370+
if err == nil || err == ethereum.NotFound {
371+
t.Fatal("error should not be nil/notfound")
372+
}
373+
// Test tx in block not found
374+
if _, err := ec.TransactionInBlock(context.Background(), block.Hash(), 1); err != ethereum.NotFound {
375+
t.Fatal("error should be ethereum.NotFound")
337376
}
338377
}
339378

340-
func TestChainID(t *testing.T) {
341-
backend, _ := newTestBackend(t)
342-
client, _ := backend.Attach()
343-
defer backend.Close()
344-
defer client.Close()
379+
func testChainID(t *testing.T, client *rpc.Client) {
345380
ec := NewClient(client)
346-
347381
id, err := ec.ChainID(context.Background())
348382
if err != nil {
349383
t.Fatalf("unexpected error: %v", err)
@@ -353,18 +387,187 @@ func TestChainID(t *testing.T) {
353387
}
354388
}
355389

356-
func TestBlockNumber(t *testing.T) {
357-
backend, _ := newTestBackend(t)
358-
client, _ := backend.Attach()
359-
defer backend.Close()
360-
defer client.Close()
390+
func testGetBlock(t *testing.T, client *rpc.Client) {
361391
ec := NewClient(client)
362-
392+
// Get current block number
363393
blockNumber, err := ec.BlockNumber(context.Background())
364394
if err != nil {
365395
t.Fatalf("unexpected error: %v", err)
366396
}
367397
if blockNumber != 1 {
368398
t.Fatalf("BlockNumber returned wrong number: %d", blockNumber)
369399
}
400+
// Get current block by number
401+
block, err := ec.BlockByNumber(context.Background(), new(big.Int).SetUint64(blockNumber))
402+
if err != nil {
403+
t.Fatalf("unexpected error: %v", err)
404+
}
405+
if block.NumberU64() != blockNumber {
406+
t.Fatalf("BlockByNumber returned wrong block: want %d got %d", blockNumber, block.NumberU64())
407+
}
408+
// Get current block by hash
409+
blockH, err := ec.BlockByHash(context.Background(), block.Hash())
410+
if err != nil {
411+
t.Fatalf("unexpected error: %v", err)
412+
}
413+
if block.Hash() != blockH.Hash() {
414+
t.Fatalf("BlockByHash returned wrong block: want %v got %v", block.Hash().Hex(), blockH.Hash().Hex())
415+
}
416+
// Get header by number
417+
header, err := ec.HeaderByNumber(context.Background(), new(big.Int).SetUint64(blockNumber))
418+
if err != nil {
419+
t.Fatalf("unexpected error: %v", err)
420+
}
421+
if block.Header().Hash() != header.Hash() {
422+
t.Fatalf("HeaderByNumber returned wrong header: want %v got %v", block.Header().Hash().Hex(), header.Hash().Hex())
423+
}
424+
// Get header by hash
425+
headerH, err := ec.HeaderByHash(context.Background(), block.Hash())
426+
if err != nil {
427+
t.Fatalf("unexpected error: %v", err)
428+
}
429+
if block.Header().Hash() != headerH.Hash() {
430+
t.Fatalf("HeaderByHash returned wrong header: want %v got %v", block.Header().Hash().Hex(), headerH.Hash().Hex())
431+
}
432+
}
433+
434+
func testStatusFunctions(t *testing.T, client *rpc.Client) {
435+
ec := NewClient(client)
436+
437+
// Sync progress
438+
progress, err := ec.SyncProgress(context.Background())
439+
if err != nil {
440+
t.Fatalf("unexpected error: %v", err)
441+
}
442+
if progress != nil {
443+
t.Fatalf("unexpected progress: %v", progress)
444+
}
445+
// NetworkID
446+
networkID, err := ec.NetworkID(context.Background())
447+
if err != nil {
448+
t.Fatalf("unexpected error: %v", err)
449+
}
450+
if networkID.Cmp(big.NewInt(0)) != 0 {
451+
t.Fatalf("unexpected networkID: %v", networkID)
452+
}
453+
// SuggestGasPrice (should suggest 1 Gwei)
454+
gasPrice, err := ec.SuggestGasPrice(context.Background())
455+
if err != nil {
456+
t.Fatalf("unexpected error: %v", err)
457+
}
458+
if gasPrice.Cmp(big.NewInt(1000000000)) != 0 {
459+
t.Fatalf("unexpected gas price: %v", gasPrice)
460+
}
461+
}
462+
463+
func testCallContract(t *testing.T, client *rpc.Client) {
464+
ec := NewClient(client)
465+
466+
// EstimateGas
467+
msg := ethereum.CallMsg{
468+
From: testAddr,
469+
To: &common.Address{},
470+
Gas: 21000,
471+
GasPrice: big.NewInt(1),
472+
Value: big.NewInt(1),
473+
}
474+
gas, err := ec.EstimateGas(context.Background(), msg)
475+
if err != nil {
476+
t.Fatalf("unexpected error: %v", err)
477+
}
478+
if gas != 21000 {
479+
t.Fatalf("unexpected gas price: %v", gas)
480+
}
481+
// CallContract
482+
if _, err := ec.CallContract(context.Background(), msg, big.NewInt(1)); err != nil {
483+
t.Fatalf("unexpected error: %v", err)
484+
}
485+
// PendingCallCOntract
486+
if _, err := ec.PendingCallContract(context.Background(), msg); err != nil {
487+
t.Fatalf("unexpected error: %v", err)
488+
}
489+
}
490+
491+
func testAtFunctions(t *testing.T, client *rpc.Client) {
492+
ec := NewClient(client)
493+
// send a transaction for some interesting pending status
494+
sendTransaction(ec)
495+
time.Sleep(100 * time.Millisecond)
496+
// Check pending transaction count
497+
pending, err := ec.PendingTransactionCount(context.Background())
498+
if err != nil {
499+
t.Fatalf("unexpected error: %v", err)
500+
}
501+
if pending != 1 {
502+
t.Fatalf("unexpected pending, wanted 1 got: %v", pending)
503+
}
504+
// Query balance
505+
balance, err := ec.BalanceAt(context.Background(), testAddr, nil)
506+
if err != nil {
507+
t.Fatalf("unexpected error: %v", err)
508+
}
509+
penBalance, err := ec.PendingBalanceAt(context.Background(), testAddr)
510+
if err != nil {
511+
t.Fatalf("unexpected error: %v", err)
512+
}
513+
if balance.Cmp(penBalance) == 0 {
514+
t.Fatalf("unexpected balance: %v %v", balance, penBalance)
515+
}
516+
// NonceAt
517+
nonce, err := ec.NonceAt(context.Background(), testAddr, nil)
518+
if err != nil {
519+
t.Fatalf("unexpected error: %v", err)
520+
}
521+
penNonce, err := ec.PendingNonceAt(context.Background(), testAddr)
522+
if err != nil {
523+
t.Fatalf("unexpected error: %v", err)
524+
}
525+
if penNonce != nonce+1 {
526+
t.Fatalf("unexpected nonce: %v %v", nonce, penNonce)
527+
}
528+
// StorageAt
529+
storage, err := ec.StorageAt(context.Background(), testAddr, common.Hash{}, nil)
530+
if err != nil {
531+
t.Fatalf("unexpected error: %v", err)
532+
}
533+
penStorage, err := ec.PendingStorageAt(context.Background(), testAddr, common.Hash{})
534+
if err != nil {
535+
t.Fatalf("unexpected error: %v", err)
536+
}
537+
if !bytes.Equal(storage, penStorage) {
538+
t.Fatalf("unexpected storage: %v %v", storage, penStorage)
539+
}
540+
// CodeAt
541+
code, err := ec.CodeAt(context.Background(), testAddr, nil)
542+
if err != nil {
543+
t.Fatalf("unexpected error: %v", err)
544+
}
545+
penCode, err := ec.PendingCodeAt(context.Background(), testAddr)
546+
if err != nil {
547+
t.Fatalf("unexpected error: %v", err)
548+
}
549+
if !bytes.Equal(code, penCode) {
550+
t.Fatalf("unexpected code: %v %v", code, penCode)
551+
}
552+
}
553+
554+
func sendTransaction(ec *Client) error {
555+
// Retrieve chainID
556+
chainID, err := ec.ChainID(context.Background())
557+
if err != nil {
558+
return err
559+
}
560+
// Create transaction
561+
tx := types.NewTransaction(0, common.Address{1}, big.NewInt(1), 22000, big.NewInt(1), nil)
562+
signer := types.NewEIP155Signer(chainID)
563+
signature, err := crypto.Sign(signer.Hash(tx).Bytes(), testKey)
564+
if err != nil {
565+
return err
566+
}
567+
signedTx, err := tx.WithSignature(signer, signature)
568+
if err != nil {
569+
return err
570+
}
571+
// Send transaction
572+
return ec.SendTransaction(context.Background(), signedTx)
370573
}

0 commit comments

Comments
 (0)