Skip to content

Commit

Permalink
add integration tests
Browse files Browse the repository at this point in the history
  • Loading branch information
mehdi-aouadi committed Jul 29, 2024
1 parent 170276e commit 4b28766
Show file tree
Hide file tree
Showing 6 changed files with 274 additions and 9 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
/*
* Copyright Consensys Software Inc., 2024
*
* 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.v2.beacon;

import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
import static org.mockito.ArgumentMatchers.anyList;
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_OK;

import com.fasterxml.jackson.databind.JsonNode;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.Optional;
import okhttp3.Response;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.TestTemplate;
import tech.pegasys.teku.beaconrestapi.AbstractDataBackedRestAPIIntegrationTest;
import tech.pegasys.teku.beaconrestapi.handlers.v2.beacon.PostAttestationsV2;
import tech.pegasys.teku.infrastructure.async.SafeFuture;
import tech.pegasys.teku.infrastructure.json.JsonTestUtil;
import tech.pegasys.teku.infrastructure.json.JsonUtil;
import tech.pegasys.teku.infrastructure.json.types.SerializableTypeDefinition;
import tech.pegasys.teku.infrastructure.unsigned.UInt64;
import tech.pegasys.teku.spec.SpecMilestone;
import tech.pegasys.teku.spec.TestSpecContext;
import tech.pegasys.teku.spec.TestSpecInvocationContextProvider;
import tech.pegasys.teku.spec.datastructures.operations.Attestation;
import tech.pegasys.teku.spec.util.DataStructureUtil;
import tech.pegasys.teku.validator.api.SubmitDataError;

@TestSpecContext(milestone = {SpecMilestone.PHASE0, SpecMilestone.ELECTRA})
public class PostAttestationsV2IntegrationTest extends AbstractDataBackedRestAPIIntegrationTest {

private DataStructureUtil dataStructureUtil;
private SpecMilestone specMilestone;

@BeforeEach
void setup(final TestSpecInvocationContextProvider.SpecContext specContext) {
spec = specContext.getSpec();
specMilestone = specContext.getSpecMilestone();
startRestAPIAtGenesis(specMilestone);
dataStructureUtil = specContext.getDataStructureUtil();
}

@TestTemplate
void shouldPostAttestations_NoErrors() throws Exception {
when(validatorApiChannel.sendSignedAttestations(anyList()))
.thenReturn(SafeFuture.completedFuture(Collections.emptyList()));

final List<Attestation> attestations =
List.of(dataStructureUtil.randomAttestation(), dataStructureUtil.randomAttestation());

final Response response =
post(
PostAttestationsV2.ROUTE,
JsonUtil.serialize(
attestations,
SerializableTypeDefinition.listOf(
spec.atSlot(UInt64.ONE)
.getSchemaDefinitions()
.getAttestationSchema()
.castTypeToAttestationSchema()
.getJsonTypeDefinition())),
Collections.emptyMap(),
Optional.of(specMilestone.name().toLowerCase(Locale.ROOT)));

assertThat(response.code()).isEqualTo(SC_OK);
assertThat(response.body().string()).isEmpty();
}

@TestTemplate
void shouldPartiallyPostAttestations_ReturnsErrors() throws Exception {
final SubmitDataError firstSubmitDataError =
new SubmitDataError(UInt64.ZERO, "Bad attestation");
final SubmitDataError secondSubmitDataError =
new SubmitDataError(UInt64.ONE, "Very bad attestation");
when(validatorApiChannel.sendSignedAttestations(anyList()))
.thenReturn(
SafeFuture.completedFuture(List.of(firstSubmitDataError, secondSubmitDataError)));

final List<Attestation> attestations =
List.of(
dataStructureUtil.randomAttestation(),
dataStructureUtil.randomAttestation(),
dataStructureUtil.randomAttestation());

final Response response =
post(
PostAttestationsV2.ROUTE,
JsonUtil.serialize(
attestations,
SerializableTypeDefinition.listOf(
spec.atSlot(UInt64.ONE)
.getSchemaDefinitions()
.getAttestationSchema()
.castTypeToAttestationSchema()
.getJsonTypeDefinition())),
Collections.emptyMap(),
Optional.of(specMilestone.name().toLowerCase(Locale.ROOT)));

assertThat(response.code()).isEqualTo(SC_BAD_REQUEST);
final JsonNode resultAsJsonNode = JsonTestUtil.parseAsJsonNode(response.body().string());

assertThat(resultAsJsonNode.get("message").asText())
.isEqualTo("Some items failed to publish, refer to errors for details");
assertThat(resultAsJsonNode.get("failures").size()).isEqualTo(2);
assertThat(resultAsJsonNode.get("failures").get(0).get("index").asText())
.isEqualTo(firstSubmitDataError.getIndex().toString());
assertThat(resultAsJsonNode.get("failures").get(0).get("message").asText())
.isEqualTo(firstSubmitDataError.getMessage());
assertThat(resultAsJsonNode.get("failures").get(1).get("index").asText())
.isEqualTo(secondSubmitDataError.getIndex().toString());
assertThat(resultAsJsonNode.get("failures").get(1).get("message").asText())
.isEqualTo(secondSubmitDataError.getMessage());
}

@TestTemplate
void shouldFailWhenMissingConsensusHeader() throws Exception {
when(validatorApiChannel.sendSignedAttestations(anyList()))
.thenReturn(SafeFuture.completedFuture(Collections.emptyList()));

final List<Attestation> attestations =
List.of(dataStructureUtil.randomAttestation(), dataStructureUtil.randomAttestation());

final Response response =
post(
PostAttestationsV2.ROUTE,
JsonUtil.serialize(
attestations,
SerializableTypeDefinition.listOf(
spec.atSlot(UInt64.ONE)
.getSchemaDefinitions()
.getAttestationSchema()
.castTypeToAttestationSchema()
.getJsonTypeDefinition())));

assertThat(response.code()).isEqualTo(SC_BAD_REQUEST);

final JsonNode resultAsJsonNode = JsonTestUtil.parseAsJsonNode(response.body().string());
assertThat(resultAsJsonNode.get("message").asText())
.isEqualTo("(Eth-Consensus-Version) header value was unexpected");
}

@TestTemplate
void shouldFailWhenBadConsensusHeaderValue() throws Exception {
when(validatorApiChannel.sendSignedAttestations(anyList()))
.thenReturn(SafeFuture.completedFuture(Collections.emptyList()));

final List<Attestation> attestations =
List.of(dataStructureUtil.randomAttestation(), dataStructureUtil.randomAttestation());

final Response response =
post(
PostAttestationsV2.ROUTE,
JsonUtil.serialize(
attestations,
SerializableTypeDefinition.listOf(
spec.atSlot(UInt64.ONE)
.getSchemaDefinitions()
.getAttestationSchema()
.castTypeToAttestationSchema()
.getJsonTypeDefinition())),
Collections.emptyMap(),
Optional.of("NonExistingMileStone"));

assertThat(response.code()).isEqualTo(SC_BAD_REQUEST);

final JsonNode resultAsJsonNode = JsonTestUtil.parseAsJsonNode(response.body().string());
assertThat(resultAsJsonNode.get("message").asText())
.isEqualTo("(Eth-Consensus-Version) header value was unexpected");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@
import tech.pegasys.teku.beaconrestapi.handlers.v2.beacon.GetAttesterSlashingsV2;
import tech.pegasys.teku.beaconrestapi.handlers.v2.beacon.GetBlock;
import tech.pegasys.teku.beaconrestapi.handlers.v2.beacon.GetBlockAttestationsV2;
import tech.pegasys.teku.beaconrestapi.handlers.v2.beacon.PostAttestationV2;
import tech.pegasys.teku.beaconrestapi.handlers.v2.beacon.PostAttestationsV2;
import tech.pegasys.teku.beaconrestapi.handlers.v2.beacon.PostBlindedBlockV2;
import tech.pegasys.teku.beaconrestapi.handlers.v2.beacon.PostBlockV2;
import tech.pegasys.teku.beaconrestapi.handlers.v2.debug.GetChainHeadsV2;
Expand Down Expand Up @@ -240,7 +240,7 @@ private static RestApi create(
.endpoint(new GetAttestations(dataProvider, spec))
.endpoint(new GetAttestationsV2(dataProvider, schemaCache))
.endpoint(new PostAttestation(dataProvider, schemaCache))
.endpoint(new PostAttestationV2(dataProvider, schemaCache))
.endpoint(new PostAttestationsV2(dataProvider, schemaCache))
.endpoint(new GetAttesterSlashings(dataProvider, spec))
.endpoint(new GetAttesterSlashingsV2(dataProvider, schemaCache))
.endpoint(new PostAttesterSlashing(dataProvider, spec))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,17 +43,17 @@
import tech.pegasys.teku.spec.schemas.SchemaDefinitions;
import tech.pegasys.teku.validator.api.SubmitDataError;

public class PostAttestationV2 extends RestApiEndpoint {
public class PostAttestationsV2 extends RestApiEndpoint {

public static final String ROUTE = "/eth/v2/beacon/pool/attestations";
private final ValidatorDataProvider validatorDataProvider;

public PostAttestationV2(
public PostAttestationsV2(
final DataProvider validatorDataProvider, final SchemaDefinitionCache schemaDefinitionCache) {
this(validatorDataProvider.getValidatorDataProvider(), schemaDefinitionCache);
}

public PostAttestationV2(
public PostAttestationsV2(
final ValidatorDataProvider validatorDataProvider,
final SchemaDefinitionCache schemaDefinitionCache) {
super(createMetadata(schemaDefinitionCache));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@
import tech.pegasys.teku.validator.api.SubmitDataError;

@TestSpecContext(milestone = {PHASE0, ELECTRA})
public class PostAttestationV2Test extends AbstractMigratedBeaconHandlerTest {
public class PostAttestationsV2Test extends AbstractMigratedBeaconHandlerTest {

private SpecMilestone specMilestone;

Expand All @@ -59,7 +59,7 @@ void setUp(final TestSpecInvocationContextProvider.SpecContext specContext) {
spec = specContext.getSpec();
specMilestone = specContext.getSpecMilestone();
schemaDefinitionCache = new SchemaDefinitionCache(spec);
setHandler(new PostAttestationV2(validatorDataProvider, schemaDefinitionCache));
setHandler(new PostAttestationsV2(validatorDataProvider, schemaDefinitionCache));
}

@TestTemplate
Expand Down Expand Up @@ -117,7 +117,7 @@ void metadata_shouldHandle400() throws Exception {
final JsonNode expected =
JsonTestUtil.parseAsJsonNode(
Resources.toString(
Resources.getResource(PostAttestationV2Test.class, "errorListBadRequest.json"),
Resources.getResource(PostAttestationsV2Test.class, "errorListBadRequest.json"),
UTF_8));
AssertionsForClassTypes.assertThat(data).isEqualTo(expected);
}
Expand All @@ -135,6 +135,6 @@ void metadata_shouldHandle200() {
private String getExpectedResponseAsJson(final SpecMilestone specMilestone) throws IOException {
final String fileName =
String.format("postAttestationRequestBody%s.json", specMilestone.name());
return Resources.toString(Resources.getResource(PostAttestationV2Test.class, fileName), UTF_8);
return Resources.toString(Resources.getResource(PostAttestationsV2Test.class, fileName), UTF_8);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
{
"version": "electra",
"data": [
{
"aggregation_bits": "0x4a9278690f62e1a353f1abf2b9701e13e8cdf4d9ac6b032ba43b05b25f713540ce24f3192819e752fb091217ff34b68e934a06d316b6060696f8f24749574c4b3ac2e4ccb6914c434b09a81fff523e12acbe299fcdad715593298d72ca70e1ffc743ad7ce89587fbb4b4c57db7856b7082db70ebddcbebe264f886236df2dd51539e10d4dcd5950e6cea7c993d3e999a5589a4c71669ffb1390987e43a8c4790a70275364f96cbee34b0b5a9d1b3da4322ad12e07c81c6e6430d2528f19bb1727c3f63f414885bd97505283b0bb6773712096d5feb67c43d67f2fbf17bf796ed5080aece6b968d532d985ad2553daf31ad4022aa49d7a92ada719c9f93ab4b6f0d09f127c8d47b9ab80e95a2e72257013e933113029994778c23dfa313b689e08c58979148ac541159b8eb601eee74e985a3b5b9c2dfe0ce3145794d84647136865fabf5814e8a013e236e9b740a6c18229838f3022e1aa2afe5fe48caff6e1470e4458ebcbf152462dc300b07a3d0b102a29196b0a8d444871868408fe80e1dcecd216fe8022ea70326081e516c48bd1b8a18003322738642b189013c3ed8ad64185cf1a44cb1f6265cc40450b5caea7c29b135b5145b4f3c5f14bc76f27442d5a180909ec2e144be68711737211e8d70bda6502a88a4a6558d9c857d6028b1fdfdf2d7df9d2a415b8754d194d17b29d09444d786a0478e62141c31410eda02abcd05769473e5fa75496d49aad564d139af8efee156d8089a253f4cd49814ed34fa9346701d66738938cbc5d54ba2adeb11dbe76f828dec46b82a6ff51dcf17e49771a6d88ad61996a5552809f78746562eba9d7aa9d4525d969c662628b857133d024ead8205bd3f367f3523c6ee9ff9b1784f47de41a1c196a73b178fce869b445c9a1b872a83ba946f2ca41232cdea11c53b7652dcfe615e9b3f9f0153f706eeee404e88e8736b3712e8ab9da9c9b75e419a615c3c1d1357886f77c8eaebbf4501dc1fef854fc5cc7f2f071c0a7411eb78bc14b25307cc7e4bde334ee3df0c53d6159751e82248f280434e466712dfe33981e0171e67352cdd86838eff3acd6e05592e2d1e441ddae9450a144da5c7926ee673458a59bc98c9e4d68f8b04134cc24ffdc2034c4ac3b46d6dd98ecca28dcaa7857f0c3f73a0809ae3c5dd2205555fd7cc6444024869d4f6d7dfe043917660119433c76239b17cdc8fad6c92f3756d206d67800e4e2566a73b27bb7a51dac62bc8411cdab0c5920a821e8ae6bb7779afb69f53452ad0b33c60c41a2be2c3aa94d46e97ffb5b2ebd9adc99eab85d5a3a73d4935f7ea6867d8277040c49f3ac822a4c7c7d67aba4f45765a46fccb7f79c332ac708b58911dc000c49d54fe6137be87df7f364a94fa5642338b6eeaf4152f7410ba97b0169aad82a9c4dd2d353cc3a8f57aaa90b5335f325b3e6e01",
"data": {
"slot": "4665021361504678828",
"index": "4669978815449698508",
"beacon_block_root": "0x103ac9406cdc59b89027eb1c9e97f607dd5fdccfa8fb2da4eaeea9d25032add9",
"source": {
"epoch": "542502839",
"root": "0x8200a6402ca295554fb9562193cc71d60272d63beeaf2201fdf53e846e77f919"
},
"target": {
"epoch": "542887588",
"root": "0x5cbeb140ec0ad7cb653388caecba483cf66bd817821ed18ca1f3b7f3b9b58a04"
}
},
"signature": "0xae401f767ab1917f925fe299ad51a57d52f7cc80deb1cc20fa2b3aa983e4e4d23056d79f01f3c97e29c8905da17e70e30c2a3f6bdd83dbc4ddf530e02e8f4d7ba22260e12e5f5fe7875b48e79660615b275597e87b2d33e076664b3da1737852",
"committee_bits": "0x08"
},
{
"aggregation_bits": "0x845545fabb721755d4a172b873380c0edb449ebd072a2de3b1876da1d8982be4180ef73f8ba3ae1e5591d29e266b8c81c5dc355847a2ab7cf16ea32faa82896cf0321cbbe284bea22e0d0f1d89dc2eaf1ee3ebad1a41c1b15320f7c539213a5c3b66b6cbb895b3b64f7f5c734069f90ae04794bbb4b878eecf54206948eed9a986c2cfbc6e63f6d4579b685d3d0b676b64ddfd0823e79f1b707f2ecbfc53c9d917bc69ee349db40ce9c613b9607a638788397d29c83c607606ac5b6365d67a87594f1d21ec28f28a30add7b915540909f15d30d59bb57e9983af5140e516365a41bdb22c28e71d738d4cedebc05d4c03ee3b5b12737ce986c3e6163f7d1c66d53c5b042691f5b62c2dcb47650682746b7d69ea1c24344b23f6d64e66c493ded66be1f3ad68110c921365fde983165637ac4508cf3e0c2e9d0d3ae4d0ea19837b5f6195ff65a37e3dcbcba06ee4be125ca8ba384941e40088d56d47e9f4be8235999e152bafdc5fc1a9876e6224596f101f6afd2879ffb0f413a008143ffc8e357c370a420c2ad2941429587d57858cf5c42d42a92c6b4741e78575a8d72734141913081c7f8813ea6084af86618a4c50b0427ad32842d24332757466c89b8709fbae2cf2185cf20bcbcbfe2523965a044f351c4eddd63ca44814a5e21d1385405c5e009777a1c5edd367364ac7ccfc8c4b17e3c904063b0dbb3277c42c0b455a1e4c3755c93da5d6c0018d6ca9fea294627664b646e59a352e1401ff5cb86331e2cc8c85a1c6b5ac7e3c89d6fcf6e8a94fc252f7f4a08965791f54ee8e054f403c4d335935b0e21e08d921580cd2305343eb32a4ca75a0203401efc6812f8b34d54ac10357f88a36f054b2fe53ca54aa2e52d4451399f31a4fbdf0bf4e35ca8685bbc869fd75f24563a6b74f14ea273c44109eed479daeb97d92d4a4f853d32a222d484d3e1014caccf4a9583c54cb4884de03a579b6fcc131bd13fd0ed7647b7071a19e295c019241adf483375b32ddece6a07ef9d3451da2fbbe3959d45c0158dfeedae3bed87fd8fb15b36561017d37440a071a388c96d76991acc70cea3ad10537622e358ac8800213b687e1a3bcda4fb7365ce99e727eae54191a75021f76c9bff99509adc9af01dc98dd2ad1b6e1703026439b58a2db7ae37554cbaf21f4e6fde58e492653b7c9a87cfa4b987d00ce797077326fcf6afd4b19c985b7dce7376a3f80cf09dbfcf883979accd219e6b9c0bab705a1299bc306ea85f718082a4cc901ca763b59f38224dccd9cfaa8aa9908eec3cdb9d6e4ae7e9cb0a216225d34d205b0d343e6c1be6bf311d01aafcdfd8c61284746bf9fe83cdf4f4421b5bde4060cf81ad019f06db0ace76d59dec36b01e971601d3aaef9a25f192059fa3bd734deb9ab88df6e4f5c107a900d0449b2a05ac93b1f2c5f78e36cf0ed66e801",
"data": {
"slot": "4602226973500878187",
"index": "4593964548827522954",
"beacon_block_root": "0x7e2bbb3f2a737918a12f79e9a52da7e1fceaae0b6c0c82172425cbce8d99a0c6",
"source": {
"epoch": "535192610",
"root": "0x58e9c63feadbba8eb6a9aa92fd1b7e47efe4b0e7ff7a30a3c822443ed8d731b1"
},
"target": {
"epoch": "534038364",
"root": "0xcbafa33faaa1f62b763b1697f350f91515f7aa53462f2500db29d9eff71c7ef1"
}
},
"signature": "0x9776d892cbc6c914554d0153158c9a7c72164e9f60d3fe5816bdaf08a9bf3ca67d77a9c1d6431ba3294ec9032424322b0ab9e9a58fb0b9d8de93946ff414d2bef1f58da9f4a9b1e585c57571a6c8c8c2c0aa1c574939b7acd228d3f35d7b6e6e",
"committee_bits": "0x02"
}
]
}
Loading

0 comments on commit 4b28766

Please sign in to comment.