mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-22 20:56:42 +00:00
add happy and timeout unit tests
This commit is contained in:
parent
ca42c98c60
commit
a33a1c9142
1 changed files with 140 additions and 2 deletions
|
|
@ -440,6 +440,14 @@ type testBackend struct {
|
|||
|
||||
pending *types.Block
|
||||
pendingReceipts types.Receipts
|
||||
|
||||
// test-only fields for SendRawTransactionSync
|
||||
autoMine bool
|
||||
mined bool
|
||||
syncDefaultTO time.Duration
|
||||
syncMaxTO time.Duration
|
||||
sentTx *types.Transaction
|
||||
sentTxHash common.Hash
|
||||
}
|
||||
|
||||
func newTestBackend(t *testing.T, n int, gspec *core.Genesis, engine consensus.Engine, generator func(i int, b *core.BlockGen)) *testBackend {
|
||||
|
|
@ -592,14 +600,38 @@ func (b testBackend) SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscr
|
|||
func (b testBackend) SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) event.Subscription {
|
||||
panic("implement me")
|
||||
}
|
||||
func (b testBackend) SendTx(ctx context.Context, signedTx *types.Transaction) error {
|
||||
panic("implement me")
|
||||
func (b *testBackend) SendTx(ctx context.Context, tx *types.Transaction) error {
|
||||
b.sentTx = tx
|
||||
b.sentTxHash = tx.Hash()
|
||||
if b.autoMine {
|
||||
b.mined = true
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (b testBackend) GetCanonicalTransaction(txHash common.Hash) (bool, *types.Transaction, common.Hash, uint64, uint64) {
|
||||
// in-memory fast path for tests
|
||||
if b.mined && txHash == b.sentTxHash {
|
||||
return true, b.sentTx, common.HexToHash("0x01"), 1, 0
|
||||
}
|
||||
// fallback to existing DB-backed path
|
||||
tx, blockHash, blockNumber, index := rawdb.ReadCanonicalTransaction(b.db, txHash)
|
||||
return tx != nil, tx, blockHash, blockNumber, index
|
||||
}
|
||||
func (b testBackend) GetCanonicalReceipt(tx *types.Transaction, blockHash common.Hash, blockNumber, blockIndex uint64) (*types.Receipt, error) {
|
||||
// In-memory fast path used by tests
|
||||
if b.mined && tx != nil && tx.Hash() == b.sentTxHash && blockHash == common.HexToHash("0x01") && blockNumber == 1 && blockIndex == 0 {
|
||||
return &types.Receipt{
|
||||
Type: tx.Type(),
|
||||
Status: types.ReceiptStatusSuccessful,
|
||||
CumulativeGasUsed: 21000,
|
||||
GasUsed: 21000,
|
||||
EffectiveGasPrice: big.NewInt(1),
|
||||
BlockHash: blockHash,
|
||||
BlockNumber: new(big.Int).SetUint64(blockNumber),
|
||||
TransactionIndex: 0,
|
||||
}, nil
|
||||
}
|
||||
// Fallback: use the chain's canonical receipt (DB-backed)
|
||||
return b.chain.GetCanonicalReceipt(tx, blockHash, blockNumber, blockIndex)
|
||||
}
|
||||
func (b testBackend) TxIndexDone() bool {
|
||||
|
|
@ -3889,3 +3921,109 @@ func (b configTimeBackend) HeaderByNumber(_ context.Context, n rpc.BlockNumber)
|
|||
func (b configTimeBackend) CurrentHeader() *types.Header {
|
||||
return &types.Header{Time: b.time}
|
||||
}
|
||||
|
||||
func (b *testBackend) RPCTxSyncDefaultTimeout() time.Duration {
|
||||
if b.syncDefaultTO != 0 {
|
||||
return b.syncDefaultTO
|
||||
}
|
||||
return 2 * time.Second
|
||||
}
|
||||
func (b *testBackend) RPCTxSyncMaxTimeout() time.Duration {
|
||||
if b.syncMaxTO != 0 {
|
||||
return b.syncMaxTO
|
||||
}
|
||||
return 5 * time.Minute
|
||||
}
|
||||
func (b *backendMock) RPCTxSyncDefaultTimeout() time.Duration { return 2 * time.Second }
|
||||
func (b *backendMock) RPCTxSyncMaxTimeout() time.Duration { return 5 * time.Minute }
|
||||
|
||||
func makeSignedRaw(t *testing.T, api *TransactionAPI, from, to common.Address, value *big.Int) (hexutil.Bytes, *types.Transaction) {
|
||||
t.Helper()
|
||||
|
||||
fillRes, err := api.FillTransaction(context.Background(), TransactionArgs{
|
||||
From: &from,
|
||||
To: &to,
|
||||
Value: (*hexutil.Big)(value),
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("FillTransaction failed: %v", err)
|
||||
}
|
||||
signRes, err := api.SignTransaction(context.Background(), argsFromTransaction(fillRes.Tx, from))
|
||||
if err != nil {
|
||||
t.Fatalf("SignTransaction failed: %v", err)
|
||||
}
|
||||
return signRes.Raw, signRes.Tx
|
||||
}
|
||||
|
||||
// makeSelfSignedRaw is a convenience for a 0-ETH self-transfer.
|
||||
func makeSelfSignedRaw(t *testing.T, api *TransactionAPI, addr common.Address) (hexutil.Bytes, *types.Transaction) {
|
||||
return makeSignedRaw(t, api, addr, addr, big.NewInt(0))
|
||||
}
|
||||
|
||||
func TestSendRawTransactionSync_Success(t *testing.T) {
|
||||
t.Parallel()
|
||||
genesis := &core.Genesis{
|
||||
Config: params.TestChainConfig,
|
||||
Alloc: types.GenesisAlloc{},
|
||||
}
|
||||
b := newTestBackend(t, 0, genesis, ethash.NewFaker(), nil)
|
||||
b.autoMine = true // immediately “mines” the tx in-memory
|
||||
|
||||
api := NewTransactionAPI(b, new(AddrLocker))
|
||||
|
||||
raw, _ := makeSelfSignedRaw(t, api, b.acc.Address)
|
||||
|
||||
receipt, err := api.SendRawTransactionSync(context.Background(), raw, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if receipt == nil {
|
||||
t.Fatalf("expected non-nil receipt")
|
||||
}
|
||||
if _, ok := receipt["blockNumber"]; !ok {
|
||||
t.Fatalf("expected blockNumber in receipt, got %#v", receipt)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSendRawTransactionSync_Timeout(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
genesis := &core.Genesis{
|
||||
Config: params.TestChainConfig,
|
||||
Alloc: types.GenesisAlloc{},
|
||||
}
|
||||
b := newTestBackend(t, 0, genesis, ethash.NewFaker(), nil)
|
||||
b.autoMine = false // don't mine, should time out
|
||||
|
||||
api := NewTransactionAPI(b, new(AddrLocker))
|
||||
|
||||
raw, _ := makeSelfSignedRaw(t, api, b.acc.Address)
|
||||
|
||||
timeout := hexutil.Uint64(200) // 200ms
|
||||
receipt, err := api.SendRawTransactionSync(context.Background(), raw, &timeout)
|
||||
|
||||
if receipt != nil {
|
||||
t.Fatalf("expected nil receipt, got %#v", receipt)
|
||||
}
|
||||
if err == nil {
|
||||
t.Fatalf("expected timeout error, got nil")
|
||||
}
|
||||
// assert error shape & data (hash)
|
||||
var de interface {
|
||||
ErrorCode() int
|
||||
ErrorData() interface{}
|
||||
}
|
||||
if !errors.As(err, &de) {
|
||||
t.Fatalf("expected data error with code/data, got %T %v", err, err)
|
||||
}
|
||||
if de.ErrorCode() != errCodeTxSyncTimeout {
|
||||
t.Fatalf("expected code %d, got %d", errCodeTxSyncTimeout, de.ErrorCode())
|
||||
}
|
||||
tx := new(types.Transaction)
|
||||
if e := tx.UnmarshalBinary(raw); e != nil {
|
||||
t.Fatal(e)
|
||||
}
|
||||
if got, want := de.ErrorData(), tx.Hash().Hex(); got != want {
|
||||
t.Fatalf("expected ErrorData=%s, got %v", want, got)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue