github.com/ethereum-optimism/optimism@v1.7.2/op-node/rollup/driver/metered_l1fetcher_test.go (about)

     1  package driver
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"testing"
     7  	"time"
     8  
     9  	"github.com/ethereum-optimism/optimism/op-service/eth"
    10  	"github.com/ethereum-optimism/optimism/op-service/testutils"
    11  	"github.com/ethereum/go-ethereum/common"
    12  	"github.com/ethereum/go-ethereum/core/types"
    13  	"github.com/stretchr/testify/mock"
    14  	"github.com/stretchr/testify/require"
    15  )
    16  
    17  func TestDurationRecorded(t *testing.T) {
    18  	num := uint64(1234)
    19  	hash := common.Hash{0xaa}
    20  	ref := eth.L1BlockRef{Number: num}
    21  	info := &testutils.MockBlockInfo{}
    22  	expectedErr := errors.New("test error")
    23  
    24  	tests := []struct {
    25  		method string
    26  		expect func(inner *testutils.MockL1Source)
    27  		call   func(t *testing.T, fetcher *MeteredL1Fetcher, inner *testutils.MockL1Source)
    28  	}{
    29  		{
    30  			method: "L1BlockRefByLabel",
    31  			call: func(t *testing.T, fetcher *MeteredL1Fetcher, inner *testutils.MockL1Source) {
    32  				inner.ExpectL1BlockRefByLabel(eth.Finalized, ref, expectedErr)
    33  
    34  				result, err := fetcher.L1BlockRefByLabel(context.Background(), eth.Finalized)
    35  				require.Equal(t, ref, result)
    36  				require.Equal(t, expectedErr, err)
    37  			},
    38  		},
    39  		{
    40  			method: "L1BlockRefByNumber",
    41  			call: func(t *testing.T, fetcher *MeteredL1Fetcher, inner *testutils.MockL1Source) {
    42  				inner.ExpectL1BlockRefByNumber(num, ref, expectedErr)
    43  
    44  				result, err := fetcher.L1BlockRefByNumber(context.Background(), num)
    45  				require.Equal(t, ref, result)
    46  				require.Equal(t, expectedErr, err)
    47  			},
    48  		},
    49  		{
    50  			method: "L1BlockRefByHash",
    51  			call: func(t *testing.T, fetcher *MeteredL1Fetcher, inner *testutils.MockL1Source) {
    52  				inner.ExpectL1BlockRefByHash(hash, ref, expectedErr)
    53  
    54  				result, err := fetcher.L1BlockRefByHash(context.Background(), hash)
    55  				require.Equal(t, ref, result)
    56  				require.Equal(t, expectedErr, err)
    57  			},
    58  		},
    59  		{
    60  			method: "InfoByHash",
    61  			call: func(t *testing.T, fetcher *MeteredL1Fetcher, inner *testutils.MockL1Source) {
    62  				inner.ExpectInfoByHash(hash, info, expectedErr)
    63  
    64  				result, err := fetcher.InfoByHash(context.Background(), hash)
    65  				require.Equal(t, info, result)
    66  				require.Equal(t, expectedErr, err)
    67  			},
    68  		},
    69  		{
    70  			method: "InfoAndTxsByHash",
    71  			call: func(t *testing.T, fetcher *MeteredL1Fetcher, inner *testutils.MockL1Source) {
    72  				txs := types.Transactions{
    73  					&types.Transaction{},
    74  				}
    75  				inner.ExpectInfoAndTxsByHash(hash, info, txs, expectedErr)
    76  
    77  				actualInfo, actualTxs, err := fetcher.InfoAndTxsByHash(context.Background(), hash)
    78  				require.Equal(t, info, actualInfo)
    79  				require.Equal(t, txs, actualTxs)
    80  				require.Equal(t, expectedErr, err)
    81  			},
    82  		},
    83  		{
    84  			method: "FetchReceipts",
    85  			call: func(t *testing.T, fetcher *MeteredL1Fetcher, inner *testutils.MockL1Source) {
    86  				rcpts := types.Receipts{
    87  					&types.Receipt{},
    88  				}
    89  				inner.ExpectFetchReceipts(hash, info, rcpts, expectedErr)
    90  
    91  				actualInfo, actualRcpts, err := fetcher.FetchReceipts(context.Background(), hash)
    92  				require.Equal(t, info, actualInfo)
    93  				require.Equal(t, rcpts, actualRcpts)
    94  				require.Equal(t, expectedErr, err)
    95  			},
    96  		},
    97  	}
    98  	for _, test := range tests {
    99  		test := test
   100  		t.Run(test.method, func(t *testing.T) {
   101  			duration := 200 * time.Millisecond
   102  			fetcher, inner, metrics := createFetcher(duration)
   103  			defer inner.AssertExpectations(t)
   104  			defer metrics.AssertExpectations(t)
   105  
   106  			metrics.ExpectRecordRequestTime(test.method, duration)
   107  
   108  			test.call(t, fetcher, inner)
   109  		})
   110  	}
   111  }
   112  
   113  // createFetcher creates a MeteredL1Fetcher with a mock inner.
   114  // The clock used to calculate the current time will advance by clockIncrement on each call, making it appear as if
   115  // each request takes that amount of time to execute.
   116  func createFetcher(clockIncrement time.Duration) (*MeteredL1Fetcher, *testutils.MockL1Source, *mockMetrics) {
   117  	inner := &testutils.MockL1Source{}
   118  	currTime := time.UnixMilli(1294812934000000)
   119  	clock := func() time.Time {
   120  		currTime = currTime.Add(clockIncrement)
   121  		return currTime
   122  	}
   123  	metrics := &mockMetrics{}
   124  	fetcher := MeteredL1Fetcher{
   125  		inner:   inner,
   126  		metrics: metrics,
   127  		now:     clock,
   128  	}
   129  	return &fetcher, inner, metrics
   130  }
   131  
   132  type mockMetrics struct {
   133  	mock.Mock
   134  }
   135  
   136  func (m *mockMetrics) RecordL1RequestTime(method string, duration time.Duration) {
   137  	m.MethodCalled("RecordL1RequestTime", method, duration)
   138  }
   139  
   140  func (m *mockMetrics) ExpectRecordRequestTime(method string, duration time.Duration) {
   141  	m.On("RecordL1RequestTime", method, duration).Once()
   142  }