From 162a1a1e5386becc4cbe16d171dd2618ddf436c8 Mon Sep 17 00:00:00 2001 From: Paul Harris Date: Thu, 5 May 2022 15:39:45 +1000 Subject: [PATCH] Add tests to node endpoints. (#5434) Signed-off-by: Paul Harris --- .../migrated/paths/_eth_v1_node_syncing.json | 14 +++- .../handlers/v1/node/GetIdentity.java | 22 ++++++ .../handlers/v1/node/GetPeerCount.java | 19 +++++ .../handlers/v1/node/GetPeers.java | 18 +++++ .../handlers/v1/node/GetSyncing.java | 45 +++++++++++- .../handlers/v1/node/GetHealthTest.java | 73 ++++++++----------- .../handlers/v1/node/GetIdentityTest.java | 54 +++++++++----- .../handlers/v1/node/GetPeerByIdTest.java | 58 ++++++++------- .../handlers/v1/node/GetPeerCountTest.java | 67 +++++++++++++++++ .../handlers/v1/node/GetPeersTest.java | 56 ++++++++++---- .../handlers/v1/node/GetSyncingTest.java | 44 +++++++---- .../handlers/v1/node/GetVersionTest.java | 34 +++++++-- .../restapi/StubRestApiRequest.java | 15 ++-- 13 files changed, 385 insertions(+), 134 deletions(-) create mode 100644 data/beaconrestapi/src/test/java/tech/pegasys/teku/beaconrestapi/handlers/v1/node/GetPeerCountTest.java diff --git a/data/beaconrestapi/src/integration-test/resources/tech/pegasys/teku/beaconrestapi/beacon/migrated/paths/_eth_v1_node_syncing.json b/data/beaconrestapi/src/integration-test/resources/tech/pegasys/teku/beaconrestapi/beacon/migrated/paths/_eth_v1_node_syncing.json index 5798ba3a62a..41a8ad509bd 100644 --- a/data/beaconrestapi/src/integration-test/resources/tech/pegasys/teku/beaconrestapi/beacon/migrated/paths/_eth_v1_node_syncing.json +++ b/data/beaconrestapi/src/integration-test/resources/tech/pegasys/teku/beaconrestapi/beacon/migrated/paths/_eth_v1_node_syncing.json @@ -15,10 +15,6 @@ } } }, - "500" : { - "description" : "Server Error", - "content" : { } - }, "400" : { "description" : "The request could not be processed, check the response for more information.", "content" : { @@ -28,6 +24,16 @@ } } } + }, + "500" : { + "description" : "Internal server error", + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/HttpErrorResponse" + } + } + } } } } diff --git a/data/beaconrestapi/src/main/java/tech/pegasys/teku/beaconrestapi/handlers/v1/node/GetIdentity.java b/data/beaconrestapi/src/main/java/tech/pegasys/teku/beaconrestapi/handlers/v1/node/GetIdentity.java index bdbe932b2a0..696eba27bef 100644 --- a/data/beaconrestapi/src/main/java/tech/pegasys/teku/beaconrestapi/handlers/v1/node/GetIdentity.java +++ b/data/beaconrestapi/src/main/java/tech/pegasys/teku/beaconrestapi/handlers/v1/node/GetIdentity.java @@ -29,6 +29,7 @@ import io.javalin.plugin.openapi.annotations.OpenApiContent; import io.javalin.plugin.openapi.annotations.OpenApiResponse; import java.util.List; +import java.util.Objects; import java.util.Optional; import java.util.function.Function; import tech.pegasys.teku.api.DataProvider; @@ -199,5 +200,26 @@ public List getDiscoveryAddresses() { public MetadataMessage getMetadata() { return metadata; } + + @Override + public boolean equals(final Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + final IdentityData that = (IdentityData) o; + return Objects.equals(peerId, that.peerId) + && Objects.equals(enr, that.enr) + && Objects.equals(listeningAddresses, that.listeningAddresses) + && Objects.equals(discoveryAddresses, that.discoveryAddresses) + && Objects.equals(metadata, that.metadata); + } + + @Override + public int hashCode() { + return Objects.hash(peerId, enr, listeningAddresses, discoveryAddresses, metadata); + } } } diff --git a/data/beaconrestapi/src/main/java/tech/pegasys/teku/beaconrestapi/handlers/v1/node/GetPeerCount.java b/data/beaconrestapi/src/main/java/tech/pegasys/teku/beaconrestapi/handlers/v1/node/GetPeerCount.java index 804ca48c33e..5923bc99804 100644 --- a/data/beaconrestapi/src/main/java/tech/pegasys/teku/beaconrestapi/handlers/v1/node/GetPeerCount.java +++ b/data/beaconrestapi/src/main/java/tech/pegasys/teku/beaconrestapi/handlers/v1/node/GetPeerCount.java @@ -28,6 +28,7 @@ import io.javalin.plugin.openapi.annotations.OpenApiContent; import io.javalin.plugin.openapi.annotations.OpenApiResponse; import java.util.List; +import java.util.Objects; import java.util.function.Function; import org.jetbrains.annotations.NotNull; import tech.pegasys.teku.api.DataProvider; @@ -126,5 +127,23 @@ UInt64 getDisconnected() { UInt64 getConnected() { return connected; } + + @Override + public boolean equals(final Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + final ResponseData that = (ResponseData) o; + return Objects.equals(disconnected, that.disconnected) + && Objects.equals(connected, that.connected); + } + + @Override + public int hashCode() { + return Objects.hash(disconnected, connected); + } } } diff --git a/data/beaconrestapi/src/main/java/tech/pegasys/teku/beaconrestapi/handlers/v1/node/GetPeers.java b/data/beaconrestapi/src/main/java/tech/pegasys/teku/beaconrestapi/handlers/v1/node/GetPeers.java index a4ef0c67a3d..d41f9d42fe8 100644 --- a/data/beaconrestapi/src/main/java/tech/pegasys/teku/beaconrestapi/handlers/v1/node/GetPeers.java +++ b/data/beaconrestapi/src/main/java/tech/pegasys/teku/beaconrestapi/handlers/v1/node/GetPeers.java @@ -29,6 +29,7 @@ import io.javalin.plugin.openapi.annotations.OpenApiContent; import io.javalin.plugin.openapi.annotations.OpenApiResponse; import java.util.List; +import java.util.Objects; import java.util.Optional; import java.util.function.Function; import org.jetbrains.annotations.NotNull; @@ -160,5 +161,22 @@ public List getPeers() { public Integer getCount() { return count; } + + @Override + public boolean equals(final Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + final PeersData peersData = (PeersData) o; + return Objects.equals(peers, peersData.peers) && Objects.equals(count, peersData.count); + } + + @Override + public int hashCode() { + return Objects.hash(peers, count); + } } } diff --git a/data/beaconrestapi/src/main/java/tech/pegasys/teku/beaconrestapi/handlers/v1/node/GetSyncing.java b/data/beaconrestapi/src/main/java/tech/pegasys/teku/beaconrestapi/handlers/v1/node/GetSyncing.java index 83692ca0676..4e9995adffc 100644 --- a/data/beaconrestapi/src/main/java/tech/pegasys/teku/beaconrestapi/handlers/v1/node/GetSyncing.java +++ b/data/beaconrestapi/src/main/java/tech/pegasys/teku/beaconrestapi/handlers/v1/node/GetSyncing.java @@ -13,7 +13,6 @@ package tech.pegasys.teku.beaconrestapi.handlers.v1.node; -import static tech.pegasys.teku.infrastructure.http.HttpStatusCodes.SC_INTERNAL_SERVER_ERROR; import static tech.pegasys.teku.infrastructure.http.HttpStatusCodes.SC_OK; import static tech.pegasys.teku.infrastructure.http.RestApiConstants.CACHE_NONE; import static tech.pegasys.teku.infrastructure.http.RestApiConstants.RES_INTERNAL_ERROR; @@ -24,12 +23,14 @@ import static tech.pegasys.teku.infrastructure.json.types.CoreTypes.UINT64_TYPE; import com.fasterxml.jackson.core.JsonProcessingException; +import com.google.common.base.MoreObjects; import io.javalin.core.util.Header; import io.javalin.http.Context; import io.javalin.plugin.openapi.annotations.HttpMethod; import io.javalin.plugin.openapi.annotations.OpenApi; import io.javalin.plugin.openapi.annotations.OpenApiContent; import io.javalin.plugin.openapi.annotations.OpenApiResponse; +import java.util.Objects; import java.util.Optional; import java.util.function.Function; import org.jetbrains.annotations.NotNull; @@ -77,7 +78,6 @@ public GetSyncing(final DataProvider provider) { + "and if it is, what block it is up to.") .tags(TAG_NODE, TAG_VALIDATOR_REQUIRED) .response(SC_OK, "Request successful", SYNCING_RESPONSE_TYPE) - .response(SC_INTERNAL_SERVER_ERROR, "Server Error") .build()); this.syncProvider = syncProvider; } @@ -121,6 +121,17 @@ public SyncStatusData(final SyncDataProvider syncProvider) { this.slotsBehind = calculateSlotsBehind(status); } + SyncStatusData( + final boolean isSyncing, + final Boolean isOptimistic, + final int currentSlot, + final int slotsBehind) { + this.isSyncing = isSyncing; + this.isOptimistic = Optional.ofNullable(isOptimistic); + this.currentSlot = UInt64.valueOf(currentSlot); + this.slotsBehind = UInt64.valueOf(slotsBehind); + } + public boolean isSyncing() { return isSyncing; } @@ -144,5 +155,35 @@ private UInt64 calculateSlotsBehind(final SyncingStatus syncingStatus) { } return UInt64.ZERO; } + + @Override + public boolean equals(final Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + final SyncStatusData that = (SyncStatusData) o; + return isSyncing == that.isSyncing + && Objects.equals(isOptimistic, that.isOptimistic) + && Objects.equals(currentSlot, that.currentSlot) + && Objects.equals(slotsBehind, that.slotsBehind); + } + + @Override + public int hashCode() { + return Objects.hash(isSyncing, isOptimistic, currentSlot, slotsBehind); + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("isSyncing", isSyncing) + .add("isOptimistic", isOptimistic) + .add("currentSlot", currentSlot) + .add("slotsBehind", slotsBehind) + .toString(); + } } } diff --git a/data/beaconrestapi/src/test/java/tech/pegasys/teku/beaconrestapi/handlers/v1/node/GetHealthTest.java b/data/beaconrestapi/src/test/java/tech/pegasys/teku/beaconrestapi/handlers/v1/node/GetHealthTest.java index f8b352dfc75..57038e13f1f 100644 --- a/data/beaconrestapi/src/test/java/tech/pegasys/teku/beaconrestapi/handlers/v1/node/GetHealthTest.java +++ b/data/beaconrestapi/src/test/java/tech/pegasys/teku/beaconrestapi/handlers/v1/node/GetHealthTest.java @@ -17,33 +17,29 @@ import static javax.servlet.http.HttpServletResponse.SC_OK; import static javax.servlet.http.HttpServletResponse.SC_PARTIAL_CONTENT; import static javax.servlet.http.HttpServletResponse.SC_SERVICE_UNAVAILABLE; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; +import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.when; +import static tech.pegasys.teku.infrastructure.http.HttpStatusCodes.SC_BAD_REQUEST; +import static tech.pegasys.teku.infrastructure.http.HttpStatusCodes.SC_INTERNAL_SERVER_ERROR; import static tech.pegasys.teku.infrastructure.http.RestApiConstants.SYNCING_STATUS; -import java.util.List; -import java.util.Map; +import com.fasterxml.jackson.core.JsonProcessingException; import org.junit.jupiter.api.Test; import tech.pegasys.teku.beacon.sync.events.SyncState; import tech.pegasys.teku.beaconrestapi.AbstractMigratedBeaconHandlerTest; -import tech.pegasys.teku.infrastructure.restapi.endpoints.JavalinRestApiRequest; -import tech.pegasys.teku.infrastructure.restapi.endpoints.RestApiRequest; +import tech.pegasys.teku.infrastructure.restapi.StubRestApiRequest; public class GetHealthTest extends AbstractMigratedBeaconHandlerTest { + private final GetHealth handler = new GetHealth(syncDataProvider, chainDataProvider); + private StubRestApiRequest request = new StubRestApiRequest(); @Test public void shouldReturnSyncingStatusWhenSyncing() throws Exception { when(chainDataProvider.isStoreAvailable()).thenReturn(true); when(syncService.getCurrentSyncState()).thenReturn(SyncState.SYNCING); - final GetHealth handler = new GetHealth(syncDataProvider, chainDataProvider); - final JavalinRestApiRequest request = new JavalinRestApiRequest(context, handler.getMetadata()); - handler.handleRequest(request); - checkResponseWithoutBody(SC_PARTIAL_CONTENT); + assertThat(request.getResponseCode()).isEqualTo(SC_PARTIAL_CONTENT); } @Test @@ -51,50 +47,37 @@ public void shouldReturnSyncingStatusWhenStartingUp() throws Exception { when(chainDataProvider.isStoreAvailable()).thenReturn(true); when(syncService.getCurrentSyncState()).thenReturn(SyncState.START_UP); - final GetHealth handler = new GetHealth(syncDataProvider, chainDataProvider); - final JavalinRestApiRequest request = new JavalinRestApiRequest(context, handler.getMetadata()); - handler.handleRequest(request); - checkResponseWithoutBody(SC_PARTIAL_CONTENT); + assertThat(request.getResponseCode()).isEqualTo(SC_PARTIAL_CONTENT); } @Test public void shouldReturnCustomSyncingStatusWhenSyncing() throws Exception { - when(context.queryParamMap()).thenReturn(Map.of(SYNCING_STATUS, List.of("100"))); when(chainDataProvider.isStoreAvailable()).thenReturn(true); when(syncService.getCurrentSyncState()).thenReturn(SyncState.SYNCING); - - final GetHealth handler = new GetHealth(syncDataProvider, chainDataProvider); - final RestApiRequest request = new JavalinRestApiRequest(context, handler.getMetadata()); + request = StubRestApiRequest.builder().optionalQueryParameter(SYNCING_STATUS, "100").build(); handler.handleRequest(request); - checkResponseWithoutBody(SC_CONTINUE); + assertThat(request.getResponseCode()).isEqualTo(SC_CONTINUE); } @Test public void shouldReturnDefaultSyncingStatusWhenSyncingWrongParam() throws Exception { when(chainDataProvider.isStoreAvailable()).thenReturn(true); when(syncService.getCurrentSyncState()).thenReturn(SyncState.SYNCING); - when(context.queryParamMap()).thenReturn(Map.of(SYNCING_STATUS, List.of("a"))); - - final GetHealth handler = new GetHealth(syncDataProvider, chainDataProvider); - final RestApiRequest request = new JavalinRestApiRequest(context, handler.getMetadata()); - + request = StubRestApiRequest.builder().optionalQueryParameter(SYNCING_STATUS, "a").build(); handler.handleRequest(request); - checkResponseWithoutBody(SC_PARTIAL_CONTENT); + assertThat(request.getResponseCode()).isEqualTo(SC_PARTIAL_CONTENT); } @Test public void shouldReturnDefaultSyncingStatusWhenSyncingMultipleParams() throws Exception { when(chainDataProvider.isStoreAvailable()).thenReturn(true); when(syncService.getCurrentSyncState()).thenReturn(SyncState.SYNCING); - when(context.queryParamMap()).thenReturn(Map.of(SYNCING_STATUS, List.of("1", "2"))); - - final GetHealth handler = new GetHealth(syncDataProvider, chainDataProvider); - final RestApiRequest request = new JavalinRestApiRequest(context, handler.getMetadata()); + request = StubRestApiRequest.builder().optionalQueryParameter(SYNCING_STATUS, "1,2").build(); handler.handleRequest(request); - checkResponseWithoutBody(SC_PARTIAL_CONTENT); + assertThat(request.getResponseCode()).isEqualTo(SC_PARTIAL_CONTENT); } @Test @@ -102,26 +85,30 @@ public void shouldReturnOkWhenInSyncAndReady() throws Exception { when(chainDataProvider.isStoreAvailable()).thenReturn(true); when(syncService.getCurrentSyncState()).thenReturn(SyncState.IN_SYNC); - final GetHealth handler = new GetHealth(syncDataProvider, chainDataProvider); - final RestApiRequest request = new JavalinRestApiRequest(context, handler.getMetadata()); - handler.handleRequest(request); - checkResponseWithoutBody(SC_OK); + assertThat(request.getResponseCode()).isEqualTo(SC_OK); } @Test public void shouldReturnUnavailableWhenStoreNotAvailable() throws Exception { when(chainDataProvider.isStoreAvailable()).thenReturn(false); - final GetHealth handler = new GetHealth(syncDataProvider, chainDataProvider); - final RestApiRequest request = new JavalinRestApiRequest(context, handler.getMetadata()); - handler.handleRequest(request); - checkResponseWithoutBody(SC_SERVICE_UNAVAILABLE); + assertThat(request.getResponseCode()).isEqualTo(SC_SERVICE_UNAVAILABLE); } - private void checkResponseWithoutBody(final int statusCode) { - verify(context).status(eq(statusCode)); - verify(context, never()).result(anyString()); + @Test + void metadata_shouldHandle400() throws JsonProcessingException { + verifyMetadataErrorResponse(handler, SC_BAD_REQUEST); + } + + @Test + void metadata_shouldHandle500() throws JsonProcessingException { + verifyMetadataErrorResponse(handler, SC_INTERNAL_SERVER_ERROR); + } + + @Test + void metadata_shouldHandle200() { + verifyMetadataEmptyResponse(handler, SC_OK); } } diff --git a/data/beaconrestapi/src/test/java/tech/pegasys/teku/beaconrestapi/handlers/v1/node/GetIdentityTest.java b/data/beaconrestapi/src/test/java/tech/pegasys/teku/beaconrestapi/handlers/v1/node/GetIdentityTest.java index ef860228405..fc859ea7070 100644 --- a/data/beaconrestapi/src/test/java/tech/pegasys/teku/beaconrestapi/handlers/v1/node/GetIdentityTest.java +++ b/data/beaconrestapi/src/test/java/tech/pegasys/teku/beaconrestapi/handlers/v1/node/GetIdentityTest.java @@ -13,31 +13,36 @@ package tech.pegasys.teku.beaconrestapi.handlers.v1.node; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.ArgumentMatchers.refEq; +import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import static tech.pegasys.teku.infrastructure.http.HttpStatusCodes.SC_BAD_REQUEST; +import static tech.pegasys.teku.infrastructure.http.HttpStatusCodes.SC_INTERNAL_SERVER_ERROR; +import static tech.pegasys.teku.infrastructure.http.HttpStatusCodes.SC_OK; +import com.fasterxml.jackson.core.JsonProcessingException; import java.util.Collections; import java.util.List; import java.util.Optional; import org.junit.jupiter.api.Test; import tech.pegasys.teku.beaconrestapi.AbstractMigratedBeaconHandlerTest; import tech.pegasys.teku.beaconrestapi.handlers.v1.node.GetIdentity.IdentityData; +import tech.pegasys.teku.infrastructure.restapi.StubRestApiRequest; import tech.pegasys.teku.infrastructure.restapi.endpoints.CacheLength; -import tech.pegasys.teku.infrastructure.restapi.endpoints.RestApiRequest; import tech.pegasys.teku.networking.p2p.peer.NodeId; import tech.pegasys.teku.spec.datastructures.networking.libp2p.rpc.metadata.MetadataMessage; public class GetIdentityTest extends AbstractMigratedBeaconHandlerTest { + private final StubRestApiRequest request = new StubRestApiRequest(); + private final GetIdentity handler = new GetIdentity(network); + private final MetadataMessage defaultMetadata = + spec.getGenesisSchemaDefinitions().getMetadataMessageSchema().createDefault(); + private final IdentityData identityData = + new IdentityData( + "aeiou", Optional.empty(), List.of("address"), Collections.emptyList(), defaultMetadata); @Test public void shouldReturnExpectedObjectType() throws Exception { - final MetadataMessage defaultMetadata = - spec.getGenesisSchemaDefinitions().getMetadataMessageSchema().createDefault(); - - GetIdentity handler = new GetIdentity(network); NodeId nodeid = mock(NodeId.class); when(eth2P2PNetwork.getMetadata()).thenReturn(defaultMetadata); @@ -45,18 +50,29 @@ public void shouldReturnExpectedObjectType() throws Exception { when(nodeid.toBase58()).thenReturn("aeiou"); when(eth2P2PNetwork.getNodeAddress()).thenReturn("address"); - final RestApiRequest request = mock(RestApiRequest.class); handler.handleRequest(request); - verify(request) - .respondOk( - refEq( - new IdentityData( - "aeiou", - Optional.empty(), - List.of("address"), - Collections.emptyList(), - defaultMetadata)), - eq(CacheLength.NO_CACHE)); + assertThat(request.getResponseCode()).isEqualTo(SC_OK); + assertThat(request.getResponseBody()).isEqualTo(identityData); + assertThat(request.getCacheLength()).isEqualTo(CacheLength.NO_CACHE); + } + + @Test + void metadata_shouldHandle400() throws JsonProcessingException { + verifyMetadataErrorResponse(handler, SC_BAD_REQUEST); + } + + @Test + void metadata_shouldHandle500() throws JsonProcessingException { + verifyMetadataErrorResponse(handler, SC_INTERNAL_SERVER_ERROR); + } + + @Test + void metadata_shouldHandle200() throws JsonProcessingException { + final String data = getResponseStringFromMetadata(handler, SC_OK, identityData); + assertThat(data) + .isEqualTo( + "{\"data\":{\"peer_id\":\"aeiou\",\"p2p_addresses\":[\"address\"]," + + "\"discovery_addresses\":[],\"metadata\":{\"seq_number\":\"0\",\"attnets\":\"0x0000000000000000\"}}}"); } } diff --git a/data/beaconrestapi/src/test/java/tech/pegasys/teku/beaconrestapi/handlers/v1/node/GetPeerByIdTest.java b/data/beaconrestapi/src/test/java/tech/pegasys/teku/beaconrestapi/handlers/v1/node/GetPeerByIdTest.java index c085b2fe14a..02ec530944e 100644 --- a/data/beaconrestapi/src/test/java/tech/pegasys/teku/beaconrestapi/handlers/v1/node/GetPeerByIdTest.java +++ b/data/beaconrestapi/src/test/java/tech/pegasys/teku/beaconrestapi/handlers/v1/node/GetPeerByIdTest.java @@ -17,24 +17,28 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import static tech.pegasys.teku.infrastructure.http.HttpStatusCodes.SC_BAD_REQUEST; +import static tech.pegasys.teku.infrastructure.http.HttpStatusCodes.SC_INTERNAL_SERVER_ERROR; +import static tech.pegasys.teku.infrastructure.http.HttpStatusCodes.SC_OK; -import java.util.Map; +import com.fasterxml.jackson.core.JsonProcessingException; import java.util.Optional; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import tech.pegasys.teku.api.NetworkDataProvider; import tech.pegasys.teku.beaconrestapi.AbstractMigratedBeaconHandlerTest; -import tech.pegasys.teku.infrastructure.restapi.endpoints.JavalinRestApiRequest; -import tech.pegasys.teku.infrastructure.restapi.endpoints.RestApiRequest; +import tech.pegasys.teku.infrastructure.http.HttpErrorResponse; +import tech.pegasys.teku.infrastructure.restapi.StubRestApiRequest; import tech.pegasys.teku.networking.eth2.peers.Eth2Peer; import tech.pegasys.teku.networking.p2p.mock.MockNodeId; import tech.pegasys.teku.networking.p2p.network.PeerAddress; public class GetPeerByIdTest extends AbstractMigratedBeaconHandlerTest { - final MockNodeId peerId = new MockNodeId(123456); - final Eth2Peer peer = mock(Eth2Peer.class); + private final MockNodeId peerId = new MockNodeId(123456); + private final Eth2Peer peer = mock(Eth2Peer.class); + private final StubRestApiRequest request = + StubRestApiRequest.builder().pathParameter("peer_id", peerId.toBase58()).build(); + private final GetPeerById handler = new GetPeerById(network); @BeforeEach void setUp() { @@ -46,35 +50,39 @@ void setUp() { @Test public void shouldReturnNotFoundIfPeerNotFound() throws Exception { - final RestApiRequest request = mock(RestApiRequest.class); - final GetPeerById handler = new GetPeerById(network); when(network.getEth2PeerById(peerId.toBase58())).thenReturn(Optional.empty()); - when(context.pathParamMap()).thenReturn(Map.of("peer_id", peerId.toBase58())); handler.handleRequest(request); - verify(request).respondError(eq(SC_NOT_FOUND), eq("Peer not found")); + assertThat(request.getResponseCode()).isEqualTo(SC_NOT_FOUND); + assertThat(request.getResponseBody()) + .isEqualTo(new HttpErrorResponse(SC_NOT_FOUND, "Peer not found")); } @Test public void shouldReturnPeerIfFound() throws Exception { - final NetworkDataProvider networkDataProvider = mock(NetworkDataProvider.class); - GetPeerById handler = new GetPeerById(networkDataProvider); - when(context.pathParamMap()).thenReturn(Map.of("peer_id", peerId.toBase58())); - when(networkDataProvider.getEth2PeerById(eq(peerId.toBase58()))).thenReturn(Optional.of(peer)); - - final RestApiRequest request = new JavalinRestApiRequest(context, handler.getMetadata()); - + when(network.getEth2PeerById(eq(peerId.toBase58()))).thenReturn(Optional.of(peer)); handler.handleRequest(request); - checkResponse(peerId.toBase58(), peer.getAddress().toExternalForm(), "connected", "inbound"); + assertThat(request.getResponseCode()).isEqualTo(SC_OK); + assertThat(request.getResponseBody()).isEqualTo(peer); + } + + @Test + void metadata_shouldHandle400() throws JsonProcessingException { + verifyMetadataErrorResponse(handler, SC_BAD_REQUEST); } - private void checkResponse(String peerId, String address, String state, String direction) { - final String expectedResponse = - String.format( - "{\"data\":{\"peer_id\":\"%s\",\"last_seen_p2p_address\":\"%s\",\"state\":\"%s\",\"direction\":\"%s\"}}", - peerId, address, state, direction); + @Test + void metadata_shouldHandle500() throws JsonProcessingException { + verifyMetadataErrorResponse(handler, SC_INTERNAL_SERVER_ERROR); + } - assertThat(getResultString()).isEqualTo(expectedResponse); + @Test + void metadata_shouldHandle200() throws JsonProcessingException { + final String data = getResponseStringFromMetadata(handler, SC_OK, peer); + assertThat(data) + .isEqualTo( + "{\"data\":{\"peer_id\":\"1111111111111111111111111111177em\"," + + "\"last_seen_p2p_address\":\"1111111111111111111111111111177em\",\"state\":\"connected\",\"direction\":\"inbound\"}}"); } } diff --git a/data/beaconrestapi/src/test/java/tech/pegasys/teku/beaconrestapi/handlers/v1/node/GetPeerCountTest.java b/data/beaconrestapi/src/test/java/tech/pegasys/teku/beaconrestapi/handlers/v1/node/GetPeerCountTest.java new file mode 100644 index 00000000000..6ccaf762326 --- /dev/null +++ b/data/beaconrestapi/src/test/java/tech/pegasys/teku/beaconrestapi/handlers/v1/node/GetPeerCountTest.java @@ -0,0 +1,67 @@ +/* + * Copyright 2022 ConsenSys AG. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package tech.pegasys.teku.beaconrestapi.handlers.v1.node; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; +import static tech.pegasys.teku.infrastructure.http.HttpStatusCodes.SC_BAD_REQUEST; +import static tech.pegasys.teku.infrastructure.http.HttpStatusCodes.SC_INTERNAL_SERVER_ERROR; +import static tech.pegasys.teku.infrastructure.http.HttpStatusCodes.SC_OK; + +import com.fasterxml.jackson.core.JsonProcessingException; +import java.util.List; +import org.junit.jupiter.api.Test; +import tech.pegasys.teku.api.NetworkDataProvider; +import tech.pegasys.teku.beaconrestapi.AbstractMigratedBeaconHandlerTest; +import tech.pegasys.teku.infrastructure.restapi.StubRestApiRequest; +import tech.pegasys.teku.networking.eth2.peers.Eth2Peer; + +class GetPeerCountTest extends AbstractMigratedBeaconHandlerTest { + private final Eth2Peer peer1 = mock(Eth2Peer.class); + private final Eth2Peer peer2 = mock(Eth2Peer.class); + private final NetworkDataProvider networkDataProvider = mock(NetworkDataProvider.class); + private final GetPeerCount handler = new GetPeerCount(networkDataProvider); + private final StubRestApiRequest request = new StubRestApiRequest(); + private final List data = List.of(peer1, peer2); + private final GetPeerCount.ResponseData peerCountData = new GetPeerCount.ResponseData(data); + + @Test + public void shouldReturnListOfPeers() throws Exception { + + when(networkDataProvider.getEth2Peers()).thenReturn(data); + + handler.handleRequest(request); + assertThat(request.getResponseCode()).isEqualTo(SC_OK); + assertThat(request.getResponseBody()).isEqualTo(peerCountData); + } + + @Test + void metadata_shouldHandle400() throws JsonProcessingException { + verifyMetadataErrorResponse(handler, SC_BAD_REQUEST); + } + + @Test + void metadata_shouldHandle500() throws JsonProcessingException { + verifyMetadataErrorResponse(handler, SC_INTERNAL_SERVER_ERROR); + } + + @Test + void metadata_shouldHandle200() throws JsonProcessingException { + final String data = getResponseStringFromMetadata(handler, SC_OK, peerCountData); + assertThat(data) + .isEqualTo( + "{\"data\":{\"disconnected\":\"2\",\"connecting\":\"0\",\"connected\":\"0\",\"disconnecting\":\"0\"}}"); + } +} diff --git a/data/beaconrestapi/src/test/java/tech/pegasys/teku/beaconrestapi/handlers/v1/node/GetPeersTest.java b/data/beaconrestapi/src/test/java/tech/pegasys/teku/beaconrestapi/handlers/v1/node/GetPeersTest.java index 02793fe68a3..5031b45d51c 100644 --- a/data/beaconrestapi/src/test/java/tech/pegasys/teku/beaconrestapi/handlers/v1/node/GetPeersTest.java +++ b/data/beaconrestapi/src/test/java/tech/pegasys/teku/beaconrestapi/handlers/v1/node/GetPeersTest.java @@ -13,30 +13,38 @@ package tech.pegasys.teku.beaconrestapi.handlers.v1.node; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.ArgumentMatchers.refEq; +import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import static tech.pegasys.teku.infrastructure.http.HttpStatusCodes.SC_BAD_REQUEST; +import static tech.pegasys.teku.infrastructure.http.HttpStatusCodes.SC_INTERNAL_SERVER_ERROR; +import static tech.pegasys.teku.infrastructure.http.HttpStatusCodes.SC_OK; +import com.fasterxml.jackson.core.JsonProcessingException; import java.util.List; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import tech.pegasys.teku.api.NetworkDataProvider; import tech.pegasys.teku.beaconrestapi.AbstractMigratedBeaconHandlerTest; import tech.pegasys.teku.beaconrestapi.handlers.v1.node.GetPeers.PeersData; +import tech.pegasys.teku.infrastructure.restapi.StubRestApiRequest; import tech.pegasys.teku.infrastructure.restapi.endpoints.CacheLength; -import tech.pegasys.teku.infrastructure.restapi.endpoints.RestApiRequest; import tech.pegasys.teku.networking.eth2.peers.Eth2Peer; import tech.pegasys.teku.networking.p2p.mock.MockNodeId; import tech.pegasys.teku.networking.p2p.network.PeerAddress; public class GetPeersTest extends AbstractMigratedBeaconHandlerTest { - final MockNodeId peerId1 = new MockNodeId(123456); - final Eth2Peer peer1 = mock(Eth2Peer.class); + private final MockNodeId peerId1 = new MockNodeId(123456); + private final Eth2Peer peer1 = mock(Eth2Peer.class); - final MockNodeId peerId2 = new MockNodeId(789123); - final Eth2Peer peer2 = mock(Eth2Peer.class); + private final MockNodeId peerId2 = new MockNodeId(789123); + private final Eth2Peer peer2 = mock(Eth2Peer.class); + + private final NetworkDataProvider networkDataProvider = mock(NetworkDataProvider.class); + private final GetPeers handler = new GetPeers(networkDataProvider); + private final StubRestApiRequest request = new StubRestApiRequest(); + private final List data = List.of(peer1, peer2); + private final GetPeers.PeersData peersData = new PeersData(data); @BeforeEach void setup() { @@ -53,15 +61,35 @@ void setup() { @Test public void shouldReturnListOfPeers() throws Exception { - List data = List.of(peer1, peer2); - GetPeers.PeersData peersData = new PeersData(data); - final NetworkDataProvider networkDataProvider = mock(NetworkDataProvider.class); when(networkDataProvider.getEth2Peers()).thenReturn(data); - GetPeers handler = new GetPeers(networkDataProvider); - final RestApiRequest request = mock(RestApiRequest.class); handler.handleRequest(request); - verify(request).respondOk(refEq(peersData), eq(CacheLength.NO_CACHE)); + assertThat(request.getResponseCode()).isEqualTo(SC_OK); + assertThat(request.getCacheLength()).isEqualTo(CacheLength.NO_CACHE); + assertThat(request.getResponseBody()).isEqualTo(peersData); + } + + @Test + void metadata_shouldHandle400() throws JsonProcessingException { + verifyMetadataErrorResponse(handler, SC_BAD_REQUEST); + } + + @Test + void metadata_shouldHandle500() throws JsonProcessingException { + verifyMetadataErrorResponse(handler, SC_INTERNAL_SERVER_ERROR); + } + + @Test + void metadata_shouldHandle200() throws JsonProcessingException { + final String data = getResponseStringFromMetadata(handler, SC_OK, peersData); + assertThat(data) + .isEqualTo( + "{\"data\":[{\"peer_id\":\"1111111111111111111111111111177em\"," + + "\"last_seen_p2p_address\":\"1111111111111111111111111111177em\"," + + "\"state\":\"connected\",\"direction\":\"inbound\"}," + + "{\"peer_id\":\"11111111111111111111111111111hVqL\"," + + "\"last_seen_p2p_address\":\"11111111111111111111111111111hVqL\"," + + "\"state\":\"connected\",\"direction\":\"outbound\"}],\"meta\":{\"count\":2}}"); } } diff --git a/data/beaconrestapi/src/test/java/tech/pegasys/teku/beaconrestapi/handlers/v1/node/GetSyncingTest.java b/data/beaconrestapi/src/test/java/tech/pegasys/teku/beaconrestapi/handlers/v1/node/GetSyncingTest.java index 87ccdacc5ce..d07c8bf803f 100644 --- a/data/beaconrestapi/src/test/java/tech/pegasys/teku/beaconrestapi/handlers/v1/node/GetSyncingTest.java +++ b/data/beaconrestapi/src/test/java/tech/pegasys/teku/beaconrestapi/handlers/v1/node/GetSyncingTest.java @@ -15,43 +15,59 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.when; +import static tech.pegasys.teku.infrastructure.http.HttpStatusCodes.SC_BAD_REQUEST; +import static tech.pegasys.teku.infrastructure.http.HttpStatusCodes.SC_INTERNAL_SERVER_ERROR; +import static tech.pegasys.teku.infrastructure.http.HttpStatusCodes.SC_OK; +import com.fasterxml.jackson.core.JsonProcessingException; import org.junit.jupiter.api.Test; import tech.pegasys.teku.beacon.sync.events.SyncState; import tech.pegasys.teku.beaconrestapi.AbstractMigratedBeaconHandlerTest; -import tech.pegasys.teku.infrastructure.restapi.endpoints.JavalinRestApiRequest; -import tech.pegasys.teku.infrastructure.restapi.endpoints.RestApiRequest; +import tech.pegasys.teku.infrastructure.restapi.StubRestApiRequest; public class GetSyncingTest extends AbstractMigratedBeaconHandlerTest { + private final GetSyncing handler = new GetSyncing(syncDataProvider); + private StubRestApiRequest request = new StubRestApiRequest(); @Test public void shouldGetSyncingStatusSyncing() throws Exception { - GetSyncing handler = new GetSyncing(syncDataProvider); - final RestApiRequest request = new JavalinRestApiRequest(context, handler.getMetadata()); when(syncService.getCurrentSyncState()).thenReturn(SyncState.SYNCING); when(syncService.getSyncStatus()).thenReturn(getSyncStatus(true, 1, 7, 10)); handler.handleRequest(request); - checkResponse("7", "3", true); + assertThat(request.getResponseCode()).isEqualTo(SC_OK); + assertThat(request.getResponseBody()) + .isEqualTo(new GetSyncing.SyncStatusData(true, false, 7, 3)); } @Test public void shouldGetSyncStatusInSync() throws Exception { - GetSyncing handler = new GetSyncing(syncDataProvider); - final RestApiRequest request = new JavalinRestApiRequest(context, handler.getMetadata()); when(syncService.getSyncStatus()).thenReturn(getSyncStatus(false, 1, 10, 11)); when(syncService.getCurrentSyncState()).thenReturn(SyncState.IN_SYNC); handler.handleRequest(request); - checkResponse("10", "0", false); + assertThat(request.getResponseCode()).isEqualTo(SC_OK); + assertThat(request.getResponseBody()) + .isEqualTo(new GetSyncing.SyncStatusData(false, false, 10, 0)); } - private void checkResponse(String headSlot, String syncDistance, boolean isSyncing) { - final String expectedResponse = - String.format( - "{\"data\":{\"head_slot\":\"%s\",\"sync_distance\":\"%s\",\"is_syncing\":%s,\"is_optimistic\":false}}", - headSlot, syncDistance, isSyncing); + @Test + void metadata_shouldHandle400() throws JsonProcessingException { + verifyMetadataErrorResponse(handler, SC_BAD_REQUEST); + } + + @Test + void metadata_shouldHandle500() throws JsonProcessingException { + verifyMetadataErrorResponse(handler, SC_INTERNAL_SERVER_ERROR); + } - assertThat(getResultString()).isEqualTo(expectedResponse); + @Test + void metadata_shouldHandle200() throws JsonProcessingException { + final String data = + getResponseStringFromMetadata( + handler, SC_OK, new GetSyncing.SyncStatusData(false, false, 10, 0)); + assertThat(data) + .isEqualTo( + "{\"data\":{\"head_slot\":\"10\",\"sync_distance\":\"0\",\"is_syncing\":false,\"is_optimistic\":false}}"); } } diff --git a/data/beaconrestapi/src/test/java/tech/pegasys/teku/beaconrestapi/handlers/v1/node/GetVersionTest.java b/data/beaconrestapi/src/test/java/tech/pegasys/teku/beaconrestapi/handlers/v1/node/GetVersionTest.java index 11ff76ffa33..47ef11a1dcb 100644 --- a/data/beaconrestapi/src/test/java/tech/pegasys/teku/beaconrestapi/handlers/v1/node/GetVersionTest.java +++ b/data/beaconrestapi/src/test/java/tech/pegasys/teku/beaconrestapi/handlers/v1/node/GetVersionTest.java @@ -13,23 +13,41 @@ package tech.pegasys.teku.beaconrestapi.handlers.v1.node; -import static org.mockito.ArgumentMatchers.refEq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; +import static org.assertj.core.api.Assertions.assertThat; +import static tech.pegasys.teku.infrastructure.http.HttpStatusCodes.SC_BAD_REQUEST; +import static tech.pegasys.teku.infrastructure.http.HttpStatusCodes.SC_INTERNAL_SERVER_ERROR; +import static tech.pegasys.teku.infrastructure.http.HttpStatusCodes.SC_OK; +import com.fasterxml.jackson.core.JsonProcessingException; import org.junit.jupiter.api.Test; import tech.pegasys.teku.beaconrestapi.AbstractMigratedBeaconHandlerTest; -import tech.pegasys.teku.infrastructure.restapi.endpoints.RestApiRequest; +import tech.pegasys.teku.infrastructure.restapi.StubRestApiRequest; import tech.pegasys.teku.infrastructure.version.VersionProvider; public class GetVersionTest extends AbstractMigratedBeaconHandlerTest { + private final StubRestApiRequest request = new StubRestApiRequest(); + private final GetVersion handler = new GetVersion(); @Test public void shouldReturnVersionString() throws Exception { - final RestApiRequest request = mock(RestApiRequest.class); - final GetVersion handler = new GetVersion(); - handler.handleRequest(request); - verify(request).respondOk(refEq(VersionProvider.VERSION)); + assertThat(request.getResponseCode()).isEqualTo(SC_OK); + assertThat(request.getResponseBody()).isEqualTo(VersionProvider.VERSION); + } + + @Test + void metadata_shouldHandle400() throws JsonProcessingException { + verifyMetadataErrorResponse(handler, SC_BAD_REQUEST); + } + + @Test + void metadata_shouldHandle500() throws JsonProcessingException { + verifyMetadataErrorResponse(handler, SC_INTERNAL_SERVER_ERROR); + } + + @Test + void metadata_shouldHandle200() throws JsonProcessingException { + final String data = getResponseStringFromMetadata(handler, SC_OK, VersionProvider.VERSION); + assertThat(data).isEqualTo("{\"data\":{\"version\":\"" + VersionProvider.VERSION + "\"}}"); } } diff --git a/infrastructure/restapi/src/testFixtures/java/tech/pegasys/teku/infrastructure/restapi/StubRestApiRequest.java b/infrastructure/restapi/src/testFixtures/java/tech/pegasys/teku/infrastructure/restapi/StubRestApiRequest.java index 7695691aef9..75ad88c5f7b 100644 --- a/infrastructure/restapi/src/testFixtures/java/tech/pegasys/teku/infrastructure/restapi/StubRestApiRequest.java +++ b/infrastructure/restapi/src/testFixtures/java/tech/pegasys/teku/infrastructure/restapi/StubRestApiRequest.java @@ -38,7 +38,7 @@ public class StubRestApiRequest implements RestApiRequest { private CacheLength cacheLength = null; private final Map pathParameters = new HashMap<>(); private final Map queryParameters = new HashMap<>(); - private final Map> optionalQueryParameters = new HashMap<>(); + private final Map optionalQueryParameters = new HashMap<>(); public boolean responseCodeSet() { return responseCode != CODE_NOT_SET; @@ -48,6 +48,10 @@ public int getResponseCode() { return responseCode; } + public CacheLength getCacheLength() { + return cacheLength; + } + public void setRequestBody(T requestBody) { assertThat(this.requestBody).isNull(); this.requestBody = requestBody; @@ -110,7 +114,7 @@ public void setQueryParameter(final String parameter, final String value) { this.queryParameters.put(parameter, value); } - private void setOptionalQueryParameter(final String parameter, final Optional value) { + private void setOptionalQueryParameter(final String parameter, final String value) { assertThat(this.optionalQueryParameters.containsKey(parameter)).isFalse(); this.optionalQueryParameters.put(parameter, value); } @@ -125,7 +129,8 @@ public T getPathParameter(final ParameterMetadata parameterMetadata) { @Override public Optional getOptionalQueryParameter(final ParameterMetadata parameterMetadata) { - final Optional param = optionalQueryParameters.get(parameterMetadata.getName()); + final Optional param = + Optional.ofNullable(optionalQueryParameters.get(parameterMetadata.getName())); return param.map(p -> parameterMetadata.getType().deserializeFromString(p)); } @@ -147,7 +152,7 @@ public Object getResponseBody() { public static class Builder { private final Map pathParameters = new HashMap<>(); private final Map queryParameters = new HashMap<>(); - private final Map> optionalQueryParameters = new HashMap<>(); + private final Map optionalQueryParameters = new HashMap<>(); Builder() {} @@ -163,7 +168,7 @@ public Builder queryParameter(final String param, final String value) { return this; } - public Builder optionalQueryParameter(final String param, final Optional value) { + public Builder optionalQueryParameter(final String param, final String value) { assertThat(optionalQueryParameters.containsKey(param)).isFalse(); this.optionalQueryParameters.put(param, value); return this;