synapsecns/sanguine

View on GitHub
services/rfq/api/client/suite_test.go

Summary

Maintainability
A
0 mins
Test Coverage
package client_test

import (
    "fmt"
    "math/big"
    "sync"
    "testing"
    "time"

    "github.com/Flaque/filet"
    "github.com/ethereum/go-ethereum/accounts/abi/bind"
    "github.com/ethereum/go-ethereum/common"
    "github.com/ethereum/go-ethereum/params"
    "github.com/phayes/freeport"
    "github.com/puzpuzpuz/xsync/v2"
    "github.com/stretchr/testify/suite"
    "github.com/synapsecns/sanguine/core/dbcommon"
    "github.com/synapsecns/sanguine/core/metrics"
    "github.com/synapsecns/sanguine/core/testsuite"
    "github.com/synapsecns/sanguine/ethergo/backends"
    "github.com/synapsecns/sanguine/ethergo/backends/geth"
    "github.com/synapsecns/sanguine/ethergo/signer/signer/localsigner"
    "github.com/synapsecns/sanguine/ethergo/signer/wallet"
    omniClient "github.com/synapsecns/sanguine/services/omnirpc/client"
    omnirpcHelper "github.com/synapsecns/sanguine/services/omnirpc/testhelper"
    "github.com/synapsecns/sanguine/services/rfq/api/client"
    "github.com/synapsecns/sanguine/services/rfq/api/config"
    "github.com/synapsecns/sanguine/services/rfq/api/db"
    "github.com/synapsecns/sanguine/services/rfq/api/db/sql"
    "github.com/synapsecns/sanguine/services/rfq/api/rest"
    "github.com/synapsecns/sanguine/services/rfq/contracts/fastbridge"
    "golang.org/x/sync/errgroup"
)

type ClientSuite struct {
    *testsuite.TestSuite
    omniRPCClient        omniClient.RPCClient
    omniRPCTestBackends  []backends.SimulatedTestBackend
    testBackends         map[uint64]backends.SimulatedTestBackend
    fastBridgeAddressMap *xsync.MapOf[uint64, common.Address]
    database             db.APIDB
    cfg                  config.Config
    testWallet           wallet.Wallet
    handler              metrics.Handler
    QuoterAPIServer      *rest.QuoterAPIServer
    port                 uint16
    client               client.AuthenticatedClient
}

func NewTestClientSuite(tb testing.TB) *ClientSuite {
    tb.Helper()

    return &ClientSuite{
        TestSuite: testsuite.NewTestSuite(tb),
    }
}

func (c *ClientSuite) SetupTest() {
    c.TestSuite.SetupTest()

    metricsHandler := metrics.NewNullHandler()
    c.handler = metricsHandler
    dbType, err := dbcommon.DBTypeFromString("sqlite")
    c.Require().NoError(err)
    // TODO use temp file / in memory sqlite3 to not create in directory files
    testDB, err := sql.Connect(c.GetSuiteContext(), dbType, filet.TmpDir(c.T(), ""), metricsHandler)
    c.Require().NoError(err)
    c.database = testDB

    testOmnirpc := omnirpcHelper.NewOmnirpcServer(c.GetTestContext(), c.T(), c.omniRPCTestBackends...)
    omniRPCClient := omniClient.NewOmnirpcClient(testOmnirpc, c.handler, omniClient.WithCaptureReqRes())
    c.omniRPCClient = omniRPCClient

    arbFastBridgeAddress, ok := c.fastBridgeAddressMap.Load(42161)
    c.True(ok)
    ethFastBridgeAddress, ok := c.fastBridgeAddressMap.Load(1)
    c.True(ok)
    port, err := freeport.GetFreePort()
    c.port = uint16(port)
    c.Require().NoError(err)

    testConfig := config.Config{
        Database: config.DatabaseConfig{
            Type: "sqlite",
            DSN:  filet.TmpFile(c.T(), "", "").Name(),
        },
        OmniRPCURL: testOmnirpc,
        Bridges: map[uint32]string{
            1:     ethFastBridgeAddress.Hex(),
            42161: arbFastBridgeAddress.Hex(),
        },
        Port: fmt.Sprintf("%d", port),
    }
    c.cfg = testConfig

    QuoterAPIServer, err := rest.NewAPI(c.GetTestContext(), c.cfg, c.handler, c.omniRPCClient, c.database)
    c.Require().NoError(err)
    c.QuoterAPIServer = QuoterAPIServer

    go func() {
        err := c.QuoterAPIServer.Run(c.GetTestContext())
        c.Require().NoError(err)
    }()
    time.Sleep(2 * time.Second) // Wait for the server to start.

    c.client, err = client.NewAuthenticatedClient(metrics.Get(), fmt.Sprintf("http://127.0.0.1:%d", port), localsigner.NewSigner(c.testWallet.PrivateKey()))
    c.Require().NoError(err)
}

