Skip to content

Commit

Permalink
Add custom error messages to extremely confusing assertions
Browse files Browse the repository at this point in the history
  • Loading branch information
nazarhussain committed Oct 12, 2023
1 parent 11ca6ef commit 00b495a
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 55 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -49,27 +49,27 @@ describe("beacon state api", function () {
ApiError.assert(res);
const epochCommittees = res.response.data;

expect(epochCommittees.length).toBe(committeeCount);
expect(epochCommittees).toHaveLength(committeeCount);

const slotCount: Record<string, number> = {};
const indexCount: Record<string, number> = {};

for (const committee of epochCommittees) {
expect(committee.index).toBeGreaterThanOrEqual(0);
expect(committee.index).toBeLessThanOrEqual(committeeCount - 1);
expect(committee.slot).toBeGreaterThanOrEqual(0);
expect(committee.slot).toBeLessThanOrEqual(SLOTS_PER_EPOCH - 1);
expect(committee.validators.length).toBe(validatorsPerCommittee);
expect(committee).toBeValidEpochCommittee({
committeeCount,
validatorsPerCommittee,
slotsPerEpoch: SLOTS_PER_EPOCH,
});
slotCount[committee.slot] = (slotCount[committee.slot] || 0) + 1;
indexCount[committee.index] = (indexCount[committee.index] || 0) + 1;
}

for (let i = 0; i < SLOTS_PER_EPOCH; i++) {
expect(slotCount[i]).toBe(committeesPerSlot);
expect(slotCount[i]).toBeWithMessage(committeesPerSlot, `Incorrect number of committees with slot ${i}`);
}

for (let i = 0; i < committeesPerSlot; i++) {
expect(indexCount[i]).toBe(SLOTS_PER_EPOCH);
expect(indexCount[i]).toBeWithMessage(SLOTS_PER_EPOCH, `Incorrect number of committees with index ${i}`);
}
});

Expand All @@ -78,9 +78,9 @@ describe("beacon state api", function () {
const res = await client.getEpochCommittees("head", {index});
ApiError.assert(res);
const epochCommittees = res.response.data;
expect(epochCommittees.length).toBe(SLOTS_PER_EPOCH);
expect(epochCommittees).toHaveLength(SLOTS_PER_EPOCH);
for (const committee of epochCommittees) {
expect(committee.index).toBe(index);
expect(committee.index).toBeWithMessage(index, "Committee index does not match supplied index");
}
});

Expand All @@ -89,9 +89,9 @@ describe("beacon state api", function () {
const res = await client.getEpochCommittees("head", {slot});
ApiError.assert(res);
const epochCommittees = res.response.data;
expect(epochCommittees.length).toBe(committeesPerSlot);
expect(epochCommittees).toHaveLength(committeesPerSlot);
for (const committee of epochCommittees) {
expect(committee.slot).toBe(slot);
expect(committee.slot).toBeWithMessage(slot, "Committee slot does not match supplied slot");
}
});
});
Expand Down
60 changes: 48 additions & 12 deletions packages/beacon-node/test/e2e/doppelganger/doppelganger.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,13 +124,25 @@ describe.skip("doppelganger / doppelganger test", function () {

await connect(bn2.network, bn.network);

expect(validators[0].isRunning).toBe(true);
expect(validatorsWithDoppelganger[0].isRunning).toBe(true);
expect(validators[0].isRunning).toBeWithMessage(
true,
"validator without doppelganger protection should be running"
);
expect(validatorsWithDoppelganger[0].isRunning).toBeWithMessage(
true,
"validator with doppelganger protection should be running before first epoch"
);
await waitForEvent<phase0.Checkpoint>(bn2.chain.clock, ClockEvent.epoch, timeout);
// After first epoch doppelganger protection should have stopped the validatorsWithDoppelganger
expect(validators[0].isRunning).toBe(true);
expect(validators[0].isRunning).toBeWithMessage(
true,
"validator without doppelganger protection should still be running after first epoch"
);
const pubkeyOfIndex: PubkeyHex = validatorsWithDoppelganger[0].validatorStore.getPubkeyOfIndex(0) as PubkeyHex;
expect(validatorsWithDoppelganger[0].validatorStore.isDoppelgangerSafe(pubkeyOfIndex)).toBe(false);
expect(validatorsWithDoppelganger[0].validatorStore.isDoppelgangerSafe(pubkeyOfIndex)).toBeWithMessage(
false,
"validator with doppelganger protection should be stopped after first epoch"
);
});

it("should shut down validator if same key is active with same BN and started after genesis", async function () {
Expand All @@ -156,13 +168,25 @@ describe.skip("doppelganger / doppelganger test", function () {
});
afterEachCallbacks.push(() => Promise.all(validator0WithoutDoppelganger.map((v) => v.close())));

expect(validator0WithDoppelganger[0].isRunning).toBe(true);
expect(validator0WithoutDoppelganger[0].isRunning).toBe(true);
expect(validator0WithDoppelganger[0].isRunning).toBeWithMessage(
true,
"validator with doppelganger protection should be running"
);
expect(validator0WithoutDoppelganger[0].isRunning).toBeWithMessage(
true,
"validator without doppelganger protection should be running before first epoch"
);
await waitForEvent<phase0.Checkpoint>(bn.chain.clock, ClockEvent.epoch, timeout);
//After first epoch doppelganger protection should have stopped the validator0WithDoppelganger
expect(validator0WithoutDoppelganger[0].isRunning).toBe(true);
expect(validator0WithoutDoppelganger[0].isRunning).toBeWithMessage(
true,
"validator without doppelganger protection should still be running after first epoch"
);
const pubkeyOfIndex: PubkeyHex = validator0WithDoppelganger[0].validatorStore.getPubkeyOfIndex(0) as PubkeyHex;
expect(validator0WithDoppelganger[0].validatorStore.isDoppelgangerSafe(pubkeyOfIndex)).toBe(false);
expect(validator0WithDoppelganger[0].validatorStore.isDoppelgangerSafe(pubkeyOfIndex)).toBeWithMessage(
false,
"validator with doppelganger protection should be stopped after first epoch"
);
});

