-
-
Notifications
You must be signed in to change notification settings - Fork 267
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Unit test fails at clock.test.ts
from time to time
#6734
Comments
Hi, I would like to work on this. Can i get this assigned? |
Done! Thanks for your interest! If you encounter any issue just drop a message in our discord and we can follow up from there |
Hi there, I investigated this issue and i can think of some cases where these tests could fail (This is my first issue so please forgive me if i am not following any conventions :-p ) So the failing test is this : const testConfig = {SECONDS_PER_SLOT: 12} as BeaconConfig;
const genesisTime = Math.floor(new Date("2021-01-01").getTime() / 1000);
const testCase: {name: string; delta: number}[] = [
{name: "should return next slot after 11.5s", delta: 11.5},
{name: "should return next slot after 12s", delta: 12},
{name: "should return next slot after 12.5s", delta: 12.5},
];
it.each(testCase)("$name", async function ({delta}) {
const currentSlot = getCurrentSlotAround(testConfig, genesisTime);
vi.advanceTimersByTime(delta * 1000);
expect(getCurrentSlotAround(testConfig, genesisTime)).toBe(currentSlot + 1);
}); The function 1> Delta 11.5 (Case 1):Assume You try to get the current slot on line 1 of the test case: Math.round(6 / 12) // Round(0.5) => 1 You advance the timers by 11.5 and the run the assertion: Now the current unix timestamp is : 6 + 11.5 => 17.5; Return value : 1 (Slot 1 again!) Math.round(17.5 / 12) // Round(1.458) => 1 We expected the slot to advance by 1 but it didnt! 2> Delta 12.5 (Case 3):Assume You try to get the current slot on line 1 of the test case: Math.round(17.5 / 12) // Round(1.458) => 1 You advance the timers by 12.5 and the run the assertion: Now the current unix timestamp is : 17.5 + 12.5 => 30; Return value : 3 (Slot advanced by 2!) Math.round(30 / 12) // Round(2.5) => 3 We expected the slot to advance by 1 but it advanced by 2. So the test cases will only fail in a certain 0.5 sec window if you think about it, they dont always fail but in special cases described above. (Case number 2 would never fail) The solution i can think of is to remove these two test cases here. Please let me know what you think of this and sorry for this colossal comment :-p |
Awesome explanation. Very easy to follow. Indeed it's the rounding that's causing the issue. There was a brief discussion on this issue: https://github.com/ChainSafe/lodestar/pull/6407/files#r1481758624.
The delta + advance timer approach in the current unit test does not suit the behaviour of I think it's tricky to unit test cc. @nazarhussain |
Just a note, this test is really old and never failed when we used mocha, it started to get flaky after vitest migration. |
Agreed. Dependency on |
What do you think of this approach? describe("getCurrentSlot", function () {
// eslint-disable-next-line @typescript-eslint/naming-convention
const testConfig = {SECONDS_PER_SLOT: 12} as BeaconConfig;
const genesisTime = 0;
const originalDate = global.Date.now;
beforeEach(() => {
global.Date.now = () => genesisTime;
});
afterEach(() => {
global.Date.now = originalDate;
});
const testCase: {name: string; delta: number}[] = [
{name: "should return next slot after 11.5s", delta: 11.5},
{name: "should return next slot after 12s", delta: 12},
{name: "should return next slot after 12.5s", delta: 12.5},
];
it.each(testCase)("$name", async function ({delta}) {
const currentSlot = getCurrentSlotAround(testConfig, genesisTime);
const advancement = delta * 1000;
global.Date.now = () => genesisTime + advancement;
vi.advanceTimersByTime(advancement);
expect(getCurrentSlotAround(testConfig, genesisTime)).toBe(currentSlot + 1);
});
}); Changes made here:
Changing the genesis time to special values will cause the test cases to fail, for eg 6.5 (as explained above), |
@divyesh87 Thanks for looking into this, we can achieve the same without modifying the diff --git a/packages/validator/test/unit/utils/clock.test.ts b/packages/validator/test/unit/utils/clock.test.ts
index dfa9d386e6..b5ef2ab1fa 100644
--- a/packages/validator/test/unit/utils/clock.test.ts
+++ b/packages/validator/test/unit/utils/clock.test.ts
@@ -90,6 +90,10 @@ describe("util / Clock", function () {
{name: "should return next slot after 12.5s", delta: 12.5},
];
+ beforeEach(() => {
+ vi.setSystemTime(genesisTime * 1000);
+ });
+
it.each(testCase)("$name", async function ({delta}) {
const currentSlot = getCurrentSlotAround(testConfig, genesisTime);
vi.advanceTimersByTime(delta * 1000); This seems to make the test runs deterministic, no failed tests after more than 100 runs on my machine |
Oh agreed. Thats a really neat way to do this Thanks, will create a pr soon. |
Describe the bug
Sometimes
clock.test.ts
fails. Re-running it usually makes the error go away. Same behaviour is observed when runningclock.test.ts
on my local machine.Workflows log here
Expected behavior
The test should pass every time
Steps to reproduce
Run
yarn vitest test/unit/utils/clock.test.ts
multiple timesAdditional context
No response
Operating system
Linux
Lodestar version or commit hash
v.1.18.0
The text was updated successfully, but these errors were encountered: