diff --git a/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/testutils.go b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/testutils.go new file mode 100644 index 00000000000..df64cf3bcee --- /dev/null +++ b/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/testutils.go @@ -0,0 +1,72 @@ +package mercury + +import ( + "net/http" + "net/http/httptest" + "sync/atomic" +) + +type MercuryEndpointMock interface { + URL() string + Username() string + Password() string + CallCount() int + RegisterHandler(http.HandlerFunc) +} + +var _ MercuryEndpointMock = &SimulatedMercuryServer{} + +var notFoundHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusNotFound) +}) + +type SimulatedMercuryServer struct { + server *httptest.Server + handler http.HandlerFunc + + callCounter atomic.Int32 +} + +func NewSimulatedMercuryServer() *SimulatedMercuryServer { + srv := &SimulatedMercuryServer{ + handler: notFoundHandler, + callCounter: atomic.Int32{}, + } + + srv.server = httptest.NewUnstartedServer(srv) + + return srv +} + +func (ms *SimulatedMercuryServer) URL() string { + return ms.server.URL +} + +func (ms *SimulatedMercuryServer) Username() string { + return "username1" +} + +func (ms *SimulatedMercuryServer) Password() string { + return "password1" +} + +func (ms *SimulatedMercuryServer) CallCount() int { + return int(ms.callCounter.Load()) +} + +func (ms *SimulatedMercuryServer) RegisterHandler(h http.HandlerFunc) { + ms.handler = h +} + +func (ms *SimulatedMercuryServer) Start() { + ms.server.Start() +} + +func (ms *SimulatedMercuryServer) Stop() { + ms.server.Close() +} + +func (ms *SimulatedMercuryServer) ServeHTTP(w http.ResponseWriter, r *http.Request) { + ms.callCounter.Add(1) + ms.handler.ServeHTTP(w, r) +} diff --git a/core/services/ocr2/plugins/ocr2keeper/integration_21_test.go b/core/services/ocr2/plugins/ocr2keeper/integration_21_test.go index b2a1a8df00c..4aa9b0cb7dc 100644 --- a/core/services/ocr2/plugins/ocr2keeper/integration_21_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/integration_21_test.go @@ -54,6 +54,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury/streams" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm" ) @@ -417,9 +418,7 @@ func TestIntegration_KeeperPluginLogUpkeep_ErrHandler(t *testing.T) { upkeepCount := 10 - respTimeout := -1 errResponses := []int{ - // respTimeout, // TODO: uncomment once mercuryServer is fixed http.StatusUnauthorized, http.StatusBadRequest, http.StatusInternalServerError, @@ -429,15 +428,7 @@ func TestIntegration_KeeperPluginLogUpkeep_ErrHandler(t *testing.T) { if i < len(errResponses) { resp = errResponses[i] } - switch resp { - case http.StatusNotFound, http.StatusInternalServerError: - // TODO: uncomment once mercuryServer is fixed - // in case we got a 404 or 500, wait a bit to simulate real world - // time.Sleep(time.Duration(rand.Intn(2500)) * time.Millisecond) - case respTimeout: // mercury server timeout - time.Sleep(30 * time.Second) - resp = http.StatusNotFound - default: + if resp == 0 { resp = http.StatusNotFound } return resp, nil @@ -488,7 +479,7 @@ func TestIntegration_KeeperPluginLogUpkeep_ErrHandler(t *testing.T) { done() } -func startMercuryServer(t *testing.T, mercuryServer *SimulatedMercuryServer, responder func(i int) (int, []byte)) { +func startMercuryServer(t *testing.T, mercuryServer *mercury.SimulatedMercuryServer, responder func(i int) (int, []byte)) { i := atomic.Int32{} mercuryServer.RegisterHandler(func(w http.ResponseWriter, r *http.Request) { _ = r.ParseForm() @@ -595,9 +586,9 @@ func listenPerformed(t *testing.T, backend *backends.SimulatedBackend, registry return listenPerformedN(t, backend, registry, ids, startBlock, 0) } -func setupNodes(t *testing.T, nodeKeys [5]ethkey.KeyV2, registry *iregistry21.IKeeperRegistryMaster, backend *backends.SimulatedBackend, usr *bind.TransactOpts) ([]Node, *SimulatedMercuryServer) { +func setupNodes(t *testing.T, nodeKeys [5]ethkey.KeyV2, registry *iregistry21.IKeeperRegistryMaster, backend *backends.SimulatedBackend, usr *bind.TransactOpts) ([]Node, *mercury.SimulatedMercuryServer) { lggr := logger.TestLogger(t) - mServer := NewSimulatedMercuryServer() + mServer := mercury.NewSimulatedMercuryServer() mServer.Start() // Setup bootstrap + oracle nodes diff --git a/core/services/ocr2/plugins/ocr2keeper/integration_test.go b/core/services/ocr2/plugins/ocr2keeper/integration_test.go index 56467c60abb..937c3df0c36 100644 --- a/core/services/ocr2/plugins/ocr2keeper/integration_test.go +++ b/core/services/ocr2/plugins/ocr2keeper/integration_test.go @@ -6,10 +6,7 @@ import ( "encoding/json" "fmt" "math/big" - "net/http" - "net/http/httptest" "strings" - "sync" "testing" "time" @@ -57,6 +54,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/keystest" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ocr2key" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/mercury" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/validate" "github.com/smartcontractkit/chainlink/v2/core/services/ocrbootstrap" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm" @@ -112,7 +110,7 @@ func setupNode( nodeKey ethkey.KeyV2, backend *backends.SimulatedBackend, p2pV2Bootstrappers []commontypes.BootstrapperLocator, - mercury MercuryEndpoint, + mercury mercury.MercuryEndpointMock, ) (chainlink.Application, string, common.Address, ocr2key.KeyBundle) { p2pKey := keystest.NewP2PKeyV2(t) p2paddresses := []string{fmt.Sprintf("127.0.0.1:%d", port)} @@ -236,7 +234,7 @@ func TestIntegration_KeeperPluginBasic(t *testing.T) { // Setup bootstrap + oracle nodes bootstrapNodePort := freeport.GetOne(t) - appBootstrap, bootstrapPeerID, bootstrapTransmitter, bootstrapKb := setupNode(t, bootstrapNodePort, nodeKeys[0], backend, nil, NewSimulatedMercuryServer()) + appBootstrap, bootstrapPeerID, bootstrapTransmitter, bootstrapKb := setupNode(t, bootstrapNodePort, nodeKeys[0], backend, nil, mercury.NewSimulatedMercuryServer()) bootstrapNode := Node{ appBootstrap, bootstrapTransmitter, bootstrapKb, } @@ -250,7 +248,7 @@ func TestIntegration_KeeperPluginBasic(t *testing.T) { app, peerID, transmitter, kb := setupNode(t, ports[i], nodeKeys[i+1], backend, []commontypes.BootstrapperLocator{ // Supply the bootstrap IP and port as a V2 peer address {PeerID: bootstrapPeerID, Addrs: []string{fmt.Sprintf("127.0.0.1:%d", bootstrapNodePort)}}, - }, NewSimulatedMercuryServer()) + }, mercury.NewSimulatedMercuryServer()) nodes = append(nodes, Node{ app, transmitter, kb, @@ -488,7 +486,7 @@ func TestIntegration_KeeperPluginForwarderEnabled(t *testing.T) { effectiveTransmitters := make([]common.Address, 0) // Setup bootstrap + oracle nodes bootstrapNodePort := freeport.GetOne(t) - appBootstrap, bootstrapPeerID, bootstrapTransmitter, bootstrapKb := setupNode(t, bootstrapNodePort, nodeKeys[0], backend, nil, NewSimulatedMercuryServer()) + appBootstrap, bootstrapPeerID, bootstrapTransmitter, bootstrapKb := setupNode(t, bootstrapNodePort, nodeKeys[0], backend, nil, mercury.NewSimulatedMercuryServer()) bootstrapNode := Node{ appBootstrap, bootstrapTransmitter, bootstrapKb, @@ -503,7 +501,7 @@ func TestIntegration_KeeperPluginForwarderEnabled(t *testing.T) { app, peerID, transmitter, kb := setupNode(t, ports[i], nodeKeys[i+1], backend, []commontypes.BootstrapperLocator{ // Supply the bootstrap IP and port as a V2 peer address {PeerID: bootstrapPeerID, Addrs: []string{fmt.Sprintf("127.0.0.1:%d", bootstrapNodePort)}}, - }, NewSimulatedMercuryServer()) + }, mercury.NewSimulatedMercuryServer()) nodeForwarder := setupForwarderForNode(t, app, sergey, backend, transmitter, linkAddr) effectiveTransmitters = append(effectiveTransmitters, nodeForwarder) @@ -711,72 +709,3 @@ func TestFilterNamesFromSpec20(t *testing.T) { _, err = ocr2keeper.FilterNamesFromSpec20(spec) require.ErrorContains(t, err, "not a valid EIP55 formatted address") } - -// ------- below this line could be added to a test helpers package -type MercuryEndpoint interface { - URL() string - Username() string - Password() string - CallCount() int - RegisterHandler(http.HandlerFunc) -} - -type SimulatedMercuryServer struct { - server *httptest.Server - handler http.HandlerFunc - - mu sync.RWMutex - callCount int -} - -func NewSimulatedMercuryServer() *SimulatedMercuryServer { - srv := &SimulatedMercuryServer{ - handler: func(w http.ResponseWriter, r *http.Request) { - w.WriteHeader(http.StatusNotFound) - }, - } - - srv.server = httptest.NewUnstartedServer(srv) - - return srv -} - -func (ms *SimulatedMercuryServer) URL() string { - return ms.server.URL -} - -func (ms *SimulatedMercuryServer) Username() string { - return "username1" -} - -func (ms *SimulatedMercuryServer) Password() string { - return "password1" -} - -func (ms *SimulatedMercuryServer) CallCount() int { - ms.mu.RLock() - defer ms.mu.RUnlock() - - return ms.callCount -} - -func (ms *SimulatedMercuryServer) RegisterHandler(h http.HandlerFunc) { - ms.handler = h -} - -func (ms *SimulatedMercuryServer) Start() { - ms.server.Start() -} - -func (ms *SimulatedMercuryServer) Stop() { - ms.server.Close() -} - -func (ms *SimulatedMercuryServer) ServeHTTP(w http.ResponseWriter, r *http.Request) { - ms.mu.Lock() - defer ms.mu.Unlock() - - ms.callCount++ - - ms.handler.ServeHTTP(w, r) -}