it("should not shut down validator if key is different", async function () {
Expand All @@ -179,11 +203,23 @@ describe.skip("doppelganger / doppelganger test", function () {

await connect(bn2.network, bn.network);

expect(validators[0].isRunning).toBe(true);
expect(validatorsWithDoppelganger[0].isRunning).toBe(true);
expect(validators[0].isRunning).toBeWithMessage(
true,
"validator without doppelganger protection should be running"
);
expect(validatorsWithDoppelganger[0].isRunning).toBeWithMessage(
true,
"validator with doppelganger protection should be running before first epoch"
);
await waitForEvent<phase0.Checkpoint>(bn2.chain.clock, ClockEvent.epoch, timeout);
expect(validators[0].isRunning).toBe(true);
expect(validatorsWithDoppelganger[0].isRunning).toBe(true);
expect(validators[0].isRunning).toBeWithMessage(
true,
"validator without doppelganger protection should still be running after first epoch"
);
expect(validatorsWithDoppelganger[0].isRunning).toBeWithMessage(
true,
"validator with doppelganger protection should still be active after first epoch"
);
});

it("should not sign block if doppelganger period has not passed and not started at genesis", async function () {
Expand Down
12 changes: 6 additions & 6 deletions packages/beacon-node/test/e2e/eth1/jsonRpcHttpClient.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ describe("eth1 / jsonRpcHttpClient - with retries", function () {
},
})
).rejects.toThrow("getaddrinfo ENOTFOUND");
expect(retryCount).toBe(retryAttempts);
expect(retryCount).toBeWithMessage(retryAttempts, "ENOTFOUND should be retried before failing");
});

it("should retry ECONNREFUSED", async function () {
Expand All @@ -221,7 +221,7 @@ describe("eth1 / jsonRpcHttpClient - with retries", function () {
},
})
).rejects.toThrow(expect.objectContaining({code: "ECONNREFUSED"}));
expect(retryCount).toBe(retryAttempts);
expect(retryCount).toBeWithMessage(retryAttempts, "code ECONNREFUSED should be retried before failing");
});

it("should retry 404", async function () {
Expand Down Expand Up @@ -251,7 +251,7 @@ describe("eth1 / jsonRpcHttpClient - with retries", function () {
const controller = new AbortController();
const eth1JsonRpcClient = new JsonRpcHttpClient([url], {signal: controller.signal});
await expect(eth1JsonRpcClient.fetchWithRetries(payload, {retryAttempts})).rejects.toThrow("Not Found");
expect(retryCount).toBe(retryAttempts);
expect(retryCount).toBeWithMessage(retryAttempts, "404 responses should be retried before failing");
});

it("should retry timeout", async function () {
Expand Down Expand Up @@ -284,7 +284,7 @@ describe("eth1 / jsonRpcHttpClient - with retries", function () {
await expect(eth1JsonRpcClient.fetchWithRetries(payload, {retryAttempts, timeout})).rejects.toThrow(
"Timeout request"
);
expect(retryCount).toBe(retryAttempts);
expect(retryCount).toBeWithMessage(retryAttempts, "Timeout request should be retried before failing");
});

it("should retry aborted", async function () {
Expand Down Expand Up @@ -314,7 +314,7 @@ describe("eth1 / jsonRpcHttpClient - with retries", function () {
setTimeout(() => controller.abort(), 50);
const eth1JsonRpcClient = new JsonRpcHttpClient([url], {signal: controller.signal});
await expect(eth1JsonRpcClient.fetchWithRetries(payload, {retryAttempts, timeout})).rejects.toThrow("Aborted");
expect(retryCount).toBe(1);
expect(retryCount).toBeWithMessage(1, "Aborted request should be retried before failing");
});

it("should not retry payload error", async function () {
Expand Down Expand Up @@ -344,6 +344,6 @@ describe("eth1 / jsonRpcHttpClient - with retries", function () {
const controller = new AbortController();
const eth1JsonRpcClient = new JsonRpcHttpClient([url], {signal: controller.signal});
await expect(eth1JsonRpcClient.fetchWithRetries(payload, {retryAttempts})).rejects.toThrow("Method not found");
expect(retryCount).toBe(1);
expect(retryCount).toBeWithMessage(1, "Payload error (non-network error) should not be retried");
});
}, {timeout: 10_000});
34 changes: 9 additions & 25 deletions packages/beacon-node/vitest.config.ts
Original file line number Diff line number Diff line change
@@ -1,27 +1,11 @@
import {defineConfig} from "vitest/config";
import {defineConfig, mergeConfig} from "vitest/config";
import vitestConfig from "../../vitest.base.config";

export default defineConfig({
test: {
globalSetup: ["./test/globalSetup.ts"],
reporters: ["default", "hanging-process"],
coverage: {
clean: true,
all: false,
extension: [".ts"],
provider: "v8",
reporter: [["lcovonly", {file: "lcov.info"}], ["text"]],
reportsDirectory: "./coverage",
exclude: [
"**/*.d.ts",
"**/*.js",
"**/lib/**",
"**/coverage/**",
"**/scripts/**",
"**/test/**",
"**/types/**",
"**/bin/**",
"**/node_modules/**",
],
export default mergeConfig(
vitestConfig,
defineConfig({
test: {
globalSetup: ["./test/globalSetup.ts"],
},
},
});
})
);

0 comments on commit 00b495a

Please sign in to comment.