From 61bf2546de8ba3af9be87db65b3b27c4ded71138 Mon Sep 17 00:00:00 2001 From: Marc Font Date: Wed, 2 Oct 2024 16:20:09 +0200 Subject: [PATCH 1/3] add integration test --- .../makeAllCronPerformanceCalls.test.ts | 96 +++++++++++++++++++ 1 file changed, 96 insertions(+) create mode 100644 packages/brain/test/integration/modules/cron/trackValidatorsPerformance/makeAllCronPerformanceCalls.test.ts diff --git a/packages/brain/test/integration/modules/cron/trackValidatorsPerformance/makeAllCronPerformanceCalls.test.ts b/packages/brain/test/integration/modules/cron/trackValidatorsPerformance/makeAllCronPerformanceCalls.test.ts new file mode 100644 index 00000000..e0570979 --- /dev/null +++ b/packages/brain/test/integration/modules/cron/trackValidatorsPerformance/makeAllCronPerformanceCalls.test.ts @@ -0,0 +1,96 @@ +import { BeaconchainApi } from "../../../../../src/modules/apiClients/beaconchain/index.js"; + +import { expect } from "chai"; +import { Network } from "@stakingbrain/common"; +import { ApiParams, ValidatorStatus } from "../../../../../src/modules/apiClients/types.js"; +import { BeaconchainApiError } from "../../../../../src/modules/apiClients/beaconchain/error.js"; + +describe.skip("Beaconchain API Tests", function () { + let api: BeaconchainApi; + const validatorIndexes = ["1802459", "1802425"]; + before(async function () { + const apiParams: ApiParams = { + baseUrl: "http://beacon-chain.holesky.dncore.dappnode:3500" // replace with actual API URL + }; + + api = new BeaconchainApi(apiParams, Network.Holesky); // Network matters for number of slots in epoch + }); + + // first call done in cron, to check what epoch to process + it("should retrieve finality checkpoints for the head state", async function () { + const checkpointsResponse = await api.getStateFinalityCheckpoints({ stateId: "head" }); + console.log("Finality Checkpoints Response:", checkpointsResponse); + expect(checkpointsResponse).to.have.property("data"); + }); + + it("should retrieve ids of validators in the finalized state that are active_ongoing", async function () { + this.timeout(10000); // Set timeout to 10 seconds (10000 ms). This takes longer + const response = await api.postStateValidators({ + body: { + ids: validatorIndexes, + statuses: [ValidatorStatus.ACTIVE_ONGOING] + }, + stateId: "finalized" + }); + console.log("Validator states for finalized state: ", response); + const indexToCheck1 = "1802459"; // First index to check + const indexToCheck2 = "1802425"; // Second index to check + + // Check if the data array contains the indices you are looking for + const indicesInResponse = response.data.map((validator) => validator.index); + + expect(indicesInResponse).to.include(indexToCheck1); + expect(indicesInResponse).to.include(indexToCheck2); + }); + + it("should be able to check if node is syncing", async function () { + const { el_offline, is_syncing } = (await api.getSyncingStatus()).data; + expect(el_offline).to.exist; + expect(is_syncing).to.exist; + }); + + it("should retrieve the block header and derive epoch from slot", async function () { + const blockHeaderResponse = await api.getBlockHeader({ blockId: "head" }); + console.log("Block Header Response:", blockHeaderResponse); + expect(blockHeaderResponse).to.have.property("data"); + + const epoch = await api.getEpochHeader({ blockId: "head" }); + console.log("Derived Epoch:", epoch); + expect(epoch).to.be.a("number"); + }); + + it("should retrieve attestation rewards & block proposal duties for a specific epoch", async function () { + this.timeout(10000); // Set timeout to 10 seconds (10000 ms). This takes longer + + const epoch = await api.getStateFinalityCheckpoints({ stateId: "head" }); + const duties = await api.getProposerDuties({ epoch: epoch.data.finalized.epoch }); + + // Assume we want to check the first duty slot + const slotToCheck = duties.data[0]?.slot; + + if (slotToCheck) { + try { + // Attempt to retrieve the block header + const blockHeaderResponse = await api.getBlockHeader({ blockId: slotToCheck }); + expect(blockHeaderResponse.data.header.message.proposer_index).to.exist; // Check for proposer_index if the request is successful + } catch (error) { + // Check if the error is a BeaconchainApiError + expect(error).to.be.instanceOf(BeaconchainApiError); // Ensure it's the correct error type + + // Assert that the error message includes "404" + expect(error.message).to.include("404"); + expect(error.message).to.include("Could not find requested block"); // check for specific message contents + } + } else { + throw new Error("No slot available for duties data"); + } + + // Retrieve attestation rewards + const rewardsResponse = await api.getAttestationsRewards({ + epoch: epoch.data.finalized.epoch, + pubkeysOrIndexes: [] + }); + console.log("Attestation Rewards Response:", rewardsResponse); + expect(rewardsResponse).to.have.property("data"); + }); +}); \ No newline at end of file From b377d6f856786f8fae96775353d568c96e595415 Mon Sep 17 00:00:00 2001 From: Marc Font Date: Wed, 2 Oct 2024 16:51:11 +0200 Subject: [PATCH 2/3] add cron integration test --- packages/brain/package.json | 2 + .../makeAllCronPerformanceCalls.int.test.ts | 92 +++++++++++++++++++ 2 files changed, 94 insertions(+) create mode 100644 packages/brain/test/integration/modules/cron/trackValidatorsPerformance/makeAllCronPerformanceCalls.int.test.ts diff --git a/packages/brain/package.json b/packages/brain/package.json index 7fc4b1fa..e8d2ce16 100644 --- a/packages/brain/package.json +++ b/packages/brain/package.json @@ -8,6 +8,8 @@ "scripts": { "test": "yarn run test:unit", "test:unit": "mocha --exit --recursive 'test/**/*.unit.test.ts'", + "test:int": "mocha --exit --recursive 'test/**/*.int.test.ts'", + "test:all": "yarn run test:unit && yarn run test:int", "dev": "yarn run link:ui && tsx --watch src/index.ts", "link:ui": "ln -s ../ui/build/ ./uiBuild", "build": "yarn run clean:dist && yarn run clean:ln && tsc -p tsconfig.json", diff --git a/packages/brain/test/integration/modules/cron/trackValidatorsPerformance/makeAllCronPerformanceCalls.int.test.ts b/packages/brain/test/integration/modules/cron/trackValidatorsPerformance/makeAllCronPerformanceCalls.int.test.ts new file mode 100644 index 00000000..2f18e322 --- /dev/null +++ b/packages/brain/test/integration/modules/cron/trackValidatorsPerformance/makeAllCronPerformanceCalls.int.test.ts @@ -0,0 +1,92 @@ +import { BeaconchainApi } from "../../../../../src/modules/apiClients/beaconchain/index.js"; + +import { expect } from "chai"; +import { Network } from "@stakingbrain/common"; +import { ApiParams, ValidatorStatus } from "../../../../../src/modules/apiClients/types.js"; +import { BeaconchainApiError } from "../../../../../src/modules/apiClients/beaconchain/error.js"; + +describe.skip("Beaconchain API Tests", function () { + let api: BeaconchainApi; + const validatorIndexes = ["1802459", "1802425"]; + before(async function () { + const apiParams: ApiParams = { + baseUrl: "http://beacon-chain.holesky.dncore.dappnode:3500" // replace with actual API URL + }; + + api = new BeaconchainApi(apiParams, Network.Holesky); // Network matters for number of slots in epoch + }); + + // first call done in cron, to check what epoch to process + it("should retrieve finality checkpoints for the head state", async function () { + const checkpointsResponse = await api.getStateFinalityCheckpoints({ stateId: "head" }); + + expect(checkpointsResponse).to.have.property("data"); + expect(checkpointsResponse.data).to.have.property("finalized"); + expect(checkpointsResponse.data.finalized).to.have.property("epoch"); + + // Check that finalized.epoch exists and is a number (converted from string) + const epoch = parseInt(checkpointsResponse.data.finalized.epoch, 10); + expect(epoch).to.be.a("number"); + expect(epoch).to.not.be.NaN; // Ensure it's a valid number + }); + + it("should retrieve ids of validators in the finalized state that are active_ongoing", async function () { + this.timeout(10000); // Set timeout to 10 seconds (10000 ms). This takes longer + const response = await api.postStateValidators({ + body: { + ids: validatorIndexes, + statuses: [ValidatorStatus.ACTIVE_ONGOING] + }, + stateId: "finalized" + }); + const indexToCheck1 = "1802459"; // First index to check + const indexToCheck2 = "1802425"; // Second index to check + + // Check if the data array contains the indices you are looking for + const indicesInResponse = response.data.map((validator) => validator.index); + + expect(indicesInResponse).to.include(indexToCheck1); + expect(indicesInResponse).to.include(indexToCheck2); + }); + + it("should be able to check if node is syncing", async function () { + const { el_offline, is_syncing } = (await api.getSyncingStatus()).data; + + // Check that both el_offline and is_syncing are booleans + expect(el_offline).to.be.a("boolean"); + expect(is_syncing).to.be.a("boolean"); + }); + + it("should retrieve attestation rewards & block proposal duties for a specific epoch", async function () { + this.timeout(10000); // Set timeout to 10 seconds (10000 ms). This takes longer + + const epoch = await api.getStateFinalityCheckpoints({ stateId: "head" }); + const duties = await api.getProposerDuties({ epoch: epoch.data.finalized.epoch }); + + // Assume we want to check the first duty slot + const slotToCheck = duties.data[0]?.slot; + + if (slotToCheck) { + try { + // Attempt to retrieve the block header + const blockHeaderResponse = await api.getBlockHeader({ blockId: slotToCheck }); + expect(blockHeaderResponse.data.header.message.proposer_index).to.be.equal(duties.data[0].validator_index); + } catch (error) { + // Check if the error is a BeaconchainApiError + expect(error).to.be.instanceOf(BeaconchainApiError); // Ensure it's the correct error type + + // Assert that the error message includes "404" + expect(error.message).to.include("404"); + } + } else { + throw new Error("No slot available for duties data"); + } + + // Retrieve attestation rewards + const rewardsResponse = await api.getAttestationsRewards({ + epoch: epoch.data.finalized.epoch, + pubkeysOrIndexes: [] + }); + expect(rewardsResponse.data).to.have.property("total_rewards"); + }); +}); From 92201285cfbc6402ce03db5c6a8654e8a3c00d75 Mon Sep 17 00:00:00 2001 From: Marc Font Date: Wed, 2 Oct 2024 17:36:08 +0200 Subject: [PATCH 3/3] delete old test --- .../makeAllCronPerformanceCalls.test.ts | 96 ------------------- 1 file changed, 96 deletions(-) delete mode 100644 packages/brain/test/integration/modules/cron/trackValidatorsPerformance/makeAllCronPerformanceCalls.test.ts diff --git a/packages/brain/test/integration/modules/cron/trackValidatorsPerformance/makeAllCronPerformanceCalls.test.ts b/packages/brain/test/integration/modules/cron/trackValidatorsPerformance/makeAllCronPerformanceCalls.test.ts deleted file mode 100644 index e0570979..00000000 --- a/packages/brain/test/integration/modules/cron/trackValidatorsPerformance/makeAllCronPerformanceCalls.test.ts +++ /dev/null @@ -1,96 +0,0 @@ -import { BeaconchainApi } from "../../../../../src/modules/apiClients/beaconchain/index.js"; - -import { expect } from "chai"; -import { Network } from "@stakingbrain/common"; -import { ApiParams, ValidatorStatus } from "../../../../../src/modules/apiClients/types.js"; -import { BeaconchainApiError } from "../../../../../src/modules/apiClients/beaconchain/error.js"; - -describe.skip("Beaconchain API Tests", function () { - let api: BeaconchainApi; - const validatorIndexes = ["1802459", "1802425"]; - before(async function () { - const apiParams: ApiParams = { - baseUrl: "http://beacon-chain.holesky.dncore.dappnode:3500" // replace with actual API URL - }; - - api = new BeaconchainApi(apiParams, Network.Holesky); // Network matters for number of slots in epoch - }); - - // first call done in cron, to check what epoch to process - it("should retrieve finality checkpoints for the head state", async function () { - const checkpointsResponse = await api.getStateFinalityCheckpoints({ stateId: "head" }); - console.log("Finality Checkpoints Response:", checkpointsResponse); - expect(checkpointsResponse).to.have.property("data"); - }); - - it("should retrieve ids of validators in the finalized state that are active_ongoing", async function () { - this.timeout(10000); // Set timeout to 10 seconds (10000 ms). This takes longer - const response = await api.postStateValidators({ - body: { - ids: validatorIndexes, - statuses: [ValidatorStatus.ACTIVE_ONGOING] - }, - stateId: "finalized" - }); - console.log("Validator states for finalized state: ", response); - const indexToCheck1 = "1802459"; // First index to check - const indexToCheck2 = "1802425"; // Second index to check - - // Check if the data array contains the indices you are looking for - const indicesInResponse = response.data.map((validator) => validator.index); - - expect(indicesInResponse).to.include(indexToCheck1); - expect(indicesInResponse).to.include(indexToCheck2); - }); - - it("should be able to check if node is syncing", async function () { - const { el_offline, is_syncing } = (await api.getSyncingStatus()).data; - expect(el_offline).to.exist; - expect(is_syncing).to.exist; - }); - - it("should retrieve the block header and derive epoch from slot", async function () { - const blockHeaderResponse = await api.getBlockHeader({ blockId: "head" }); - console.log("Block Header Response:", blockHeaderResponse); - expect(blockHeaderResponse).to.have.property("data"); - - const epoch = await api.getEpochHeader({ blockId: "head" }); - console.log("Derived Epoch:", epoch); - expect(epoch).to.be.a("number"); - }); - - it("should retrieve attestation rewards & block proposal duties for a specific epoch", async function () { - this.timeout(10000); // Set timeout to 10 seconds (10000 ms). This takes longer - - const epoch = await api.getStateFinalityCheckpoints({ stateId: "head" }); - const duties = await api.getProposerDuties({ epoch: epoch.data.finalized.epoch }); - - // Assume we want to check the first duty slot - const slotToCheck = duties.data[0]?.slot; - - if (slotToCheck) { - try { - // Attempt to retrieve the block header - const blockHeaderResponse = await api.getBlockHeader({ blockId: slotToCheck }); - expect(blockHeaderResponse.data.header.message.proposer_index).to.exist; // Check for proposer_index if the request is successful - } catch (error) { - // Check if the error is a BeaconchainApiError - expect(error).to.be.instanceOf(BeaconchainApiError); // Ensure it's the correct error type - - // Assert that the error message includes "404" - expect(error.message).to.include("404"); - expect(error.message).to.include("Could not find requested block"); // check for specific message contents - } - } else { - throw new Error("No slot available for duties data"); - } - - // Retrieve attestation rewards - const rewardsResponse = await api.getAttestationsRewards({ - epoch: epoch.data.finalized.epoch, - pubkeysOrIndexes: [] - }); - console.log("Attestation Rewards Response:", rewardsResponse); - expect(rewardsResponse).to.have.property("data"); - }); -}); \ No newline at end of file