func (c *ClientSuite) SetupSuite() {
    c.TestSuite.SetupSuite()

    // let's create 2 mock chains
    chainIDs := []uint64{1, 42161}

    c.testBackends = make(map[uint64]backends.SimulatedTestBackend)
    var mux sync.Mutex

    g, _ := errgroup.WithContext(c.GetSuiteContext())
    for _, chainID := range chainIDs {
        chainID := chainID // capture func literal
        g.Go(func() error {
            // Setup backend for the suite to have RPC support
            backend := geth.NewEmbeddedBackendForChainID(c.GetSuiteContext(), c.T(), new(big.Int).SetUint64(chainID))

            // add the backend to the list of backends
            mux.Lock()
            defer mux.Unlock()
            c.testBackends[chainID] = backend
            c.omniRPCTestBackends = append(c.omniRPCTestBackends, backend)
            return nil
        })
    }

    // wait for all backends to be ready
    if err := g.Wait(); err != nil {
        c.T().Fatal(err)
    }

    testWallet, err := wallet.FromRandom()
    c.Require().NoError(err)
    c.testWallet = testWallet
    for _, backend := range c.testBackends {
        backend.FundAccount(c.GetSuiteContext(), c.testWallet.Address(), *big.NewInt(params.Ether))
    }

    c.fastBridgeAddressMap = xsync.NewIntegerMapOf[uint64, common.Address]()

    g, _ = errgroup.WithContext(c.GetSuiteContext())
    for _, backend := range c.testBackends {
        backend := backend
        g.Go(func() error {
            chainID, err := backend.ChainID(c.GetSuiteContext())
            if err != nil {
                return fmt.Errorf("could not get chainID: %w", err)
            }
            // Create an auth to interact with the blockchain
            auth, err := bind.NewKeyedTransactorWithChainID(c.testWallet.PrivateKey(), chainID)
            c.Require().NoError(err)

            // Deploy the FastBridge contract
            fastBridgeAddress, tx, _, err := fastbridge.DeployFastBridge(auth, backend, c.testWallet.Address())
            c.Require().NoError(err)
            backend.WaitForConfirmation(c.GetSuiteContext(), tx)

            // Save the contracts to the map
            c.fastBridgeAddressMap.Store(chainID.Uint64(), fastBridgeAddress)

            fastBridgeInstance, err := fastbridge.NewFastBridge(fastBridgeAddress, backend)
            c.Require().NoError(err)
            relayerRole, err := fastBridgeInstance.RELAYERROLE(&bind.CallOpts{Context: c.GetTestContext()})
            c.NoError(err)

            tx, err = fastBridgeInstance.GrantRole(auth, relayerRole, c.testWallet.Address())
            c.Require().NoError(err)
            backend.WaitForConfirmation(c.GetSuiteContext(), tx)

            return nil
        })
    }

    // wait for all backends to be ready
    if err := g.Wait(); err != nil {
        c.T().Fatal(err)
    }

    // setup config
}

// TestConfigSuite runs the integration test suite.
func TestClientSuite(t *testing.T) {
    suite.Run(t, NewTestClientSuite(t))
}