-
Notifications
You must be signed in to change notification settings - Fork 6k
feat: add tests for node/heart.ts #5122
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
Changes from all commits
bd3a0cb
3934ca3
453566e
75960fa
ba70132
2e10451
d41f198
01c5691
7b11efb
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
import { logger } from "@coder/logger" | ||
import { readFile, writeFile, stat } from "fs/promises" | ||
import { Heart, heartbeatTimer } from "../../../src/node/heart" | ||
import { clean, mockLogger, tmpdir } from "../../utils/helpers" | ||
|
||
const mockIsActive = (resolveTo: boolean) => jest.fn().mockResolvedValue(resolveTo) | ||
|
||
describe("Heart", () => { | ||
const testName = "heartTests" | ||
let testDir = "" | ||
let heart: Heart | ||
|
||
beforeAll(async () => { | ||
mockLogger() | ||
await clean(testName) | ||
testDir = await tmpdir(testName) | ||
}) | ||
beforeEach(() => { | ||
heart = new Heart(`${testDir}/shutdown.txt`, mockIsActive(true)) | ||
}) | ||
afterAll(() => { | ||
jest.restoreAllMocks() | ||
}) | ||
afterEach(() => { | ||
jest.resetAllMocks() | ||
if (heart) { | ||
heart.dispose() | ||
} | ||
}) | ||
it("should write to a file when given a valid file path", async () => { | ||
// Set up heartbeat file with contents | ||
const text = "test" | ||
const pathToFile = `${testDir}/file.txt` | ||
await writeFile(pathToFile, text) | ||
const fileContents = await readFile(pathToFile, { encoding: "utf8" }) | ||
const fileStatusBeforeEdit = await stat(pathToFile) | ||
expect(fileContents).toBe(text) | ||
|
||
heart = new Heart(pathToFile, mockIsActive(true)) | ||
heart.beat() | ||
// Check that the heart wrote to the heartbeatFilePath and overwrote our text | ||
const fileContentsAfterBeat = await readFile(pathToFile, { encoding: "utf8" }) | ||
expect(fileContentsAfterBeat).not.toBe(text) | ||
jsjoeio marked this conversation as resolved.
Show resolved
Hide resolved
|
||
// Make sure the modified timestamp was updated. | ||
const fileStatusAfterEdit = await stat(pathToFile) | ||
expect(fileStatusAfterEdit.mtimeMs).toBeGreaterThan(fileStatusBeforeEdit.mtimeMs) | ||
}) | ||
it("should log a warning when given an invalid file path", async () => { | ||
heart = new Heart(`fakeDir/fake.txt`, mockIsActive(false)) | ||
heart.beat() | ||
// HACK@jsjoeio - beat has some async logic but is not an async method | ||
// Therefore, we have to create an artificial wait in order to make sure | ||
// all async code has completed before asserting | ||
Comment on lines
+51
to
+53
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This looks good to me for now. Maybe long-term we can make There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes! I briefly looked into it for this PR but since it happens in a request, I wasn't sure if changing it here to make the handler There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah yeah I think the move would be to only There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah gotcha! I did use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ahh yup we would need to make There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. But I think the current workaround is chill |
||
await new Promise((r) => setTimeout(r, 100)) | ||
// expect(logger.trace).toHaveBeenCalled() | ||
expect(logger.warn).toHaveBeenCalled() | ||
}) | ||
it("should be active after calling beat", () => { | ||
heart.beat() | ||
|
||
const isAlive = heart.alive() | ||
expect(isAlive).toBe(true) | ||
}) | ||
it("should not be active after dispose is called", () => { | ||
heart.dispose() | ||
|
||
const isAlive = heart.alive() | ||
expect(isAlive).toBe(false) | ||
}) | ||
}) | ||
|
||
describe("heartbeatTimer", () => { | ||
beforeAll(() => { | ||
mockLogger() | ||
}) | ||
afterAll(() => { | ||
jest.restoreAllMocks() | ||
}) | ||
afterEach(() => { | ||
jest.resetAllMocks() | ||
}) | ||
it("should call beat when isActive resolves to true", async () => { | ||
const isActive = true | ||
const mockIsActive = jest.fn().mockResolvedValue(isActive) | ||
const mockBeatFn = jest.fn() | ||
await heartbeatTimer(mockIsActive, mockBeatFn) | ||
expect(mockIsActive).toHaveBeenCalled() | ||
expect(mockBeatFn).toHaveBeenCalled() | ||
}) | ||
it("should log a warning when isActive rejects", async () => { | ||
const errorMsg = "oh no" | ||
const error = new Error(errorMsg) | ||
const mockIsActive = jest.fn().mockRejectedValue(error) | ||
const mockBeatFn = jest.fn() | ||
await heartbeatTimer(mockIsActive, mockBeatFn) | ||
expect(mockIsActive).toHaveBeenCalled() | ||
expect(mockBeatFn).not.toHaveBeenCalled() | ||
expect(logger.warn).toHaveBeenCalledWith(errorMsg) | ||
}) | ||
}) |
Uh oh!
There was an error while loading. Please reload this page.