Files
factorio-clusterio/test/lib/LockFile.test.js
T
Hornwitser 5dcaca4d0b Migrate to ECMAScript Modules
Migrate the usage of CommonJS specific code and imports to ESM.  Roughly
summarised this:
- Changes all require() calls to import statement or expressions.
- Changes usage of module.exports to export statements.
- Replaces require.resolve with import.meta.resolve.
- Replaces conditional imports with conditional subpath imports.
- Replaces module === require.main with import.meta.main.
- Adds the full filename with extention to all relative imports.
- Changes all usage of __dirname and __filename to their import.meta
  equivalents.
- Sets "type": "module" in package.json files.
- Removes usage of "use strict".
- Adds .ts an an alias of .js for the webpack build.

Due to differences in how require and import resolves files the plugin
entrypoints will have to include the filename and extension after this
migration in order to work.
2026-09-11 22:43:57 +02:00

133 lines
4.0 KiB
JavaScript

/* eslint-disable node/no-sync */
import assert from "node:assert/strict";
import fs from "node:fs/promises";
import path from "node:path";
import { LockFile } from "@clusterio/lib";
const baseDir = path.join("temp", "test", "lock_file");
describe("class LockFile", function () {
/** @type {string} */
let filePath;
/** @type {LockFile} */
let lock;
before(async function () {
await fs.mkdir(baseDir, { recursive: true });
});
beforeEach(function() {
filePath = path.join(baseDir, `${Date.now()}-${Math.random()}.lock`);
lock = new LockFile(filePath);
});
afterEach(async function () {
await fs.unlink(filePath).catch(() => {});
});
describe("acquire()", function () {
it("should create the lock file when acquiring", async function () {
await lock.acquire();
await fs.access(filePath);
});
it("should throw LockFileBusyError if called when not idle", async function () {
await lock.acquire();
await assert.rejects(lock.acquire(), { name: "LockFileBusyError" });
});
it("should remove stale lock file and acquire it", async function () {
await fs.writeFile(filePath, "999999\n"); // stale lock
await lock.acquire();
await fs.access(filePath);
});
it("should throw if existing lock file is not stale", async function () {
await fs.writeFile(filePath, `${process.pid}\n`);
await assert.rejects(lock.acquire(), { name: "LockFileExistsError" });
});
});
describe("release()", function () {
it("should remove the lock file when releasing", async function () {
await lock.acquire();
await lock.release();
await assert.rejects(fs.access(filePath));
});
it("should throw LockFileBusyError if called when not acquired", async function () {
await assert.rejects(lock.release(), { name: "LockFileBusyError" });
});
});
describe("isHeld()", function () {
it("should return true only when lock file contains current PID", async function () {
await lock.acquire();
const held = await lock.isHeld();
assert.equal(held, true);
});
it("should return false when lock file does not exist", async function () {
const held = await lock.isHeld();
assert.equal(held, false);
});
it("should return false if lock file contains different PID", async function () {
await fs.writeFile(filePath, "999999\n"); // simulate another process
const held = await lock.isHeld();
assert.equal(held, false);
});
it("should return false if lock file was deleted while held", async function() {
await lock.acquire();
await fs.unlink(filePath);
const held = await lock.isHeld();
assert.equal(held, false);
});
});
describe("isStale()", function () {
it("should return true if lock file does not exist", async function () {
const stale = await lock.isStale();
assert.equal(stale, true);
});
it("should return true for invalid PID in lock file", async function () {
await fs.writeFile(filePath, "abc\n"); // non-numeric PID
const stale = await lock.isStale();
assert.equal(stale, true);
});
it("should return true for non-existent process PID", async function () {
await fs.writeFile(filePath, "999999\n"); // assume PID does not exist
const stale = await lock.isStale();
assert.equal(stale, true);
});
it("should return false for current process PID", async function () {
await fs.writeFile(filePath, `${process.pid}\n`);
const stale = await lock.isStale();
assert.equal(stale, false);
});
});
describe("attach/detach exit handlers", function () {
it("should attach exit handler on acquire and detach on release", async function () {
await lock.acquire();
const listenersBefore = process.listeners("exit").slice();
assert.ok(listenersBefore.includes(lock.handleExitSync));
await lock.release();
const listenersAfter = process.listeners("exit").slice();
assert.ok(!listenersAfter.includes(lock.handleExitSync));
});
});
describe("handleExitSync()", function () {
it("should not throw if file already removed", function () {
assert.doesNotThrow(() => lock.handleExitSync()); // simulate non-existent file
});
});
});