diff --git a/bridge/cmd/event_watcher/app/app.go b/bridge/cmd/event_watcher/app/app.go index 24b96e489..cfb4db455 100644 --- a/bridge/cmd/event_watcher/app/app.go +++ b/bridge/cmd/event_watcher/app/app.go @@ -42,7 +42,7 @@ func init() { } // Register `event-watcher-test` app for integration-test. - cutils.RegisterSimulation(app, "event-watcher-test") + cutils.RegisterSimulation(app, cutils.EventWatcherApp) } func action(ctx *cli.Context) error { diff --git a/bridge/cmd/gas_oracle/app/app.go b/bridge/cmd/gas_oracle/app/app.go index 5fbde6696..b7a45bcc8 100644 --- a/bridge/cmd/gas_oracle/app/app.go +++ b/bridge/cmd/gas_oracle/app/app.go @@ -45,7 +45,7 @@ func init() { } // Register `gas-oracle-test` app for integration-test. - cutils.RegisterSimulation(app, "gas-oracle-test") + cutils.RegisterSimulation(app, cutils.GasOracleApp) } func action(ctx *cli.Context) error { diff --git a/bridge/cmd/mock_app.go b/bridge/cmd/mock_app.go new file mode 100644 index 000000000..96ee072b2 --- /dev/null +++ b/bridge/cmd/mock_app.go @@ -0,0 +1,106 @@ +package app + +import ( + "encoding/json" + "fmt" + "os" + "testing" + "time" + + "scroll-tech/common/cmd" + "scroll-tech/common/docker" + "scroll-tech/common/utils" + + "scroll-tech/bridge/config" +) + +// MockApp mockApp-test client manager. +type MockApp struct { + Config *config.Config + base *docker.App + + mockApps map[utils.MockAppName]docker.AppAPI + + originFile string + bridgeFile string + + args []string +} + +// NewBridgeApp return a new bridgeApp manager, name mush be one them. +func NewBridgeApp(base *docker.App, file string) *MockApp { + + bridgeFile := fmt.Sprintf("/tmp/%d_bridge-config.json", base.Timestamp) + bridgeApp := &MockApp{ + base: base, + mockApps: make(map[utils.MockAppName]docker.AppAPI), + 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 *MockApp) RunApp(t *testing.T, name utils.MockAppName, args ...string) { + if !(name == utils.EventWatcherApp || + name == utils.GasOracleApp || + name == utils.MessageRelayerApp || + name == utils.RollupRelayerApp) { + t.Errorf(fmt.Sprintf("Don't support the mock app, name: %s", name)) + return + } + + if app, ok := b.mockApps[name]; ok { + t.Logf(fmt.Sprintf("%s already exist, free the current and recreate again", string(name))) + app.WaitExit() + } + appAPI := cmd.NewCmd(string(name), append(b.args, args...)...) + keyword := fmt.Sprintf("Start %s successfully", string(name)[:len(string(name))-len("-test")]) + appAPI.RunApp(func() bool { return appAPI.WaitResult(t, time.Second*20, keyword) }) + b.mockApps[name] = appAPI +} + +// WaitExit wait util all processes exit. +func (b *MockApp) WaitExit() { + for _, app := range b.mockApps { + app.WaitExit() + } + b.mockApps = make(map[utils.MockAppName]docker.AppAPI) +} + +// Free stop and release bridge mocked apps. +func (b *MockApp) Free() { + b.WaitExit() + _ = os.Remove(b.bridgeFile) +} + +// MockConfig creates a new bridge config. +func (b *MockApp) MockConfig(store bool) error { + base := b.base + // Load origin bridge config file. + cfg, err := config.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) +} diff --git a/bridge/cmd/msg_relayer/app/app.go b/bridge/cmd/msg_relayer/app/app.go index d58b4f57a..f2e2d40b0 100644 --- a/bridge/cmd/msg_relayer/app/app.go +++ b/bridge/cmd/msg_relayer/app/app.go @@ -43,7 +43,7 @@ func init() { } // Register `message-relayer-test` app for integration-test. - cutils.RegisterSimulation(app, "message-relayer-test") + cutils.RegisterSimulation(app, cutils.MessageRelayerApp) } func action(ctx *cli.Context) error { diff --git a/bridge/cmd/rollup_relayer/app/app.go b/bridge/cmd/rollup_relayer/app/app.go index 1257242e8..f08cc659a 100644 --- a/bridge/cmd/rollup_relayer/app/app.go +++ b/bridge/cmd/rollup_relayer/app/app.go @@ -43,7 +43,7 @@ func init() { return cutils.LogSetup(ctx) } // Register `rollup-relayer-test` app for integration-test. - cutils.RegisterSimulation(app, "rollup-relayer-test") + cutils.RegisterSimulation(app, cutils.RollupRelayerApp) } func action(ctx *cli.Context) error { diff --git a/common/utils/simulation.go b/common/utils/simulation.go index d25aad2eb..097a9608c 100644 --- a/common/utils/simulation.go +++ b/common/utils/simulation.go @@ -8,10 +8,30 @@ import ( "github.com/urfave/cli/v2" ) +// MockAppName a new type mock app. +type MockAppName string + +var ( + // EventWatcherApp the name of mock event-watcher app. + EventWatcherApp MockAppName = "event-watcher-test" + // GasOracleApp the name of mock gas-oracle app. + GasOracleApp MockAppName = "gas-oracle-test" + // MessageRelayerApp the name of mock message-relayer app. + MessageRelayerApp MockAppName = "message-relayer-test" + // RollupRelayerApp the name of mock rollup-relayer app. + RollupRelayerApp MockAppName = "rollup-relayer-test" + // CoordinatorApp the name of mock coordinator app. + CoordinatorApp MockAppName = "coordinator-test" + // DBCliApp the name of mock database app. + DBCliApp MockAppName = "db_cli-test" + // RollerApp the name of mock roller app. + RollerApp MockAppName = "roller-test" +) + // RegisterSimulation register initializer function for integration-test. -func RegisterSimulation(app *cli.App, name string) { +func RegisterSimulation(app *cli.App, name MockAppName) { // Run the app for integration-test - reexec.Register(name, func() { + reexec.Register(string(name), func() { if err := app.Run(os.Args); err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(1) diff --git a/coordinator/cmd/app/app.go b/coordinator/cmd/app/app.go index cde24528f..6e07fc0ae 100644 --- a/coordinator/cmd/app/app.go +++ b/coordinator/cmd/app/app.go @@ -40,7 +40,7 @@ func init() { } // Register `coordinator-test` app for integration-test. - utils.RegisterSimulation(app, "coordinator-test") + utils.RegisterSimulation(app, utils.CoordinatorApp) } func action(ctx *cli.Context) error { diff --git a/coordinator/cmd/app/mock_app.go b/coordinator/cmd/app/mock_app.go new file mode 100644 index 000000000..c3e431b41 --- /dev/null +++ b/coordinator/cmd/app/mock_app.go @@ -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(string(utils.CoordinatorApp), 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) +} diff --git a/database/cmd/app/app.go b/database/cmd/app/app.go index e742b5fb8..5c048b89b 100644 --- a/database/cmd/app/app.go +++ b/database/cmd/app/app.go @@ -67,7 +67,7 @@ func init() { } // Register `db_cli-test` app for integration-test. - utils.RegisterSimulation(app, "db_cli-test") + utils.RegisterSimulation(app, utils.DBCliApp) } // Run run database cmd instance. diff --git a/roller/cmd/app/app.go b/roller/cmd/app/app.go index b580f395e..38b106d05 100644 --- a/roller/cmd/app/app.go +++ b/roller/cmd/app/app.go @@ -30,7 +30,7 @@ func init() { } // Register `roller-test` app for integration-test. - utils.RegisterSimulation(app, "roller-test") + utils.RegisterSimulation(app, utils.RollerApp) } func action(ctx *cli.Context) error { diff --git a/roller/cmd/app/mock_app.go b/roller/cmd/app/mock_app.go new file mode 100644 index 000000000..95d58dc95 --- /dev/null +++ b/roller/cmd/app/mock_app.go @@ -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: string(utils.RollerApp), + 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() +} diff --git a/roller/go.mod b/roller/go.mod index f693c693b..66cc8afcb 100644 --- a/roller/go.mod +++ b/roller/go.mod @@ -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 ( diff --git a/roller/go.sum b/roller/go.sum index be0270d52..393efc76e 100644 --- a/roller/go.sum +++ b/roller/go.sum @@ -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= diff --git a/tests/integration-test/common.go b/tests/integration-test/common.go deleted file mode 100644 index 3377dac69..000000000 --- a/tests/integration-test/common.go +++ /dev/null @@ -1,219 +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/cmd/app" - - _ "scroll-tech/roller/cmd/app" - rollerConfig "scroll-tech/roller/config" - - _ "scroll-tech/bridge/cmd/event_watcher/app" - _ "scroll-tech/bridge/cmd/gas_oracle/app" - _ "scroll-tech/bridge/cmd/msg_relayer/app" - _ "scroll-tech/bridge/cmd/rollup_relayer/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 - 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) - 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(coordinatorFile)) - assert.NoError(t, os.Remove(rollerFile)) - assert.NoError(t, os.Remove(bboltDB)) -} - -func runMsgRelayerApp(t *testing.T, args ...string) docker.AppAPI { - args = append(args, "--log.debug", "--config", bridgeFile) - app := cmd.NewCmd("message-relayer-test", args...) - app.OpenLog(true) - return app -} - -func runGasOracleApp(t *testing.T, args ...string) docker.AppAPI { - args = append(args, "--log.debug", "--config", bridgeFile) - app := cmd.NewCmd("gas-oracle-test", args...) - app.OpenLog(true) - return app -} - -func runRollupRelayerApp(t *testing.T, args ...string) docker.AppAPI { - args = append(args, "--log.debug", "--config", bridgeFile) - app := cmd.NewCmd("rollup-relayer-test", args...) - app.OpenLog(true) - return app -} - -func runEventWatcherApp(t *testing.T, args ...string) docker.AppAPI { - args = append(args, "--log.debug", "--config", bridgeFile) - app := cmd.NewCmd("event-watcher-test", args...) - app.OpenLog(true) - return app -} - -func runCoordinatorApp(t *testing.T, args ...string) docker.AppAPI { - args = append(args, "--log.debug", "--config", coordinatorFile, "--ws", "--ws.port", strconv.Itoa(int(wsPort))) - // start process - app := cmd.NewCmd("coordinator-test", args...) - app.OpenLog(true) - return app -} - -func runDBCliApp(t *testing.T, option, keyword string) { - args := []string{option, "--config", base.DBConfigFile} - app := cmd.NewCmd("db_cli-test", args...) - app.OpenLog(true) - defer app.WaitExit() - - // Wait expect result. - app.ExpectWithTimeout(t, true, time.Second*3, keyword) - app.RunApp(nil) -} - -func runRollerApp(t *testing.T, args ...string) docker.AppAPI { - args = append(args, "--log.debug", "--config", rollerFile) - app := cmd.NewCmd("roller-test", args...) - app.OpenLog(true) - return app -} - -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.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 = base.DBConfig - - // 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 = base.DBConfig - - cfg.L2Config.Endpoint = base.L2gethImg.Endpoint() - - 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 { - data, err := json.Marshal(base.DBConfig) - 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 -} diff --git a/tests/integration-test/integration_test.go b/tests/integration-test/integration_test.go index 5ace458b2..438e92f48 100644 --- a/tests/integration-test/integration_test.go +++ b/tests/integration-test/integration_test.go @@ -8,98 +8,91 @@ import ( "strconv" "strings" "testing" - "time" "github.com/stretchr/testify/assert" + bcmd "scroll-tech/bridge/cmd" + _ "scroll-tech/bridge/cmd/event_watcher/app" + _ "scroll-tech/bridge/cmd/gas_oracle/app" + _ "scroll-tech/bridge/cmd/msg_relayer/app" + _ "scroll-tech/bridge/cmd/rollup_relayer/app" + "scroll-tech/common/docker" + "scroll-tech/common/utils" + + capp "scroll-tech/coordinator/cmd/app" + "scroll-tech/database/migrate" + rapp "scroll-tech/roller/cmd/app" ) -func TestIntegration(t *testing.T) { +var ( + base *docker.App + bridgeApp *bcmd.MockApp + coordinatorApp *capp.CoordinatorApp + rollerApp *rapp.RollerApp +) + +func TestMain(m *testing.M) { base = docker.NewDockerApp() - setupEnv(t) - - // test db_cli migrate cmd. - t.Run("testDBClientMigrate", func(t *testing.T) { - runDBCliApp(t, "migrate", "current version:") - }) - - // test bridge service - t.Run("testStartProcess", testStartProcess) - - // test monitor metrics - t.Run("testMonitorMetrics", testMonitorMetrics) - - t.Cleanup(func() { - free(t) - }) + bridgeApp = bcmd.NewBridgeApp(base, "../../bridge/config.json") + coordinatorApp = capp.NewCoordinatorApp(base, "../../coordinator/config.json") + rollerApp = rapp.NewRollerApp(base, "../../roller/config.json", coordinatorApp.WSEndpoint()) + m.Run() + bridgeApp.Free() + coordinatorApp.Free() + rollerApp.Free() + base.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. - ewCmd := runEventWatcherApp(t) - ewCmd.RunApp(func() bool { return ewCmd.WaitResult(t, time.Second*20, "Start event-watcher successfully") }) + // Run bridge apps. + bridgeApp.RunApp(t, utils.EventWatcherApp) + bridgeApp.RunApp(t, utils.GasOracleApp) + bridgeApp.RunApp(t, utils.MessageRelayerApp) + bridgeApp.RunApp(t, utils.RollupRelayerApp) - goCmd := runGasOracleApp(t) - goCmd.RunApp(func() bool { return goCmd.WaitResult(t, time.Second*20, "Start gas-oracle successfully") }) + // Run coordinator app. + coordinatorApp.RunApp(t) + // Run roller app. + rollerApp.RunApp(t) - mrCmd := runMsgRelayerApp(t) - mrCmd.RunApp(func() bool { return mrCmd.WaitResult(t, time.Second*20, "Start message-relayer successfully") }) - - rrCmd := runRollupRelayerApp(t) - rrCmd.RunApp(func() bool { return rrCmd.WaitResult(t, time.Second*20, "Start rollup-relayer successfully") }) - - // 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 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") }) - - ewCmd.WaitExit() - goCmd.WaitExit() - mrCmd.WaitExit() - rrCmd.WaitExit() - rollerCmd.WaitExit() - coordinatorCmd.WaitExit() + // Free apps. + bridgeApp.WaitExit() + rollerApp.WaitExit() + coordinatorApp.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))) port1, _ := rand.Int(rand.Reader, big.NewInt(2000)) svrPort1 := strconv.FormatInt(port1.Int64()+50000, 10) - ewCmd := runEventWatcherApp(t, "--metrics", "--metrics.addr", "localhost", "--metrics.port", svrPort1) - ewCmd.RunApp(func() bool { return ewCmd.WaitResult(t, time.Second*20, "Start event-watcher successfully") }) + bridgeApp.RunApp(t, utils.EventWatcherApp, "--metrics", "--metrics.addr", "localhost", "--metrics.port", svrPort1) port2, _ := rand.Int(rand.Reader, big.NewInt(2000)) svrPort2 := strconv.FormatInt(port2.Int64()+50000, 10) - goCmd := runGasOracleApp(t, "--metrics", "--metrics.addr", "localhost", "--metrics.port", svrPort2) - goCmd.RunApp(func() bool { return goCmd.WaitResult(t, time.Second*20, "Start gas-oracle successfully") }) + bridgeApp.RunApp(t, utils.GasOracleApp, "--metrics", "--metrics.addr", "localhost", "--metrics.port", svrPort2) port3, _ := rand.Int(rand.Reader, big.NewInt(2000)) svrPort3 := strconv.FormatInt(port3.Int64()+50000, 10) - mrCmd := runMsgRelayerApp(t, "--metrics", "--metrics.addr", "localhost", "--metrics.port", svrPort3) - mrCmd.RunApp(func() bool { return mrCmd.WaitResult(t, time.Second*20, "Start message-relayer successfully") }) + bridgeApp.RunApp(t, utils.MessageRelayerApp, "--metrics", "--metrics.addr", "localhost", "--metrics.port", svrPort3) port4, _ := rand.Int(rand.Reader, big.NewInt(2000)) svrPort4 := strconv.FormatInt(port4.Int64()+50000, 10) - rrCmd := runRollupRelayerApp(t, "--metrics", "--metrics.addr", "localhost", "--metrics.port", svrPort4) - rrCmd.RunApp(func() bool { return rrCmd.WaitResult(t, time.Second*20, "Start rollup-relayer successfully") }) + bridgeApp.RunApp(t, utils.RollupRelayerApp, "--metrics", "--metrics.addr", "localhost", "--metrics.port", svrPort4) // Start coordinator process with metrics server. port5, _ := rand.Int(rand.Reader, big.NewInt(2000)) svrPort5 := strconv.FormatInt(port5.Int64()+52000, 10) - coordinatorCmd := runCoordinatorApp(t, "--metrics", "--metrics.addr", "localhost", "--metrics.port", svrPort5) - coordinatorCmd.RunApp(func() bool { return coordinatorCmd.WaitResult(t, time.Second*20, "Start coordinator successfully") }) + coordinatorApp.RunApp(t, "--metrics", "--metrics.addr", "localhost", "--metrics.port", svrPort5) // Get bridge monitor metrics. resp, err := http.Get("http://localhost:" + svrPort1) @@ -124,9 +117,6 @@ func testMonitorMetrics(t *testing.T) { assert.Equal(t, true, strings.Contains(bodyStr, "coordinator_rollers_disconnects_total")) // Exit. - ewCmd.WaitExit() - goCmd.WaitExit() - mrCmd.WaitExit() - rrCmd.WaitExit() - coordinatorCmd.WaitExit() + bridgeApp.WaitExit() + coordinatorApp.WaitExit() }