From 47a522641f6943228c01e07ed7e3afe2129a36ae Mon Sep 17 00:00:00 2001 From: James Kim Date: Tue, 22 Oct 2024 10:49:04 -0700 Subject: [PATCH] fix(test): remove time.sleep and improve test suite startup time --- go.mod | 4 ++ go.sum | 1 - orchestrator/orchestrator.go | 4 ++ readme_test.go | 36 ++++++++----- supersim_test.go | 100 +++++++++++++++++++++++------------ testutils/wait.go | 15 ++++++ 6 files changed, 110 insertions(+), 50 deletions(-) create mode 100644 testutils/wait.go diff --git a/go.mod b/go.mod index 5b2fbf9d..adfb67ff 100644 --- a/go.mod +++ b/go.mod @@ -43,6 +43,7 @@ require ( github.com/ethereum/c-kzg-4844 v1.0.0 // indirect github.com/ethereum/go-verkle v0.1.1-0.20240829091221-dffa7562dbe9 // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect + github.com/gballet/go-libpcsclite v0.0.0-20191108122812-4678299bea08 // indirect github.com/getsentry/sentry-go v0.27.0 // indirect github.com/go-ole/go-ole v1.3.0 // indirect github.com/gofrs/flock v0.8.1 // indirect @@ -54,6 +55,8 @@ require ( github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-bexpr v0.1.11 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect + github.com/holiman/billy v0.0.0-20240216141850-2abb0c79d3c4 // indirect github.com/holiman/bloomfilter/v2 v2.0.3 // indirect github.com/holiman/uint256 v1.3.1 // indirect github.com/huin/goupnp v1.3.0 // indirect @@ -80,6 +83,7 @@ require ( github.com/rs/cors v1.11.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/shirou/gopsutil v3.21.11+incompatible // indirect + github.com/status-im/keycard-go v0.2.0 // indirect github.com/stretchr/objx v0.5.2 // indirect github.com/supranational/blst v0.3.13 // indirect github.com/syndtr/goleveldb v1.0.1-0.20220614013038-64ee5596c38a // indirect diff --git a/go.sum b/go.sum index 0f20c9df..30951824 100644 --- a/go.sum +++ b/go.sum @@ -160,7 +160,6 @@ github.com/hashicorp/go-bexpr v0.1.11 h1:6DqdA/KBjurGby9yTY0bmkathya0lfwF2SeuubC github.com/hashicorp/go-bexpr v0.1.11/go.mod h1:f03lAo0duBlDIUMGCuad8oLcgejw4m7U+N8T+6Kz1AE= github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= -github.com/hashicorp/golang-lru v0.5.0 h1:CL2msUPvZTLb5O648aiLNJw3hnBxN2+1Jq8rCOH9wdo= github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= github.com/holiman/billy v0.0.0-20240216141850-2abb0c79d3c4 h1:X4egAf/gcS1zATw6wn4Ej8vjuVGxeHdan+bRb2ebyv4= diff --git a/orchestrator/orchestrator.go b/orchestrator/orchestrator.go index c0ef9763..fc21b31e 100644 --- a/orchestrator/orchestrator.go +++ b/orchestrator/orchestrator.go @@ -115,8 +115,12 @@ func (o *Orchestrator) Start(ctx context.Context) error { if err := interop.Configure(ctx, chain); err != nil { errs[i] = fmt.Errorf("failed to configure interop for chain %s: %w", chain.Config().Name, err) } + wg.Done() }(i) } + + wg.Wait() + if err := errors.Join(errs...); err != nil { return err } diff --git a/readme_test.go b/readme_test.go index 30d307f1..34a0cf64 100644 --- a/readme_test.go +++ b/readme_test.go @@ -1,6 +1,7 @@ package supersim import ( + "context" "fmt" "os/exec" "strings" @@ -8,6 +9,7 @@ import ( "time" "github.com/ethereum-optimism/supersim/config" + "github.com/ethereum-optimism/supersim/testutils" "github.com/stretchr/testify/assert" ) @@ -38,14 +40,17 @@ func TestL1ToL2Deposit(t *testing.T) { _, err = runCmd(bridgeCmd) assert.NoError(t, err, "Failed to bridge ETH") - // Wait for a few seconds to allow the bridge transaction to be processed - time.Sleep(5 * time.Second) + // Wait for bridge transaction to be processed + waitErr := testutils.WaitForWithTimeout(context.Background(), 500*time.Millisecond, 10*time.Second, func() (bool, error) { + finalBalanceCmd := "cast balance 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 --rpc-url http://127.0.0.1:9545" + finalBalance, err := runCmd(finalBalanceCmd) + if err != nil { + return false, err + } - // Check the final balance on L2 - finalBalanceCmd := "cast balance 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 --rpc-url http://127.0.0.1:9545" - finalBalance, err := runCmd(finalBalanceCmd) - assert.NoError(t, err) - assert.Equal(t, "10000100000000000000000", finalBalance, "Final balance check failed") + return finalBalance == "10000100000000000000000", nil + }) + assert.NoError(t, waitErr) } func TestL2ToL2Transfer(t *testing.T) { @@ -71,12 +76,15 @@ func TestL2ToL2Transfer(t *testing.T) { _, err = runCmd(sendCmd) assert.NoError(t, err) - // Wait for the relayed message to be processed - time.Sleep(2 * time.Second) - // Check the final balance on chain 902 - finalBalanceCmd := `cast balance --erc20 0x420beeF000000000000000000000000000000001 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 --rpc-url http://127.0.0.1:9546` - finalBalance, err := runCmd(finalBalanceCmd) - assert.NoError(t, err) - assert.Equal(t, "1000", finalBalance, "Final balance check failed") + waitErr := testutils.WaitForWithTimeout(context.Background(), 500*time.Millisecond, 10*time.Second, func() (bool, error) { + finalBalanceCmd := `cast balance --erc20 0x420beeF000000000000000000000000000000001 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 --rpc-url http://127.0.0.1:9546` + finalBalance, err := runCmd(finalBalanceCmd) + if err != nil { + return false, err + } + + return finalBalance == "1000", nil + }) + assert.NoError(t, waitErr) } diff --git a/supersim_test.go b/supersim_test.go index 3fac1ac9..6795bc1d 100644 --- a/supersim_test.go +++ b/supersim_test.go @@ -10,12 +10,14 @@ import ( "github.com/ethereum-optimism/optimism/op-chain-ops/devkeys" opbindings "github.com/ethereum-optimism/optimism/op-e2e/bindings" + "github.com/ethereum-optimism/optimism/op-e2e/e2eutils/wait" "github.com/ethereum-optimism/optimism/op-service/predeploys" "github.com/ethereum-optimism/optimism/op-service/testlog" registry "github.com/ethereum-optimism/superchain-registry/superchain" "github.com/ethereum-optimism/supersim/bindings" "github.com/ethereum-optimism/supersim/config" "github.com/ethereum-optimism/supersim/interop" + "github.com/ethereum-optimism/supersim/testutils" "github.com/joho/godotenv" "github.com/ethereum/go-ethereum/accounts/abi" @@ -29,6 +31,7 @@ import ( "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/rpc" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -142,9 +145,6 @@ func createForkedInteropTestSuite(t *testing.T, testOptions ForkInteropTestSuite destChainID := new(big.Int).SetUint64(destChainCfg.ChainID) sourceChainID := new(big.Int).SetUint64(srcChainCfg.ChainID) - // TODO: fix when we add a wait for ready on the opsim - time.Sleep(3 * time.Second) - return &InteropTestSuite{ t: t, Cfg: testSuite.Cfg, @@ -168,9 +168,6 @@ func createInteropTestSuite(t *testing.T, cliConfig config.CLIConfig) *InteropTe destEthClient, _ := ethclient.Dial(destURL) defer destEthClient.Close() - // TODO: fix when we add a wait for ready on the opsim - time.Sleep(3 * time.Second) - return &InteropTestSuite{ t: t, Cfg: testSuite.Cfg, @@ -184,6 +181,8 @@ func createInteropTestSuite(t *testing.T, cliConfig config.CLIConfig) *InteropTe } func TestStartup(t *testing.T) { + t.Parallel() + testSuite := createTestSuite(t, &config.CLIConfig{}) l2Chains := testSuite.Supersim.Orchestrator.L2Chains() @@ -213,6 +212,8 @@ func TestStartup(t *testing.T) { } func TestL1GenesisState(t *testing.T) { + t.Parallel() + testSuite := createTestSuite(t, &config.CLIConfig{}) l1Client := testSuite.Supersim.Orchestrator.L1Chain().EthClient() @@ -232,6 +233,8 @@ func TestL1GenesisState(t *testing.T) { } func TestGenesisState(t *testing.T) { + t.Parallel() + testSuite := createTestSuite(t, &config.CLIConfig{}) for _, chain := range testSuite.Supersim.Orchestrator.L2Chains() { client, err := rpc.Dial(chain.Endpoint()) @@ -251,6 +254,8 @@ func TestGenesisState(t *testing.T) { } func TestAccountBalances(t *testing.T) { + t.Parallel() + testSuite := createTestSuite(t, &config.CLIConfig{}) for _, l2Chain := range testSuite.Supersim.Orchestrator.L2Chains() { @@ -267,6 +272,8 @@ func TestAccountBalances(t *testing.T) { } func TestDepositTxSimpleEthDeposit(t *testing.T) { + t.Parallel() + testSuite := createTestSuite(t, &config.CLIConfig{}) l1Chain := testSuite.Supersim.Orchestrator.L1Chain() @@ -304,9 +311,13 @@ func TestDepositTxSimpleEthDeposit(t *testing.T) { require.True(t, txReceipt.Status == 1, "Deposit transaction failed") require.NotEmpty(t, txReceipt.Logs, "Deposit transaction failed") - // wait for the deposit to be processed - time.Sleep(2 * time.Second) - postBalance, _ := l2EthClient.BalanceAt(context.Background(), senderAddress, nil) + postBalance, postBalanceCheckErr := wait.ForBalanceChange( + context.Background(), + l2EthClient, + senderAddress, + prevBalance, + ) + require.NoError(t, postBalanceCheckErr) // check that balance was increased require.Equal(t, oneEth, postBalance.Sub(postBalance, prevBalance), "Recipient balance is incorrect") @@ -317,6 +328,8 @@ func TestDepositTxSimpleEthDeposit(t *testing.T) { } func TestDependencySet(t *testing.T) { + t.Parallel() + testSuite := createTestSuite(t, &config.CLIConfig{}) for _, chain := range testSuite.Supersim.Orchestrator.L2Chains() { @@ -327,9 +340,6 @@ func TestDependencySet(t *testing.T) { l1BlockInterop, err := bindings.NewL1BlockInterop(predeploys.L1BlockAddr, l2Client) require.NoError(t, err) - // TODO: fix when we add a wait for ready on the opsim - time.Sleep(3 * time.Second) - depSetSize, err := l1BlockInterop.DependencySetSize(&bind.CallOpts{}) require.NoError(t, err) @@ -347,6 +357,8 @@ func TestDependencySet(t *testing.T) { } func TestDeployContractsL1WithDevAccounts(t *testing.T) { + t.Parallel() + testSuite := createTestSuite(t, &config.CLIConfig{}) l1Client, err := ethclient.Dial(testSuite.Supersim.Orchestrator.L1Chain().Endpoint()) @@ -385,6 +397,8 @@ func TestDeployContractsL1WithDevAccounts(t *testing.T) { } func TestBatchJsonRpcRequests(t *testing.T) { + t.Parallel() + testSuite := createTestSuite(t, &config.CLIConfig{}) for _, chain := range testSuite.Supersim.Orchestrator.L2Chains() { @@ -405,6 +419,8 @@ func TestBatchJsonRpcRequests(t *testing.T) { } func TestBatchJsonRpcRequestErrorHandling(t *testing.T) { + t.Parallel() + testSuite := createInteropTestSuite(t, config.CLIConfig{}) gasLimit := uint64(30000000) gasPrice := big.NewInt(10000000) @@ -467,6 +483,8 @@ func TestBatchJsonRpcRequestErrorHandling(t *testing.T) { } func TestInteropInvariantCheckSucceeds(t *testing.T) { + t.Parallel() + testSuite := createInteropTestSuite(t, config.CLIConfig{}) privateKey, err := testSuite.DevKeys.Secret(devkeys.UserKey(0)) require.NoError(t, err) @@ -520,6 +538,8 @@ func TestInteropInvariantCheckSucceeds(t *testing.T) { } func TestInteropInvariantCheckFailsBadLogIndex(t *testing.T) { + t.Parallel() + testSuite := createInteropTestSuite(t, config.CLIConfig{}) privateKey, err := testSuite.DevKeys.Secret(devkeys.UserKey(0)) require.NoError(t, err) @@ -571,6 +591,8 @@ func TestInteropInvariantCheckFailsBadLogIndex(t *testing.T) { } func TestInteropInvariantCheckBadBlockNumber(t *testing.T) { + t.Parallel() + testSuite := createInteropTestSuite(t, config.CLIConfig{}) privateKey, err := testSuite.DevKeys.Secret(devkeys.UserKey(0)) require.NoError(t, err) @@ -622,6 +644,8 @@ func TestInteropInvariantCheckBadBlockNumber(t *testing.T) { } func TestInteropInvariantCheckBadBlockTimestamp(t *testing.T) { + t.Parallel() + testSuite := createInteropTestSuite(t, config.CLIConfig{}) privateKey, err := testSuite.DevKeys.Secret(devkeys.UserKey(0)) require.NoError(t, err) @@ -672,6 +696,8 @@ func TestInteropInvariantCheckBadBlockTimestamp(t *testing.T) { } func TestForkedInteropInvariantCheckSucceeds(t *testing.T) { + t.Parallel() + testSuite := createForkedInteropTestSuite(t, ForkInteropTestSuiteOptions{interopAutoRelay: false}) privateKey, err := testSuite.DevKeys.Secret(devkeys.UserKey(0)) @@ -726,6 +752,8 @@ func TestForkedInteropInvariantCheckSucceeds(t *testing.T) { } func TestAutoRelaySimpleStorageCallSucceeds(t *testing.T) { + t.Parallel() + testSuite := createInteropTestSuite(t, config.CLIConfig{InteropAutoRelay: true}) privateKey, err := testSuite.DevKeys.Secret(devkeys.UserKey(0)) require.NoError(t, err) @@ -767,21 +795,21 @@ func TestAutoRelaySimpleStorageCallSucceeds(t *testing.T) { require.NoError(t, err) require.True(t, initiatingMessageTxReceipt.Status == 1, "initiating message transaction failed") - time.Sleep(time.Second * 2) - - // progress forward one block before sending tx - err = testSuite.DestEthClient.Client().CallContext(context.Background(), nil, "anvil_mine", uint64(3), uint64(2)) - require.NoError(t, err) - err = testSuite.SourceEthClient.Client().CallContext(context.Background(), nil, "anvil_mine", uint64(3), uint64(2)) - require.NoError(t, err) + waitErr := testutils.WaitForWithTimeout(context.Background(), 500*time.Millisecond, 10*time.Second, func() (bool, error) { + newVal, err := simpleStorage.Get(&bind.CallOpts{}, key) + require.NoError(t, err) + if err != nil { + return false, err + } - // message should have been auto-relayed by now - newVal, err := simpleStorage.Get(&bind.CallOpts{}, key) - require.NoError(t, err) - require.Equal(t, val, common.Hash(newVal), "SimpleStorage value is incorrect") + return newVal == common.Hash(newVal), nil + }) + assert.NoError(t, waitErr) } func TestAutoRelaySuperchainWETHTransferSucceeds(t *testing.T) { + t.Parallel() + testSuite := createInteropTestSuite(t, config.CLIConfig{InteropAutoRelay: true}) privateKey, err := testSuite.DevKeys.Secret(devkeys.UserKey(0)) require.NoError(t, err) @@ -817,12 +845,13 @@ func TestAutoRelaySuperchainWETHTransferSucceeds(t *testing.T) { require.NoError(t, err) require.True(t, initiatingMessageTxReceipt.Status == 1, "initiating message transaction failed") - time.Sleep(time.Second * 4) - - destEndingBalance, err := destSuperchainWETH.BalanceOf(&bind.CallOpts{}, sourceTransactor.From) - require.NoError(t, err) - diff := new(big.Int).Sub(destEndingBalance, destStartingBalance) - require.Equal(t, valueToTransfer, diff) + waitErr := testutils.WaitForWithTimeout(context.Background(), 500*time.Millisecond, 10*time.Second, func() (bool, error) { + destEndingBalance, err := destSuperchainWETH.BalanceOf(&bind.CallOpts{}, sourceTransactor.From) + require.NoError(t, err) + diff := new(big.Int).Sub(destEndingBalance, destStartingBalance) + return diff.Cmp(valueToTransfer) == 0, nil + }) + assert.NoError(t, waitErr) } func TestForkAutoRelaySuperchainWETHTransferSucceeds(t *testing.T) { @@ -862,10 +891,11 @@ func TestForkAutoRelaySuperchainWETHTransferSucceeds(t *testing.T) { require.NoError(t, err) require.True(t, initiatingMessageTxReceipt.Status == 1, "initiating message transaction failed") - time.Sleep(time.Second * 4) - - destEndingBalance, err := destSuperchainWETH.BalanceOf(&bind.CallOpts{}, sourceTransactor.From) - require.NoError(t, err) - diff := new(big.Int).Sub(destEndingBalance, destStartingBalance) - require.Equal(t, valueToTransfer, diff) + waitErr := testutils.WaitForWithTimeout(context.Background(), 500*time.Millisecond, 10*time.Second, func() (bool, error) { + destEndingBalance, err := destSuperchainWETH.BalanceOf(&bind.CallOpts{}, sourceTransactor.From) + require.NoError(t, err) + diff := new(big.Int).Sub(destEndingBalance, destStartingBalance) + return diff.Cmp(valueToTransfer) == 0, nil + }) + assert.NoError(t, waitErr) } diff --git a/testutils/wait.go b/testutils/wait.go new file mode 100644 index 00000000..5f20d641 --- /dev/null +++ b/testutils/wait.go @@ -0,0 +1,15 @@ +package testutils + +import ( + "context" + "time" + + "github.com/ethereum-optimism/optimism/op-e2e/e2eutils/wait" +) + +func WaitForWithTimeout(ctx context.Context, ticker time.Duration, timeout time.Duration, cb func() (bool, error)) error { + ctx, cancel := context.WithTimeout(ctx, timeout) + defer cancel() + + return wait.For(ctx, ticker, cb) +}