Skip to content

refactor: add timeout for race condition in heart test #5131

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

Merged
merged 4 commits into from
Apr 26, 2022
Merged
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 12 additions & 4 deletions test/unit/node/heart.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { logger } from "@coder/logger"
import { readFile, writeFile, stat } from "fs/promises"
import { readFile, writeFile, stat, open } from "fs/promises"
import { Heart, heartbeatTimer } from "../../../src/node/heart"
import { clean, mockLogger, tmpdir } from "../../utils/helpers"

Expand Down Expand Up @@ -33,17 +33,26 @@ describe("Heart", () => {
const pathToFile = `${testDir}/file.txt`
await writeFile(pathToFile, text)
const fileContents = await readFile(pathToFile, { encoding: "utf8" })
const fileStatusBeforeEdit = await stat(pathToFile)
// Explicitly set the modified time to 0 so that we can check
// that the file was indeed modified after calling heart.beat().
// This works around any potential race conditions.
const fileHandle = await open(pathToFile, "r+")
await fileHandle.utimes(0, 0)
Copy link
Member

@code-asher code-asher Apr 26, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Whoops, sorry I linked you to the wrong section that makes you open a file handle. I think you might have to close this as well? But it might be easier to use this one: https://nodejs.org/api/fs.html#fspromisesutimespath-atime-mtime

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, no, that's my bad. I assumed you could only access utimes after opening the file and didn't bother checking the rest of the docs. Yeah, that would leak since I don't have logic to close it (I've run into that with Deno).

Nice!!! Our codebase thanks you for your attention-to-detail 😂


expect(fileContents).toBe(text)

heart = new Heart(pathToFile, mockIsActive(true))
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
await new Promise((r) => setTimeout(r, 100))
// Check that the heart wrote to the heartbeatFilePath and overwrote our text
const fileContentsAfterBeat = await readFile(pathToFile, { encoding: "utf8" })
expect(fileContentsAfterBeat).not.toBe(text)
// Make sure the modified timestamp was updated.
const fileStatusAfterEdit = await stat(pathToFile)
expect(fileStatusAfterEdit.mtimeMs).toBeGreaterThan(fileStatusBeforeEdit.mtimeMs)
expect(fileStatusAfterEdit.mtimeMs).toBeGreaterThan(0)
})
it("should log a warning when given an invalid file path", async () => {
heart = new Heart(`fakeDir/fake.txt`, mockIsActive(false))
Expand All @@ -52,7 +61,6 @@ describe("Heart", () => {
// Therefore, we have to create an artificial wait in order to make sure
// all async code has completed before asserting
await new Promise((r) => setTimeout(r, 100))
// expect(logger.trace).toHaveBeenCalled()
expect(logger.warn).toHaveBeenCalled()
})
it("should be active after calling beat", () => {
Expand Down