Compare commits

...

30 Commits

Author SHA1 Message Date
maskpp
c9175e769b fix bug 2023-03-31 10:13:46 +08:00
maskpp
a1476ab8db fix bug when in testdata module 2023-03-29 21:07:43 +08:00
maskpp
8052866492 fix bug when in testdata module 2023-03-29 21:07:21 +08:00
maskpp
6bf7fb7fca trigger ci 2023-03-29 20:52:44 +08:00
maskpp
420efdbd70 fix bug when in testdata module 2023-03-29 20:38:36 +08:00
maskpp
f4246128a1 add debug log 2023-03-29 20:21:50 +08:00
maskpp
8ae1c5c44a add debug log 2023-03-29 17:48:51 +08:00
maskpp
a2c7b2449c trigger ci 2023-03-29 17:48:32 +08:00
maskpp
5c2d60c676 trigger ci 2023-03-29 17:41:43 +08:00
maskpp
b2807ecbef add debug log 2023-03-29 17:37:30 +08:00
maskpp
5c73beb461 fix bug 2023-03-28 10:14:57 +08:00
maskpp
906631e7d8 fix bug 2023-03-28 09:41:07 +08:00
maskpp
59df623b6a fix bug 2023-03-28 09:29:47 +08:00
maskpp
c1f02745e2 trigger ci 2023-03-28 09:19:00 +08:00
maskpp
e66e2cc348 Upgrade integration-test framework 2023-03-28 09:14:57 +08:00
maskpp
47b1fb7c09 Init load trace list. 2023-03-28 07:51:16 +08:00
maskpp
d5cedb9876 trigger ci 2023-03-28 06:44:38 +08:00
maskpp
3e5df55086 fix ci 2023-03-28 05:58:53 +08:00
maskpp
ed3486426b fix ci 2023-03-28 05:37:50 +08:00
maskpp
b78ec9a4a1 fine-tuning 2023-03-28 05:31:39 +08:00
maskpp
f60b4181e5 fix ci 2023-03-27 21:55:01 +08:00
maskpp
1060833f17 Update docker_app.go
fix ci
2023-03-27 21:18:11 +08:00
maskpp
3de0f9c24f fine-tuning 2023-03-27 20:08:38 +08:00
maskpp
bc0d5a9696 fix ci 2023-03-27 19:58:54 +08:00
maskpp
1d70c0f36b add comments 2023-03-27 19:58:01 +08:00
maskpp
a1099de5b2 fix ci 2023-03-27 19:45:27 +08:00
maskpp
aa352717f8 Merge branch 'develop' into feat/integration-test_upgrade 2023-03-27 19:27:55 +08:00
maskpp
f26ab8b727 fix ci 2023-03-27 19:27:07 +08:00
maskpp
dd8b5ef0b5 simplify integration-test framework 2023-03-27 18:56:31 +08:00
maskpp
4fd2abadd5 temporary code 2023-03-20 13:25:01 +08:00
33 changed files with 764 additions and 663 deletions

View File

@@ -0,0 +1,86 @@
package app
import (
"encoding/json"
"fmt"
"os"
"testing"
"time"
"scroll-tech/common/cmd"
"scroll-tech/common/docker"
"scroll-tech/common/utils"
bridgeConfig "scroll-tech/bridge/config"
)
// BridgeApp bridge-test client manager.
type BridgeApp struct {
Config *bridgeConfig.Config
base *docker.App
originFile string
bridgeFile string
name string
args []string
docker.AppAPI
}
// NewBridgeApp return a new bridgeApp manager.
func NewBridgeApp(base *docker.App, file string) *BridgeApp {
bridgeFile := fmt.Sprintf("/tmp/%d_bridge-config.json", base.Timestamp)
bridgeApp := &BridgeApp{
base: base,
name: "bridge-test",
originFile: file,
bridgeFile: bridgeFile,
args: []string{"--log.debug", "--config", bridgeFile},
}
if err := bridgeApp.MockConfig(true); err != nil {
panic(err)
}
return bridgeApp
}
// RunApp run bridge-test child process by multi parameters.
func (b *BridgeApp) RunApp(t *testing.T, args ...string) {
b.AppAPI = cmd.NewCmd("bridge-test", append(b.args, args...)...)
b.AppAPI.RunApp(func() bool { return b.AppAPI.WaitResult(t, time.Second*20, "Start bridge successfully") })
}
// Free stop and release bridge-test.
func (b *BridgeApp) Free() {
if !utils.IsNil(b.AppAPI) {
b.AppAPI.WaitExit()
}
_ = os.Remove(b.bridgeFile)
}
// MockConfig creates a new bridge config.
func (b *BridgeApp) MockConfig(store bool) error {
base := b.base
// Load origin bridge config file.
cfg, err := bridgeConfig.NewConfig(b.originFile)
if err != nil {
return err
}
cfg.L1Config.Endpoint = base.L1gethImg.Endpoint()
cfg.L2Config.RelayerConfig.SenderConfig.Endpoint = base.L1gethImg.Endpoint()
cfg.L2Config.Endpoint = base.L2gethImg.Endpoint()
cfg.L1Config.RelayerConfig.SenderConfig.Endpoint = base.L2gethImg.Endpoint()
cfg.DBConfig.DSN = base.DBImg.Endpoint()
b.Config = cfg
if !store {
return nil
}
// Store changed bridge config into a temp file.
data, err := json.Marshal(b.Config)
if err != nil {
return err
}
return os.WriteFile(b.bridgeFile, data, 0600)
}

View File

@@ -27,10 +27,13 @@
},
"finalize_batch_interval_sec": 0,
"message_sender_private_keys": [
"1212121212121212121212121212121212121212121212121212121212121212"
"1212121212121212121212121212121212121212121212121212121212121213"
],
"gas_oracle_sender_private_keys": [
"1212121212121212121212121212121212121212121212121212121212121212"
"1212121212121212121212121212121212121212121212121212121212121215"
],
"rollup_sender_private_keys": [
"1212121212121212121212121212121212121212121212121212121212121214"
]
}
},
@@ -61,13 +64,13 @@
},
"finalize_batch_interval_sec": 0,
"message_sender_private_keys": [
"1212121212121212121212121212121212121212121212121212121212121212"
"1212121212121212121212121212121212121212121212121212121212121213"
],
"gas_oracle_sender_private_keys": [
"1212121212121212121212121212121212121212121212121212121212121212"
"1212121212121212121212121212121212121212121212121212121212121215"
],
"rollup_sender_private_keys": [
"1212121212121212121212121212121212121212121212121212121212121212"
"1212121212121212121212121212121212121212121212121212121212121214"
]
},
"batch_proposer_config": {

View File

@@ -3,8 +3,6 @@ package l1
import (
"testing"
"github.com/stretchr/testify/assert"
"scroll-tech/common/docker"
"scroll-tech/bridge/config"
@@ -20,27 +18,16 @@ var (
func TestMain(m *testing.M) {
base = docker.NewDockerApp()
var err error
cfg, err = config.NewConfig("../config.json")
if err != nil {
panic(err)
}
cfg.L2Config.RelayerConfig.SenderConfig.Endpoint = base.L1gethImg.Endpoint()
cfg.L1Config.RelayerConfig.SenderConfig.Endpoint = base.L2gethImg.Endpoint()
cfg.DBConfig = base.DBConfig
m.Run()
base.Free()
}
func setupEnv(t *testing.T) {
// Load config.
var err error
cfg, err = config.NewConfig("../config.json")
assert.NoError(t, err)
base.RunImages(t)
cfg.L2Config.RelayerConfig.SenderConfig.Endpoint = base.L1GethEndpoint()
cfg.L1Config.RelayerConfig.SenderConfig.Endpoint = base.L2GethEndpoint()
cfg.DBConfig.DSN = base.DBEndpoint()
}
func TestL1(t *testing.T) {
setupEnv(t)
t.Run("testCreateNewL1Relayer", testCreateNewL1Relayer)
t.Run("testStartWatcher", testStartWatcher)
}

View File

@@ -11,8 +11,10 @@ import (
"scroll-tech/database"
)
// testCreateNewRelayer test create new relayer instance and stop
func testCreateNewL1Relayer(t *testing.T) {
// TestCreateNewL1Relayer test create new relayer instance and stop
func TestCreateNewL1Relayer(t *testing.T) {
// Start docker containers.
base.RunImages(t)
// Create db handler and reset db.
db, err := database.NewOrmFactory(cfg.DBConfig)
assert.NoError(t, err)

View File

@@ -15,9 +15,10 @@ import (
geth_metrics "github.com/scroll-tech/go-ethereum/metrics"
"github.com/scroll-tech/go-ethereum/rpc"
"scroll-tech/database"
"scroll-tech/common/metrics"
"scroll-tech/common/types"
"scroll-tech/database"
cutil "scroll-tech/common/utils"

View File

@@ -3,27 +3,30 @@ package l1
import (
"context"
"testing"
"time"
"github.com/scroll-tech/go-ethereum/ethclient"
"github.com/stretchr/testify/assert"
"scroll-tech/database"
"scroll-tech/database/migrate"
)
func testStartWatcher(t *testing.T) {
func TestStartWatcher(t *testing.T) {
// Start docker containers.
base.RunImages(t)
// Create db handler and reset db.
db, err := database.NewOrmFactory(cfg.DBConfig)
assert.NoError(t, err)
assert.NoError(t, migrate.ResetDB(db.GetDB().DB))
defer db.Close()
client, err := ethclient.Dial(base.L1GethEndpoint())
client, err := base.L1Client()
assert.NoError(t, err)
l1Cfg := cfg.L1Config
watcher := NewWatcher(context.Background(), client, l1Cfg.StartHeight, l1Cfg.Confirmations, l1Cfg.L1MessengerAddress, l1Cfg.L1MessageQueueAddress, l1Cfg.RelayerConfig.RollupContractAddress, db)
watcher.Start()
time.Sleep(time.Millisecond * 500)
defer watcher.Stop()
}

View File

@@ -16,7 +16,12 @@ import (
"scroll-tech/common/types"
)
func testBatchProposerProposeBatch(t *testing.T) {
func TestBatchProposerProposeBatch(t *testing.T) {
// Start docker containers.
base.RunImages(t)
l2Cli, err := base.L2Client()
assert.NoError(t, err)
// Create db handler and reset db.
db, err := database.NewOrmFactory(cfg.DBConfig)
assert.NoError(t, err)
@@ -31,6 +36,16 @@ func testBatchProposerProposeBatch(t *testing.T) {
wc.Start()
defer wc.Stop()
batch, err := db.GetLatestBatch()
assert.NoError(t, err)
// Create a new batch.
batchData := types.NewBatchData(&types.BlockBatch{
Index: 0,
Hash: batch.Hash,
StateRoot: batch.StateRoot,
}, []*types.WrappedBlock{wrappedBlock1}, nil)
relayer, err := NewLayer2Relayer(context.Background(), l2Cli, db, cfg.L2Config.RelayerConfig)
assert.NoError(t, err)
@@ -48,12 +63,17 @@ func testBatchProposerProposeBatch(t *testing.T) {
assert.NoError(t, err)
assert.Equal(t, 0, len(infos))
exist, err := db.BatchRecordExist(batchData1.Hash().Hex())
exist, err := db.BatchRecordExist(batchData.Hash().Hex())
assert.NoError(t, err)
assert.Equal(t, true, exist)
}
func testBatchProposerGracefulRestart(t *testing.T) {
func TestBatchProposerGracefulRestart(t *testing.T) {
// Start docker containers.
base.RunImages(t)
l2Cli, err := base.L2Client()
assert.NoError(t, err)
// Create db handler and reset db.
db, err := database.NewOrmFactory(cfg.DBConfig)
assert.NoError(t, err)

View File

@@ -1,13 +1,9 @@
package l2
import (
"encoding/json"
"os"
"testing"
"github.com/scroll-tech/go-ethereum/ethclient"
"github.com/scroll-tech/go-ethereum/log"
"github.com/stretchr/testify/assert"
"scroll-tech/common/testdata"
"scroll-tech/common/docker"
"scroll-tech/common/types"
@@ -21,9 +17,6 @@ var (
base *docker.App
// l2geth client
l2Cli *ethclient.Client
// block trace
wrappedBlock1 *types.WrappedBlock
wrappedBlock2 *types.WrappedBlock
@@ -33,84 +26,47 @@ var (
batchData2 *types.BatchData
)
func setupEnv(t *testing.T) (err error) {
// Load config.
cfg, err = config.NewConfig("../config.json")
assert.NoError(t, err)
base.RunImages(t)
cfg.L2Config.RelayerConfig.SenderConfig.Endpoint = base.L1GethEndpoint()
cfg.L1Config.RelayerConfig.SenderConfig.Endpoint = base.L2GethEndpoint()
cfg.DBConfig.DSN = base.DBEndpoint()
// Create l2geth client.
l2Cli, err = base.L2Client()
assert.NoError(t, err)
templateBlockTrace1, err := os.ReadFile("../../common/testdata/blockTrace_02.json")
if err != nil {
return err
func init() {
trace02 := testdata.GetTrace("../../common/testdata/blockTrace_02.json")
wrappedBlock1 = &types.WrappedBlock{
Header: trace02.Header,
Transactions: trace02.Transactions,
WithdrawTrieRoot: trace02.WithdrawTrieRoot,
}
// unmarshal blockTrace
wrappedBlock1 = &types.WrappedBlock{}
if err = json.Unmarshal(templateBlockTrace1, wrappedBlock1); err != nil {
return err
}
parentBatch1 := &types.BlockBatch{
batchData1 = types.NewBatchData(&types.BlockBatch{
Index: 0,
Hash: "0x0cc6b102c2924402c14b2e3a19baccc316252bfdc44d9ec62e942d34e39ec729",
StateRoot: "0x2579122e8f9ec1e862e7d415cef2fb495d7698a8e5f0dddc5651ba4236336e7d",
}
batchData1 = types.NewBatchData(parentBatch1, []*types.WrappedBlock{wrappedBlock1}, nil)
}, []*types.WrappedBlock{wrappedBlock1}, nil)
templateBlockTrace2, err := os.ReadFile("../../common/testdata/blockTrace_03.json")
if err != nil {
return err
trace03 := testdata.GetTrace("../../common/testdata/blockTrace_03.json")
wrappedBlock2 = &types.WrappedBlock{
Header: trace03.Header,
Transactions: trace03.Transactions,
WithdrawTrieRoot: trace03.WithdrawTrieRoot,
}
// unmarshal blockTrace
wrappedBlock2 = &types.WrappedBlock{}
if err = json.Unmarshal(templateBlockTrace2, wrappedBlock2); err != nil {
return err
}
parentBatch2 := &types.BlockBatch{
batchData2 = types.NewBatchData(&types.BlockBatch{
Index: batchData1.Batch.BatchIndex,
Hash: batchData1.Hash().Hex(),
StateRoot: batchData1.Batch.NewStateRoot.String(),
}
batchData2 = types.NewBatchData(parentBatch2, []*types.WrappedBlock{wrappedBlock2}, nil)
}, []*types.WrappedBlock{wrappedBlock2}, nil)
log.Info("batchHash", "batchhash1", batchData1.Hash().Hex(), "batchhash2", batchData2.Hash().Hex())
return err
}
func TestMain(m *testing.M) {
base = docker.NewDockerApp()
// Load config.
var err error
cfg, err = config.NewConfig("../config.json")
if err != nil {
panic(err)
}
cfg.L2Config.RelayerConfig.SenderConfig.Endpoint = base.L1gethImg.Endpoint()
cfg.L1Config.RelayerConfig.SenderConfig.Endpoint = base.L2gethImg.Endpoint()
cfg.DBConfig = base.DBConfig
m.Run()
base.Free()
}
func TestFunction(t *testing.T) {
if err := setupEnv(t); err != nil {
t.Fatal(err)
}
// Run l2 watcher test cases.
t.Run("TestCreateNewWatcherAndStop", testCreateNewWatcherAndStop)
t.Run("TestMonitorBridgeContract", testMonitorBridgeContract)
t.Run("TestFetchMultipleSentMessageInOneBlock", testFetchMultipleSentMessageInOneBlock)
// Run l2 relayer test cases.
t.Run("TestCreateNewRelayer", testCreateNewRelayer)
t.Run("TestL2RelayerProcessSaveEvents", testL2RelayerProcessSaveEvents)
t.Run("TestL2RelayerProcessCommittedBatches", testL2RelayerProcessCommittedBatches)
t.Run("TestL2RelayerSkipBatches", testL2RelayerSkipBatches)
// Run batch proposer test cases.
t.Run("TestBatchProposerProposeBatch", testBatchProposerProposeBatch)
t.Run("TestBatchProposerGracefulRestart", testBatchProposerGracefulRestart)
}

View File

@@ -18,9 +18,10 @@ import (
"golang.org/x/sync/errgroup"
"modernc.org/mathutil"
"scroll-tech/database"
"scroll-tech/common/metrics"
"scroll-tech/common/types"
"scroll-tech/database"
cutil "scroll-tech/common/utils"

View File

@@ -32,7 +32,12 @@ var (
}
)
func testCreateNewRelayer(t *testing.T) {
func TestCreateNewRelayer(t *testing.T) {
// Start docker containers.
base.RunImages(t)
l2Cli, err := base.L2Client()
assert.NoError(t, err)
// Create db handler and reset db.
db, err := database.NewOrmFactory(cfg.DBConfig)
assert.NoError(t, err)
@@ -46,7 +51,12 @@ func testCreateNewRelayer(t *testing.T) {
relayer.Start()
}
func testL2RelayerProcessSaveEvents(t *testing.T) {
func TestL2RelayerProcessSaveEvents(t *testing.T) {
// Start docker containers.
base.RunImages(t)
l2Cli, err := base.L2Client()
assert.NoError(t, err)
// Create db handler and reset db.
db, err := database.NewOrmFactory(cfg.DBConfig)
assert.NoError(t, err)
@@ -96,7 +106,12 @@ func testL2RelayerProcessSaveEvents(t *testing.T) {
assert.Equal(t, types.MsgSubmitted, msg.Status)
}
func testL2RelayerProcessCommittedBatches(t *testing.T) {
func TestL2RelayerProcessCommittedBatches(t *testing.T) {
// Start docker containers.
base.RunImages(t)
l2Cli, err := base.L2Client()
assert.NoError(t, err)
// Create db handler and reset db.
db, err := database.NewOrmFactory(cfg.DBConfig)
assert.NoError(t, err)
@@ -132,7 +147,12 @@ func testL2RelayerProcessCommittedBatches(t *testing.T) {
assert.Equal(t, types.RollupFinalizing, status)
}
func testL2RelayerSkipBatches(t *testing.T) {
func TestL2RelayerSkipBatches(t *testing.T) {
// Start docker containers.
base.RunImages(t)
l2Cli, err := base.L2Client()
assert.NoError(t, err)
// Create db handler and reset db.
db, err := database.NewOrmFactory(cfg.DBConfig)
assert.NoError(t, err)

View File

@@ -19,10 +19,11 @@ import (
geth_metrics "github.com/scroll-tech/go-ethereum/metrics"
"github.com/scroll-tech/go-ethereum/rpc"
"scroll-tech/database"
"scroll-tech/common/metrics"
"scroll-tech/common/types"
cutil "scroll-tech/common/utils"
"scroll-tech/database"
bridge_abi "scroll-tech/bridge/abi"
"scroll-tech/bridge/utils"

View File

@@ -24,7 +24,12 @@ import (
"scroll-tech/database/migrate"
)
func testCreateNewWatcherAndStop(t *testing.T) {
func TestCreateNewWatcherAndStop(t *testing.T) {
// Start docker containers.
base.RunImages(t)
l2Cli, err := base.L2Client()
assert.NoError(t, err)
// Create db handler and reset db.
l2db, err := database.NewOrmFactory(cfg.DBConfig)
assert.NoError(t, err)
@@ -55,7 +60,12 @@ func testCreateNewWatcherAndStop(t *testing.T) {
assert.GreaterOrEqual(t, blockNum, uint64(numTransactions))
}
func testMonitorBridgeContract(t *testing.T) {
func TestMonitorBridgeContract(t *testing.T) {
// Start docker containers.
base.RunImages(t)
l2Cli, err := base.L2Client()
assert.NoError(t, err)
// Create db handler and reset db.
db, err := database.NewOrmFactory(cfg.DBConfig)
assert.NoError(t, err)
@@ -123,7 +133,12 @@ func testMonitorBridgeContract(t *testing.T) {
assert.Equal(t, 2, len(msgs))
}
func testFetchMultipleSentMessageInOneBlock(t *testing.T) {
func TestFetchMultipleSentMessageInOneBlock(t *testing.T) {
// Start docker containers.
base.RunImages(t)
l2Cli, err := base.L2Client()
assert.NoError(t, err)
// Create db handler and reset db.
db, err := database.NewOrmFactory(cfg.DBConfig)
assert.NoError(t, err)
@@ -149,10 +164,6 @@ func testFetchMultipleSentMessageInOneBlock(t *testing.T) {
var tx *geth_types.Transaction
for i := 0; i < numTransactions; i++ {
addr := common.HexToAddress("0x1c5a77d9fa7ef466951b2f01f724bca3a5820b63")
nonce, nounceErr := l2Cli.PendingNonceAt(context.Background(), addr)
assert.NoError(t, nounceErr)
auth.Nonce = big.NewInt(int64(nonce))
toAddress := common.HexToAddress("0x4592d8f8d7b001e72cb26a73e4fa1806a51ac79d")
message := []byte("testbridgecontract")
fee := big.NewInt(0)
@@ -167,10 +178,6 @@ func testFetchMultipleSentMessageInOneBlock(t *testing.T) {
}
// extra block mined
addr := common.HexToAddress("0x1c5a77d9fa7ef466951b2f01f724bca3a5820b63")
nonce, nounceErr := l2Cli.PendingNonceAt(context.Background(), addr)
assert.NoError(t, nounceErr)
auth.Nonce = big.NewInt(int64(nonce))
toAddress := common.HexToAddress("0x4592d8f8d7b001e72cb26a73e4fa1806a51ac79d")
message := []byte("testbridgecontract")
fee := big.NewInt(0)

View File

@@ -50,7 +50,7 @@ func setupEnv(t *testing.T) {
// Load default private key.
privateKeys = []*ecdsa.PrivateKey{priv}
cfg.L1Config.RelayerConfig.SenderConfig.Endpoint = base.L2GethEndpoint()
cfg.L1Config.RelayerConfig.SenderConfig.Endpoint = base.L2gethImg.Endpoint()
}
func TestSender(t *testing.T) {

View File

@@ -11,9 +11,9 @@ import (
"github.com/scroll-tech/go-ethereum/core/types"
"github.com/scroll-tech/go-ethereum/crypto"
"github.com/scroll-tech/go-ethereum/ethclient"
"github.com/scroll-tech/go-ethereum/rpc"
"github.com/stretchr/testify/assert"
"scroll-tech/bridge/cmd/app"
"scroll-tech/bridge/config"
"scroll-tech/bridge/mock_bridge"
@@ -26,7 +26,9 @@ var (
// private key
privateKey *ecdsa.PrivateKey
base *docker.App
bridgeApp *app.BridgeApp
base *docker.App
// clients
l1Client *ethclient.Client
@@ -51,99 +53,32 @@ var (
func TestMain(m *testing.M) {
base = docker.NewDockerApp()
bridgeApp = app.NewBridgeApp(base, "../config.json")
// Load config.
cfg = bridgeApp.Config
m.Run()
bridgeApp.Free()
base.Free()
}
func setupEnv(t *testing.T) {
// Start l1geth l2geth and postgres docker containers.
base.RunImages(t)
var err error
privateKey, err = crypto.ToECDSA(common.FromHex("1212121212121212121212121212121212121212121212121212121212121212"))
assert.NoError(t, err)
messagePrivateKey, err := crypto.ToECDSA(common.FromHex("1212121212121212121212121212121212121212121212121212121212121213"))
assert.NoError(t, err)
rollupPrivateKey, err := crypto.ToECDSA(common.FromHex("1212121212121212121212121212121212121212121212121212121212121214"))
assert.NoError(t, err)
gasOraclePrivateKey, err := crypto.ToECDSA(common.FromHex("1212121212121212121212121212121212121212121212121212121212121215"))
assert.NoError(t, err)
// Load config.
cfg, err = config.NewConfig("../config.json")
assert.NoError(t, err)
cfg.L1Config.Confirmations = rpc.LatestBlockNumber
cfg.L1Config.RelayerConfig.MessageSenderPrivateKeys = []*ecdsa.PrivateKey{messagePrivateKey}
cfg.L1Config.RelayerConfig.RollupSenderPrivateKeys = []*ecdsa.PrivateKey{rollupPrivateKey}
cfg.L1Config.RelayerConfig.GasOracleSenderPrivateKeys = []*ecdsa.PrivateKey{gasOraclePrivateKey}
cfg.L2Config.Confirmations = rpc.LatestBlockNumber
cfg.L2Config.RelayerConfig.MessageSenderPrivateKeys = []*ecdsa.PrivateKey{messagePrivateKey}
cfg.L2Config.RelayerConfig.RollupSenderPrivateKeys = []*ecdsa.PrivateKey{rollupPrivateKey}
cfg.L2Config.RelayerConfig.GasOracleSenderPrivateKeys = []*ecdsa.PrivateKey{gasOraclePrivateKey}
base.RunImages(t)
// Create l1geth container.
cfg.L2Config.RelayerConfig.SenderConfig.Endpoint = base.L1GethEndpoint()
cfg.L1Config.Endpoint = base.L1GethEndpoint()
// Create l2geth container.
cfg.L1Config.RelayerConfig.SenderConfig.Endpoint = base.L2GethEndpoint()
cfg.L2Config.Endpoint = base.L2GethEndpoint()
// Create db container.
cfg.DBConfig.DSN = base.DBEndpoint()
// Create l1geth and l2geth client.
l1Client, err = ethclient.Dial(cfg.L1Config.Endpoint)
l1Client, err = base.L1Client()
assert.NoError(t, err)
l2Client, err = ethclient.Dial(cfg.L2Config.Endpoint)
l2Client, err = base.L2Client()
assert.NoError(t, err)
// Create l1 and l2 auth
l1Auth = prepareAuth(t, l1Client, privateKey)
l2Auth = prepareAuth(t, l2Client, privateKey)
// send some balance to message and rollup sender
transferEther(t, l1Auth, l1Client, messagePrivateKey)
transferEther(t, l1Auth, l1Client, rollupPrivateKey)
transferEther(t, l1Auth, l1Client, gasOraclePrivateKey)
transferEther(t, l2Auth, l2Client, messagePrivateKey)
transferEther(t, l2Auth, l2Client, rollupPrivateKey)
transferEther(t, l2Auth, l2Client, gasOraclePrivateKey)
}
func transferEther(t *testing.T, auth *bind.TransactOpts, client *ethclient.Client, privateKey *ecdsa.PrivateKey) {
targetAddress := crypto.PubkeyToAddress(privateKey.PublicKey)
gasPrice, err := client.SuggestGasPrice(context.Background())
assert.NoError(t, err)
gasPrice.Mul(gasPrice, big.NewInt(2))
// Get pending nonce
nonce, err := client.PendingNonceAt(context.Background(), auth.From)
assert.NoError(t, err)
// 200 ether should be enough
value, ok := big.NewInt(0).SetString("0xad78ebc5ac6200000", 0)
assert.Equal(t, ok, true)
tx := types.NewTx(&types.LegacyTx{
Nonce: nonce,
To: &targetAddress,
Value: value,
Gas: 500000,
GasPrice: gasPrice,
})
signedTx, err := auth.Signer(auth.From, tx)
assert.NoError(t, err)
err = client.SendTransaction(context.Background(), signedTx)
assert.NoError(t, err)
receipt, err := bind.WaitMined(context.Background(), client, signedTx)
assert.NoError(t, err)
if receipt.Status != types.ReceiptStatusSuccessful {
t.Fatalf("Call failed")
}
l1Auth = prepareAuth(t, base.L1gethImg.ChainID(), privateKey)
l2Auth = prepareAuth(t, base.L2gethImg.ChainID(), privateKey)
}
func prepareContracts(t *testing.T) {
@@ -181,9 +116,7 @@ func prepareContracts(t *testing.T) {
cfg.L2Config.RelayerConfig.GasPriceOracleContractAddress = l2MessengerAddress
}
func prepareAuth(t *testing.T, client *ethclient.Client, privateKey *ecdsa.PrivateKey) *bind.TransactOpts {
chainID, err := client.ChainID(context.Background())
assert.NoError(t, err)
func prepareAuth(t *testing.T, chainID *big.Int, privateKey *ecdsa.PrivateKey) *bind.TransactOpts {
auth, err := bind.NewKeyedTransactorWithChainID(privateKey, chainID)
assert.NoError(t, err)
auth.Value = big.NewInt(0) // in wei

View File

@@ -1,8 +1,8 @@
package docker
import (
"context"
"crypto/rand"
"database/sql"
"encoding/json"
"fmt"
"math/big"
@@ -11,13 +11,11 @@ import (
"time"
"github.com/jmoiron/sqlx"
"github.com/modern-go/reflect2"
"github.com/scroll-tech/go-ethereum/ethclient"
"github.com/stretchr/testify/assert"
"scroll-tech/database"
"scroll-tech/common/cmd"
"scroll-tech/common/utils"
)
@@ -27,150 +25,154 @@ var (
dbStartPort = 30000
)
// AppAPI app interface.
type AppAPI interface {
WaitResult(t *testing.T, timeout time.Duration, keyword string) bool
RunApp(waitResult func() bool)
WaitExit()
ExpectWithTimeout(t *testing.T, parallel bool, timeout time.Duration, keyword string)
}
// App is collection struct of runtime docker images
type App struct {
l1gethImg ImgInstance
l2gethImg ImgInstance
L1gethImg GethImgInstance
L2gethImg GethImgInstance
DBImg ImgInstance
dbImg ImgInstance
dbConfig *database.DBConfig
dbClient *sql.DB
DBConfig *database.DBConfig
dbFile string
// common time stamp.
timestamp int
Timestamp int
}
// NewDockerApp returns new instance of dokerApp struct
func NewDockerApp() *App {
timestamp := time.Now().Nanosecond()
return &App{
timestamp: timestamp,
app := &App{
Timestamp: timestamp,
L1gethImg: newTestL1Docker(),
L2gethImg: newTestL2Docker(),
DBImg: newTestDBDocker("postgres"),
dbFile: fmt.Sprintf("/tmp/%d_db-config.json", timestamp),
}
if err := app.mockDBConfig(); err != nil {
panic(err)
}
return app
}
// RunImages runs all images togather
func (b *App) RunImages(t *testing.T) {
b.runDBImage(t)
b.runL1Geth(t)
b.runL2Geth(t)
b.RunDBImage(t)
b.RunL1Geth(t)
b.RunL2Geth(t)
}
func (b *App) runDBImage(t *testing.T) {
if b.dbImg != nil {
// RunDBImage starts postgres docker container.
func (b *App) RunDBImage(t *testing.T) {
if b.DBImg.IsRunning() {
return
}
b.dbImg = newTestDBDocker(t, "postgres")
if err := b.mockDBConfig(); err != nil {
_ = b.dbImg.Stop()
b.dbImg = nil
_ = os.Remove(b.dbFile)
t.Fatal(err)
}
}
// RunDBApp runs DB app with command
func (b *App) RunDBApp(t *testing.T, option, keyword string) {
args := []string{option, "--config", b.dbFile}
app := cmd.NewCmd("db_cli-test", args...)
defer app.WaitExit()
// Wait expect result.
app.ExpectWithTimeout(t, true, time.Second*3, keyword)
app.RunApp(nil)
assert.NoError(t, b.DBImg.Start())
var isRun bool
// try 5 times until the db is ready.
utils.TryTimes(10, func() bool {
db, _ := sqlx.Open("postgres", b.DBImg.Endpoint())
isRun = db != nil && db.Ping() == nil
return isRun
})
assert.Equal(t, true, isRun)
}
// Free clear all running images
func (b *App) Free() {
if b.l1gethImg != nil {
_ = b.l1gethImg.Stop()
b.l1gethImg = nil
if b.L1gethImg.IsRunning() {
_ = b.L1gethImg.Stop()
}
if b.l2gethImg != nil {
_ = b.l2gethImg.Stop()
b.l2gethImg = nil
if b.L2gethImg.IsRunning() {
_ = b.L2gethImg.Stop()
}
if b.dbImg != nil {
_ = b.dbImg.Stop()
b.dbImg = nil
if b.DBImg.IsRunning() {
_ = b.DBImg.Stop()
_ = os.Remove(b.dbFile)
if !utils.IsNil(b.dbClient) {
_ = b.dbClient.Close()
b.dbClient = nil
}
}
}
// L1GethEndpoint returns l1gethimg endpoint
func (b *App) L1GethEndpoint() string {
if b.l1gethImg != nil {
return b.l1gethImg.Endpoint()
}
return ""
}
// L2GethEndpoint returns l2gethimg endpoint
func (b *App) L2GethEndpoint() string {
if b.l2gethImg != nil {
return b.l2gethImg.Endpoint()
}
return ""
}
// DBEndpoint returns the endpoint of the dbimg
func (b *App) DBEndpoint() string {
return b.dbImg.Endpoint()
}
func (b *App) runL1Geth(t *testing.T) {
if b.l1gethImg != nil {
// RunL1Geth starts l1geth docker container.
func (b *App) RunL1Geth(t *testing.T) {
if b.L1gethImg.IsRunning() {
return
}
b.l1gethImg = newTestL1Docker(t)
assert.NoError(t, b.L1gethImg.Start())
}
// L1Client returns a ethclient by dialing running l1geth
func (b *App) L1Client() (*ethclient.Client, error) {
if b.l1gethImg == nil || reflect2.IsNil(b.l1gethImg) {
if utils.IsNil(b.L1gethImg) {
return nil, fmt.Errorf("l1 geth is not running")
}
client, err := ethclient.Dial(b.l1gethImg.Endpoint())
client, err := ethclient.Dial(b.L1gethImg.Endpoint())
if err != nil {
return nil, err
}
return client, nil
}
func (b *App) runL2Geth(t *testing.T) {
if b.l2gethImg != nil {
// RunL2Geth starts l2geth docker container.
func (b *App) RunL2Geth(t *testing.T) {
if b.L2gethImg.IsRunning() {
return
}
b.l2gethImg = newTestL2Docker(t)
assert.NoError(t, b.L2gethImg.Start())
}
// L2Client returns a ethclient by dialing running l2geth
func (b *App) L2Client() (*ethclient.Client, error) {
if b.l2gethImg == nil || reflect2.IsNil(b.l2gethImg) {
if utils.IsNil(b.L2gethImg) {
return nil, fmt.Errorf("l2 geth is not running")
}
client, err := ethclient.Dial(b.l2gethImg.Endpoint())
client, err := ethclient.Dial(b.L2gethImg.Endpoint())
if err != nil {
return nil, err
}
return client, nil
}
// DBClient create and return *sql.DB instance.
func (b App) DBClient(t *testing.T) *sql.DB {
if !utils.IsNil(b.dbClient) {
return b.dbClient
}
var (
cfg = b.DBConfig
err error
)
b.dbClient, err = sql.Open(cfg.DriverName, cfg.DSN)
assert.NoError(t, err)
b.dbClient.SetMaxOpenConns(cfg.MaxOpenNum)
b.dbClient.SetMaxIdleConns(cfg.MaxIdleNum)
assert.NoError(t, b.dbClient.Ping())
return b.dbClient
}
func (b *App) mockDBConfig() error {
if b.dbConfig == nil {
b.dbConfig = &database.DBConfig{
DSN: "",
DriverName: "postgres",
MaxOpenNum: 200,
MaxIdleNum: 20,
}
b.DBConfig = &database.DBConfig{
DSN: "",
DriverName: "postgres",
MaxOpenNum: 200,
MaxIdleNum: 20,
}
if b.dbImg != nil {
b.dbConfig.DSN = b.dbImg.Endpoint()
if b.DBImg != nil {
b.DBConfig.DSN = b.DBImg.Endpoint()
}
data, err := json.Marshal(b.dbConfig)
data, err := json.Marshal(b.DBConfig)
if err != nil {
return err
}
@@ -178,57 +180,17 @@ func (b *App) mockDBConfig() error {
return os.WriteFile(b.dbFile, data, 0644) //nolint:gosec
}
func newTestL1Docker(t *testing.T) ImgInstance {
func newTestL1Docker() GethImgInstance {
id, _ := rand.Int(rand.Reader, big.NewInt(2000))
imgL1geth := NewImgGeth("scroll_l1geth", "", "", 0, l1StartPort+int(id.Int64()))
assert.NoError(t, imgL1geth.Start())
// try 3 times to get chainID until is ok.
utils.TryTimes(10, func() bool {
client, _ := ethclient.Dial(imgL1geth.Endpoint())
if client != nil {
if _, err := client.ChainID(context.Background()); err == nil {
return true
}
}
return false
})
return imgL1geth
return NewImgGeth("scroll_l1geth", "", "", 0, l1StartPort+int(id.Int64()))
}
func newTestL2Docker(t *testing.T) ImgInstance {
func newTestL2Docker() GethImgInstance {
id, _ := rand.Int(rand.Reader, big.NewInt(2000))
imgL2geth := NewImgGeth("scroll_l2geth", "", "", 0, l2StartPort+int(id.Int64()))
assert.NoError(t, imgL2geth.Start())
// try 3 times to get chainID until is ok.
utils.TryTimes(10, func() bool {
client, _ := ethclient.Dial(imgL2geth.Endpoint())
if client != nil {
if _, err := client.ChainID(context.Background()); err == nil {
return true
}
}
return false
})
return imgL2geth
return NewImgGeth("scroll_l2geth", "", "", 0, l2StartPort+int(id.Int64()))
}
func newTestDBDocker(t *testing.T, driverName string) ImgInstance {
func newTestDBDocker(driverName string) ImgInstance {
id, _ := rand.Int(rand.Reader, big.NewInt(2000))
imgDB := NewImgDB(driverName, "123456", "test_db", dbStartPort+int(id.Int64()))
assert.NoError(t, imgDB.Start())
// try 5 times until the db is ready.
utils.TryTimes(10, func() bool {
db, _ := sqlx.Open(driverName, imgDB.Endpoint())
if db != nil {
return db.Ping() == nil
}
return false
})
return imgDB
return NewImgDB(driverName, "123456", "test_db", dbStartPort+int(id.Int64()))
}

View File

@@ -75,12 +75,14 @@ func (i *ImgDB) Stop() error {
// Endpoint return the dsn.
func (i *ImgDB) Endpoint() string {
if !i.running {
return ""
}
return fmt.Sprintf("postgres://postgres:%s@localhost:%d/%s?sslmode=disable", i.password, i.port, i.dbName)
}
// IsRunning returns docker container's running status.
func (i *ImgDB) IsRunning() bool {
return i.running
}
func (i *ImgDB) prepare() []string {
cmd := []string{"docker", "run", "--name", i.name, "-p", fmt.Sprintf("%d:5432", i.port)}
envs := []string{

View File

@@ -3,11 +3,13 @@ package docker
import (
"context"
"fmt"
"math/big"
"strconv"
"strings"
"time"
"github.com/docker/docker/api/types"
"github.com/scroll-tech/go-ethereum/ethclient"
"scroll-tech/common/cmd"
"scroll-tech/common/utils"
@@ -23,13 +25,14 @@ type ImgGeth struct {
ipcPath string
httpPort int
wsPort int
chainID *big.Int
running bool
cmd *cmd.Cmd
}
// NewImgGeth return geth img instance.
func NewImgGeth(image, volume, ipc string, hPort, wPort int) ImgInstance {
func NewImgGeth(image, volume, ipc string, hPort, wPort int) GethImgInstance {
img := &ImgGeth{
image: image,
name: fmt.Sprintf("%s-%d", image, time.Now().Nanosecond()),
@@ -53,14 +56,28 @@ func (i *ImgGeth) Start() error {
_ = i.Stop()
return fmt.Errorf("failed to start image: %s", i.image)
}
// try 10 times to get chainID until is ok.
utils.TryTimes(10, func() bool {
client, _ := ethclient.Dial(i.Endpoint())
if client != nil {
var err error
i.chainID, err = client.ChainID(context.Background())
return err == nil && i.chainID != nil
}
return false
})
return nil
}
// IsRunning returns docker container's running status.
func (i *ImgGeth) IsRunning() bool {
return i.running
}
// Endpoint return the connection endpoint.
func (i *ImgGeth) Endpoint() string {
if !i.running {
return ""
}
switch true {
case i.httpPort != 0:
return fmt.Sprintf("http://127.0.0.1:%d", i.httpPort)
@@ -71,6 +88,11 @@ func (i *ImgGeth) Endpoint() string {
}
}
// ChainID return chainID.
func (i *ImgGeth) ChainID() *big.Int {
return i.chainID
}
func (i *ImgGeth) isOk() bool {
keyword := "WebSocket enabled"
okCh := make(chan struct{}, 1)

View File

@@ -8,8 +8,6 @@ import (
_ "github.com/lib/pq" //nolint:golint
"github.com/stretchr/testify/assert"
_ "scroll-tech/database/cmd/app"
"scroll-tech/common/docker"
)
@@ -25,50 +23,32 @@ func TestMain(m *testing.M) {
base.Free()
}
func TestStartProcess(t *testing.T) {
base.RunImages(t)
func TestDB(t *testing.T) {
base.RunDBImage(t)
// migrate db.
base.RunDBApp(t, "reset", "successful to reset")
base.RunDBApp(t, "migrate", "current version:")
db, err := sqlx.Open("postgres", base.DBImg.Endpoint())
assert.NoError(t, err)
assert.NoError(t, db.Ping())
}
func TestDocker(t *testing.T) {
base.RunImages(t)
t.Parallel()
t.Run("testL1Geth", testL1Geth)
t.Run("testL2Geth", testL2Geth)
t.Run("testDB", testDB)
}
func testL1Geth(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
func TestL1Geth(t *testing.T) {
base.RunL1Geth(t)
client, err := base.L1Client()
assert.NoError(t, err)
chainID, err := client.ChainID(ctx)
chainID, err := client.ChainID(context.Background())
assert.NoError(t, err)
t.Logf("chainId: %s", chainID.String())
}
func testL2Geth(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
func TestL2Geth(t *testing.T) {
base.RunL2Geth(t)
client, err := base.L2Client()
assert.NoError(t, err)
chainID, err := client.ChainID(ctx)
chainID, err := client.ChainID(context.Background())
assert.NoError(t, err)
t.Logf("chainId: %s", chainID.String())
}
func testDB(t *testing.T) {
driverName := "postgres"
db, err := sqlx.Open(driverName, base.DBEndpoint())
assert.NoError(t, err)
assert.NoError(t, db.Ping())
}

View File

@@ -2,6 +2,7 @@ package docker
import (
"context"
"math/big"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/filters"
@@ -26,6 +27,13 @@ type ImgInstance interface {
Start() error
Stop() error
Endpoint() string
IsRunning() bool
}
// GethImgInstance based on ImgInstance and add chainID interface.
type GethImgInstance interface {
ImgInstance
ChainID() *big.Int
}
// GetContainerID returns the ID of Container.

View File

@@ -28,6 +28,15 @@
"alloc": {
"1c5a77d9fa7ef466951b2f01f724bca3a5820b63": {
"balance": "0x200000000000000000000000000000000000000000000000000000000000000"
},
"9df85aB621C5F676D4b7fC5Ba6b8eD3E79b424e4": {
"balance": "0x200000000000000000000000000000000000000000000000000000000000000"
},
"78d46B4eFB1cF32757277B7828E2765A3f8f9F14": {
"balance": "0x200000000000000000000000000000000000000000000000000000000000000"
},
"60147F812CB308ee3aA7FF839e1f46a289e5FbF5": {
"balance": "0x200000000000000000000000000000000000000000000000000000000000000"
}
},
"number": "0x0",

View File

@@ -28,6 +28,15 @@
"alloc": {
"1c5a77d9fa7ef466951b2f01f724bca3a5820b63": {
"balance": "0x200000000000000000000000000000000000000000000000000000000000000"
},
"9df85aB621C5F676D4b7fC5Ba6b8eD3E79b424e4": {
"balance": "0x200000000000000000000000000000000000000000000000000000000000000"
},
"78d46B4eFB1cF32757277B7828E2765A3f8f9F14": {
"balance": "0x200000000000000000000000000000000000000000000000000000000000000"
},
"60147F812CB308ee3aA7FF839e1f46a289e5FbF5": {
"balance": "0x200000000000000000000000000000000000000000000000000000000000000"
}
},
"number": "0x0",

21
common/testdata/testdata.go vendored Normal file
View File

@@ -0,0 +1,21 @@
package testdata
import (
"encoding/json"
"os"
"github.com/scroll-tech/go-ethereum/core/types"
)
// GetTrace returns trace by file name.
func GetTrace(file string) *types.BlockTrace {
data, err := os.ReadFile(file)
if err != nil {
panic(err)
}
trace := &types.BlockTrace{}
if err = json.Unmarshal(data, &trace); err != nil {
panic(err)
}
return trace
}

View File

@@ -3,6 +3,8 @@ package utils
import (
"context"
"time"
"github.com/modern-go/reflect2"
)
// TryTimes try run several times until the function return true.
@@ -42,3 +44,8 @@ func Loop(ctx context.Context, period time.Duration, f func()) {
}
}
}
// IsNil Check if the interface is empty.
func IsNil(i interface{}) bool {
return i == nil || reflect2.IsNil(i)
}

View File

@@ -0,0 +1,103 @@
package app
import (
"crypto/rand"
"encoding/json"
"fmt"
"math/big"
"os"
"strconv"
"testing"
"time"
coordinatorConfig "scroll-tech/coordinator/config"
"scroll-tech/common/cmd"
"scroll-tech/common/docker"
"scroll-tech/common/utils"
)
var (
wsStartPort int64 = 40000
)
// CoordinatorApp coordinator-test client manager.
type CoordinatorApp struct {
Config *coordinatorConfig.Config
base *docker.App
originFile string
coordinatorFile string
WSPort int64
args []string
docker.AppAPI
}
// NewCoordinatorApp return a new coordinatorApp manager.
func NewCoordinatorApp(base *docker.App, file string) *CoordinatorApp {
coordinatorFile := fmt.Sprintf("/tmp/%d_coordinator-config.json", base.Timestamp)
port, _ := rand.Int(rand.Reader, big.NewInt(2000))
wsPort := port.Int64() + wsStartPort
coordinatorApp := &CoordinatorApp{
base: base,
originFile: file,
coordinatorFile: coordinatorFile,
WSPort: wsPort,
args: []string{"--log.debug", "--config", coordinatorFile, "--ws", "--ws.port", strconv.Itoa(int(wsPort))},
}
if err := coordinatorApp.MockConfig(true); err != nil {
panic(err)
}
return coordinatorApp
}
// RunApp run coordinator-test child process by multi parameters.
func (c *CoordinatorApp) RunApp(t *testing.T, args ...string) {
c.AppAPI = cmd.NewCmd("coordinator-test", append(c.args, args...)...)
c.AppAPI.RunApp(func() bool { return c.AppAPI.WaitResult(t, time.Second*20, "Start coordinator successfully") })
}
// Free stop and release coordinator-test.
func (c *CoordinatorApp) Free() {
if !utils.IsNil(c.AppAPI) {
c.AppAPI.WaitExit()
}
_ = os.Remove(c.coordinatorFile)
}
// WSEndpoint returns ws endpoint.
func (c *CoordinatorApp) WSEndpoint() string {
return fmt.Sprintf("ws://localhost:%d", c.WSPort)
}
// MockConfig creates a new coordinator config.
func (c *CoordinatorApp) MockConfig(store bool) error {
base := c.base
cfg, err := coordinatorConfig.NewConfig(c.originFile)
if err != nil {
return err
}
// Reset roller manager config for manager test cases.
cfg.RollerManagerConfig = &coordinatorConfig.RollerManagerConfig{
RollersPerSession: 1,
Verifier: &coordinatorConfig.VerifierConfig{MockMode: true},
CollectionTime: 1,
TokenTimeToLive: 1,
}
cfg.DBConfig.DSN = base.DBImg.Endpoint()
cfg.L2Config.Endpoint = base.L2gethImg.Endpoint()
c.Config = cfg
if !store {
return nil
}
data, err := json.Marshal(c.Config)
if err != nil {
return err
}
return os.WriteFile(c.coordinatorFile, data, 0644)
}

View File

@@ -18,10 +18,11 @@ import (
geth_metrics "github.com/scroll-tech/go-ethereum/metrics"
"github.com/scroll-tech/go-ethereum/rpc"
"scroll-tech/database"
"scroll-tech/common/message"
"scroll-tech/common/metrics"
"scroll-tech/common/types"
"scroll-tech/database"
"scroll-tech/common/utils/workerpool"

View File

@@ -56,7 +56,7 @@ func setEnv(t *testing.T) (err error) {
base.RunImages(t)
// Create db container.
cfg.DBConfig.DSN = base.DBEndpoint()
cfg.DBConfig = base.DBConfig
templateBlockTrace, err := os.ReadFile("../common/testdata/blockTrace_02.json")
if err != nil {

View File

@@ -1,43 +1,29 @@
package migrate
import (
"database/sql"
"testing"
"github.com/jmoiron/sqlx"
_ "github.com/lib/pq"
"github.com/stretchr/testify/assert"
"scroll-tech/common/docker"
"scroll-tech/database"
)
var (
base *docker.App
pgDB *sqlx.DB
pgDB *sql.DB
)
func initEnv(t *testing.T) error {
func initEnv(t *testing.T) {
// Start db container.
base.RunImages(t)
// Create db orm handler.
factory, err := database.NewOrmFactory(&database.DBConfig{
DriverName: "postgres",
DSN: base.DBEndpoint(),
})
if err != nil {
return err
}
pgDB = factory.GetDB()
return nil
base.RunDBImage(t)
pgDB = base.DBClient(t)
}
func TestMigrate(t *testing.T) {
base = docker.NewDockerApp()
if err := initEnv(t); err != nil {
t.Fatal(err)
}
initEnv(t)
t.Run("testCurrent", testCurrent)
t.Run("testStatus", testStatus)
@@ -51,39 +37,39 @@ func TestMigrate(t *testing.T) {
}
func testCurrent(t *testing.T) {
cur, err := Current(pgDB.DB)
cur, err := Current(pgDB)
assert.NoError(t, err)
assert.Equal(t, 0, int(cur))
}
func testStatus(t *testing.T) {
status := Status(pgDB.DB)
status := Status(pgDB)
assert.NoError(t, status)
}
func testResetDB(t *testing.T) {
assert.NoError(t, ResetDB(pgDB.DB))
cur, err := Current(pgDB.DB)
assert.NoError(t, ResetDB(pgDB))
cur, err := Current(pgDB)
assert.NoError(t, err)
// total number of tables.
assert.Equal(t, 6, int(cur))
}
func testMigrate(t *testing.T) {
assert.NoError(t, Migrate(pgDB.DB))
cur, err := Current(pgDB.DB)
assert.NoError(t, Migrate(pgDB))
cur, err := Current(pgDB)
assert.NoError(t, err)
assert.Equal(t, true, cur > 0)
}
func testRollback(t *testing.T) {
version, err := Current(pgDB.DB)
version, err := Current(pgDB)
assert.NoError(t, err)
assert.Equal(t, true, version > 0)
assert.NoError(t, Rollback(pgDB.DB, nil))
assert.NoError(t, Rollback(pgDB, nil))
cur, err := Current(pgDB.DB)
cur, err := Current(pgDB)
assert.NoError(t, err)
assert.Equal(t, true, cur+1 == version)
}

View File

@@ -84,11 +84,16 @@ var (
ormSession orm.SessionInfoOrm
)
func TestMain(m *testing.M) {
base = docker.NewDockerApp()
dbConfig = base.DBConfig
m.Run()
base.Free()
}
func setupEnv(t *testing.T) error {
// Init db config and start db container.
dbConfig = &database.DBConfig{DriverName: "postgres"}
base.RunImages(t)
dbConfig.DSN = base.DBEndpoint()
base.RunDBImage(t)
// Create db handler and reset db.
factory, err := database.NewOrmFactory(dbConfig)
@@ -97,7 +102,7 @@ func setupEnv(t *testing.T) error {
assert.NoError(t, migrate.ResetDB(db.DB))
// Init several orm handles.
ormBlock = orm.NewBlockTraceOrm(db)
ormBlock = factory
ormLayer1 = orm.NewL1MessageOrm(db)
ormLayer2 = orm.NewL2MessageOrm(db)
ormBatch = orm.NewBlockBatchOrm(db)
@@ -155,10 +160,6 @@ func setupEnv(t *testing.T) error {
// TestOrmFactory run several test cases.
func TestOrmFactory(t *testing.T) {
base = docker.NewDockerApp()
defer func() {
base.Free()
}()
if err := setupEnv(t); err != nil {
t.Fatal(err)
}
@@ -175,10 +176,8 @@ func TestOrmFactory(t *testing.T) {
}
func testOrmBlockTraces(t *testing.T) {
// Create db handler and reset db.
factory, err := database.NewOrmFactory(dbConfig)
assert.NoError(t, err)
assert.NoError(t, migrate.ResetDB(factory.GetDB().DB))
// reset db.
assert.NoError(t, migrate.ResetDB(base.DBClient(t)))
res, err := ormBlock.GetL2WrappedBlocks(map[string]interface{}{})
assert.NoError(t, err)

164
roller/cmd/app/mock_app.go Normal file
View File

@@ -0,0 +1,164 @@
package app
import (
"encoding/json"
"fmt"
"os"
"sync"
"testing"
"time"
"golang.org/x/sync/errgroup"
rollerConfig "scroll-tech/roller/config"
"scroll-tech/common/cmd"
"scroll-tech/common/docker"
"scroll-tech/common/utils"
)
var (
rollerIndex int
)
func getIndex() int {
defer func() { rollerIndex++ }()
return rollerIndex
}
// RollerApp roller-test client manager.
type RollerApp struct {
Config *rollerConfig.Config
base *docker.App
originFile string
rollerFile string
bboltDB string
keystore string
index int
name string
args []string
docker.AppAPI
}
// NewRollerApp return a new rollerApp manager.
func NewRollerApp(base *docker.App, file string, wsUrl string) *RollerApp {
rollerFile := fmt.Sprintf("/tmp/%d_roller-config.json", base.Timestamp)
rollerApp := &RollerApp{
base: base,
originFile: file,
rollerFile: rollerFile,
bboltDB: fmt.Sprintf("/tmp/%d_bbolt_db", base.Timestamp),
index: getIndex(),
name: "roller-test",
args: []string{"--log.debug", "--config", rollerFile},
}
if err := rollerApp.MockConfig(true, wsUrl); err != nil {
panic(err)
}
return rollerApp
}
// RunApp run roller-test child process by multi parameters.
func (r *RollerApp) RunApp(t *testing.T, args ...string) {
r.AppAPI = cmd.NewCmd(r.name, append(r.args, args...)...)
r.AppAPI.RunApp(func() bool { return r.AppAPI.WaitResult(t, time.Second*40, "roller start successfully") })
}
// Free stop and release roller-test.
func (r *RollerApp) Free() {
if !utils.IsNil(r.AppAPI) {
r.AppAPI.WaitExit()
}
_ = os.Remove(r.rollerFile)
_ = os.Remove(r.Config.KeystorePath)
_ = os.Remove(r.bboltDB)
}
// MockConfig creates a new roller config.
func (r *RollerApp) MockConfig(store bool, wsUrl string) error {
cfg, err := rollerConfig.NewConfig(r.originFile)
if err != nil {
return err
}
cfg.RollerName = fmt.Sprintf("%s_%d", r.name, r.index)
cfg.KeystorePath = fmt.Sprintf("/tmp/%d_%s.json", r.base.Timestamp, cfg.RollerName)
// Reuse l1geth's keystore file
cfg.KeystorePassword = "scrolltest"
cfg.DBPath = r.bboltDB
// Create keystore file.
_, err = utils.LoadOrCreateKey(cfg.KeystorePath, cfg.KeystorePassword)
if err != nil {
return err
}
cfg.CoordinatorURL = wsUrl
r.Config = cfg
if !store {
return nil
}
data, err := json.Marshal(r.Config)
if err != nil {
return err
}
return os.WriteFile(r.rollerFile, data, 0644)
}
// RollerApps rollerApp list.
type RollerApps []*RollerApp
// RunApps starts all the rollerApps.
func (r RollerApps) RunApps(t *testing.T, args ...string) {
var eg errgroup.Group
for i := range r {
i := i
eg.Go(func() error {
r[i].RunApp(t, args...)
return nil
})
}
_ = eg.Wait()
}
// MockConfigs creates all the rollerApps' configs.
func (r RollerApps) MockConfigs(store bool, wsUrl string) error {
var eg errgroup.Group
for _, roller := range r {
roller := roller
eg.Go(func() error {
return roller.MockConfig(store, wsUrl)
})
}
return eg.Wait()
}
// Free releases rollerApps.
func (r RollerApps) Free() {
var wg sync.WaitGroup
wg.Add(len(r))
for i := range r {
i := i
go func() {
r[i].Free()
wg.Done()
}()
}
wg.Wait()
}
// WaitExit wait rollerApps stopped.
func (r RollerApps) WaitExit() {
var wg sync.WaitGroup
wg.Add(len(r))
for i := range r {
i := i
go func() {
r[i].WaitExit()
wg.Done()
}()
}
wg.Wait()
}

View File

@@ -7,6 +7,7 @@ require (
github.com/stretchr/testify v1.8.2
github.com/urfave/cli/v2 v2.17.2-0.20221006022127-8f469abc00aa
go.etcd.io/bbolt v1.3.6
golang.org/x/sync v0.1.0
)
require (

View File

@@ -79,6 +79,8 @@ golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A=
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=

View File

@@ -1,203 +0,0 @@
package integration
import (
"context"
"crypto/ecdsa"
"crypto/rand"
"encoding/json"
"fmt"
"math/big"
"os"
"strconv"
"testing"
"time"
"github.com/scroll-tech/go-ethereum/crypto"
"github.com/scroll-tech/go-ethereum/rpc"
"github.com/stretchr/testify/assert"
"scroll-tech/database"
_ "scroll-tech/database/cmd/app"
_ "scroll-tech/roller/cmd/app"
rollerConfig "scroll-tech/roller/config"
_ "scroll-tech/bridge/cmd/app"
bridgeConfig "scroll-tech/bridge/config"
"scroll-tech/bridge/sender"
"scroll-tech/common/cmd"
"scroll-tech/common/docker"
_ "scroll-tech/coordinator/cmd/app"
coordinatorConfig "scroll-tech/coordinator/config"
)
var (
base *docker.App
timestamp int
wsPort int64
bridgeFile string
dbFile string
coordinatorFile string
bboltDB string
rollerFile string
)
func setupEnv(t *testing.T) {
// Start l1geth l2geth and postgres.
base.RunImages(t)
// Create a random ws port.
port, _ := rand.Int(rand.Reader, big.NewInt(2000))
wsPort = port.Int64() + 22000
timestamp = time.Now().Nanosecond()
// Load reset and store config into a random file.
bridgeFile = mockBridgeConfig(t)
dbFile = mockDatabaseConfig(t)
coordinatorFile = mockCoordinatorConfig(t)
rollerFile = mockRollerConfig(t)
}
func free(t *testing.T) {
base.Free()
// Delete temporary files.
assert.NoError(t, os.Remove(bridgeFile))
assert.NoError(t, os.Remove(dbFile))
assert.NoError(t, os.Remove(coordinatorFile))
assert.NoError(t, os.Remove(rollerFile))
assert.NoError(t, os.Remove(bboltDB))
}
type appAPI interface {
WaitResult(t *testing.T, timeout time.Duration, keyword string) bool
RunApp(waitResult func() bool)
WaitExit()
ExpectWithTimeout(t *testing.T, parallel bool, timeout time.Duration, keyword string)
}
func runBridgeApp(t *testing.T, args ...string) appAPI {
args = append(args, "--log.debug", "--config", bridgeFile)
return cmd.NewCmd("bridge-test", args...)
}
func runCoordinatorApp(t *testing.T, args ...string) appAPI {
args = append(args, "--log.debug", "--config", coordinatorFile, "--ws", "--ws.port", strconv.Itoa(int(wsPort)))
// start process
return cmd.NewCmd("coordinator-test", args...)
}
func runDBCliApp(t *testing.T, option, keyword string) {
args := []string{option, "--config", dbFile}
app := cmd.NewCmd("db_cli-test", args...)
defer app.WaitExit()
// Wait expect result.
app.ExpectWithTimeout(t, true, time.Second*3, keyword)
app.RunApp(nil)
}
func runRollerApp(t *testing.T, args ...string) appAPI {
args = append(args, "--log.debug", "--config", rollerFile)
return cmd.NewCmd("roller-test", args...)
}
func runSender(t *testing.T, endpoint string) *sender.Sender {
priv, err := crypto.HexToECDSA("1212121212121212121212121212121212121212121212121212121212121212")
assert.NoError(t, err)
newSender, err := sender.NewSender(context.Background(), &bridgeConfig.SenderConfig{
Endpoint: endpoint,
CheckPendingTime: 3,
EscalateBlocks: 100,
Confirmations: rpc.LatestBlockNumber,
EscalateMultipleNum: 11,
EscalateMultipleDen: 10,
TxType: "LegacyTx",
}, []*ecdsa.PrivateKey{priv})
assert.NoError(t, err)
return newSender
}
func mockBridgeConfig(t *testing.T) string {
// Load origin bridge config file.
cfg, err := bridgeConfig.NewConfig("../../bridge/config.json")
assert.NoError(t, err)
cfg.L1Config.Endpoint = base.L1GethEndpoint()
cfg.L2Config.RelayerConfig.SenderConfig.Endpoint = base.L1GethEndpoint()
cfg.L2Config.Endpoint = base.L2GethEndpoint()
cfg.L1Config.RelayerConfig.SenderConfig.Endpoint = base.L2GethEndpoint()
cfg.DBConfig.DSN = base.DBEndpoint()
// Store changed bridge config into a temp file.
data, err := json.Marshal(cfg)
assert.NoError(t, err)
file := fmt.Sprintf("/tmp/%d_bridge-config.json", timestamp)
err = os.WriteFile(file, data, 0644)
assert.NoError(t, err)
return file
}
func mockCoordinatorConfig(t *testing.T) string {
cfg, err := coordinatorConfig.NewConfig("../../coordinator/config.json")
assert.NoError(t, err)
cfg.RollerManagerConfig.Verifier.MockMode = true
cfg.DBConfig.DSN = base.DBEndpoint()
cfg.L2Config.Endpoint = base.L2GethEndpoint()
data, err := json.Marshal(cfg)
assert.NoError(t, err)
file := fmt.Sprintf("/tmp/%d_coordinator-config.json", timestamp)
err = os.WriteFile(file, data, 0644)
assert.NoError(t, err)
return file
}
func mockDatabaseConfig(t *testing.T) string {
cfg, err := database.NewConfig("../../database/config.json")
assert.NoError(t, err)
cfg.DSN = base.DBEndpoint()
data, err := json.Marshal(cfg)
assert.NoError(t, err)
file := fmt.Sprintf("/tmp/%d_db-config.json", timestamp)
err = os.WriteFile(file, data, 0644)
assert.NoError(t, err)
return file
}
func mockRollerConfig(t *testing.T) string {
cfg, err := rollerConfig.NewConfig("../../roller/config.json")
assert.NoError(t, err)
cfg.CoordinatorURL = fmt.Sprintf("ws://localhost:%d", wsPort)
// Reuse l1geth's keystore file
cfg.KeystorePath = "../../common/docker/l1geth/genesis-keystore"
cfg.KeystorePassword = "scrolltest"
bboltDB = fmt.Sprintf("/tmp/%d_bbolt_db", timestamp)
cfg.DBPath = bboltDB
assert.NoError(t, os.WriteFile(bboltDB, []byte{}, 0644))
data, err := json.Marshal(cfg)
assert.NoError(t, err)
file := fmt.Sprintf("/tmp/%d_roller-config.json", timestamp)
err = os.WriteFile(file, data, 0644)
assert.NoError(t, err)
return file
}

View File

@@ -5,75 +5,83 @@ import (
"io/ioutil"
"math/big"
"net/http"
"strconv"
"strings"
"testing"
"time"
"github.com/stretchr/testify/assert"
"scroll-tech/common/docker"
_ "scroll-tech/database/cmd/app"
"scroll-tech/database/migrate"
rApp "scroll-tech/roller/cmd/app"
cApp "scroll-tech/coordinator/cmd/app"
bApp "scroll-tech/bridge/cmd/app"
)
func TestIntegration(t *testing.T) {
var (
base *docker.App
bridge *bApp.BridgeApp
coordinator *cApp.CoordinatorApp
rollers rApp.RollerApps
)
func TestMain(m *testing.M) {
base = docker.NewDockerApp()
setupEnv(t)
bridge = bApp.NewBridgeApp(base, "../../bridge/config.json")
coordinator = cApp.NewCoordinatorApp(base, "../../coordinator/config.json")
rollers = append(rollers, rApp.NewRollerApp(base, "../../roller/config.json", coordinator.WSEndpoint()))
// test db_cli migrate cmd.
t.Run("testDBClientMigrate", func(t *testing.T) {
runDBCliApp(t, "migrate", "current version:")
})
m.Run()
// test bridge service
t.Run("testStartProcess", testStartProcess)
// test monitor metrics
t.Run("testMonitorMetrics", testMonitorMetrics)
t.Cleanup(func() {
free(t)
})
base.Free()
bridge.Free()
coordinator.Free()
rollers.Free()
}
func testStartProcess(t *testing.T) {
// migrate db.
runDBCliApp(t, "reset", "successful to reset")
runDBCliApp(t, "migrate", "current version:")
func TestStartProcess(t *testing.T) {
// Start l1geth l2geth and postgres docker containers.
base.RunImages(t)
// reset db.
assert.NoError(t, migrate.ResetDB(base.DBClient(t)))
// Start bridge process.
bridgeCmd := runBridgeApp(t)
bridgeCmd.RunApp(func() bool { return bridgeCmd.WaitResult(t, time.Second*20, "Start bridge successfully") })
// Start bridge.
bridge.RunApp(t)
// Start coordinator process.
coordinatorCmd := runCoordinatorApp(t, "--ws", "--ws.port", "8391")
coordinatorCmd.RunApp(func() bool { return coordinatorCmd.WaitResult(t, time.Second*20, "Start coordinator successfully") })
// Start coordinator, ws is enabled by default.
coordinator.RunApp(t)
// Start roller process.
rollerCmd := runRollerApp(t)
rollerCmd.ExpectWithTimeout(t, true, time.Second*60, "register to coordinator successfully!")
rollerCmd.RunApp(func() bool { return rollerCmd.WaitResult(t, time.Second*40, "roller start successfully") })
// Start rollers.
rollers.RunApps(t)
rollerCmd.WaitExit()
bridgeCmd.WaitExit()
coordinatorCmd.WaitExit()
rollers.WaitExit()
coordinator.WaitExit()
bridge.WaitExit()
}
func testMonitorMetrics(t *testing.T) {
// migrate db.
runDBCliApp(t, "reset", "successful to reset")
runDBCliApp(t, "migrate", "current version:")
func TestMonitorMetrics(t *testing.T) {
// Start l1geth l2geth and postgres docker containers.
base.RunImages(t)
// reset db.
assert.NoError(t, migrate.ResetDB(base.DBClient(t)))
// Start bridge process with metrics server.
port1, _ := rand.Int(rand.Reader, big.NewInt(2000))
svrPort1 := strconv.FormatInt(port1.Int64()+50000, 10)
bridgeCmd := runBridgeApp(t, "--metrics", "--metrics.addr", "localhost", "--metrics.port", svrPort1)
bridgeCmd.RunApp(func() bool { return bridgeCmd.WaitResult(t, time.Second*20, "Start bridge successfully") })
// Start bridge and open metrics flag.
bridge.RunApp(t, "--metrics", "--metrics.addr", "localhost", "--metrics.port", svrPort1)
// Start coordinator process with metrics server.
port, _ := rand.Int(rand.Reader, big.NewInt(2000))
svrPort2 := strconv.FormatInt(port.Int64()+52000, 10)
coordinatorCmd := runCoordinatorApp(t, "--metrics", "--metrics.addr", "localhost", "--metrics.port", svrPort2)
coordinatorCmd.RunApp(func() bool { return coordinatorCmd.WaitResult(t, time.Second*20, "Start coordinator successfully") })
// Start coordinator.
coordinator.RunApp(t, "--metrics", "--metrics.addr", "localhost", "--metrics.port", svrPort2)
// Get bridge monitor metrics.
resp, err := http.Get("http://localhost:" + svrPort1)
@@ -98,6 +106,6 @@ func testMonitorMetrics(t *testing.T) {
assert.Equal(t, true, strings.Contains(bodyStr, "coordinator_rollers_disconnects_total"))
// Exit.
bridgeCmd.WaitExit()
coordinatorCmd.WaitExit()
coordinator.WaitExit()
bridge.WaitExit()
}