Skip to content

Commit

Permalink
test: enhance test coverage for filesystem metadata
Browse files Browse the repository at this point in the history
- Added tests for Linux device disk handling.
- Improved assertions in fs_metadata.test.ts for better accuracy and robustness.
  • Loading branch information
mceachen committed Nov 22, 2024
1 parent 82f3449 commit 8535d32
Show file tree
Hide file tree
Showing 4 changed files with 116 additions and 11 deletions.
15 changes: 8 additions & 7 deletions src/__tests__/fs_metadata.test.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,15 @@
// src/__tests__/fs_metadata.test.ts

import { jest } from "@jest/globals";
import { platform } from "node:os";
import { times } from "../array.js";
import { TimeoutError } from "../async.js";
import { getVolumeMetadata, getVolumeMountPoints } from "../index.js";
import { omit } from "../object.js";
import { isLinux, isMacOS, isWindows } from "../platform.js";
import { pickRandom, randomLetter, randomLetters, shuffle } from "../random.js";
import { sortByLocale } from "../string.js";
import { assertMetadata } from "../test-utils/assert.js";

const isWindows = platform() === "win32";
const isMacOS = platform() === "darwin";
const isLinux = platform() === "linux";
import { MiB } from "../units.js";

describe("Filesystem Metadata", () => {
jest.setTimeout(15_000);
Expand Down Expand Up @@ -142,8 +139,12 @@ describe("Filesystem Metadata", () => {
expect(omit(ea, "available", "used")).toEqual(
omit(expected, "available", "used"),
);
expect(ea.available).toBeCloseTo(expected.available, 5);
expect(ea.used).toBeCloseTo(expected.used, 5);
// REMEMBER: NEVER USE toBeCloseTo -- the api is bonkers and only applicable for fractional numbers
expect(ea.available).toBeWithin(
expected.available - MiB,
expected.available + MiB,
);
expect(ea.used).toBeWithin(expected.used - MiB, expected.used + MiB);
}
}
});
Expand Down
84 changes: 84 additions & 0 deletions src/__tests__/linux_dev_disk.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import { mkdir, mkdtemp, rm, symlink, writeFile } from "node:fs/promises";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { getBasenameLinkedTo } from "../linux/dev_disk.js";
import { describePlatform } from "../test-utils/platform.js";

/*
Rather than fooling around with mocks, we're going to create a temporary
directory structure that mimics the real /dev/disk/by-uuid and
/dev/disk/by-label directories. We'll create some device files and symlinks to
test the getBasenameLinkedTo function.
- Create base temp directory: $tmp = /tmp/test-dev-disk
- Create subdirectories: $tmp/dev/disk/by-uuid and /dev/disk/by-label
- Create some device files: $tmp/dev/sda1, /dev/sda2
- Create symlinks in by-uuid and by-label directories that match relative
paths in /dev/disk/by-*:
- by-uuid/ABC-DEF -> ../../sda2
- by-uuid/123-456 -> ../../sda1
- by-label/ROOT -> ../../sda1
- by-label/DATA -> ../../sda2
*/

describePlatform("linux")("dev_disk", () => {
let tempDir: string;
let devDir: string;
let byUuidDir: string;
let byLabelDir: string;

beforeAll(async () => {
// Create base temp directory
tempDir = await mkdtemp(join(tmpdir(), "test-dev-disk-"));

// Create directory structure
devDir = join(tempDir, "dev");
byUuidDir = join(devDir, "disk", "by-uuid");
byLabelDir = join(devDir, "disk", "by-label");

await mkdir(devDir, { recursive: true });
await mkdir(byUuidDir, { recursive: true });
await mkdir(byLabelDir, { recursive: true });

// Create some device files
for (const device of ["sda1", "sda2"]) {
const devicePath = join(devDir, device);
await writeFile(devicePath, "# " + devicePath);
}

// Create symlinks
await symlink("../../sda1", join(byUuidDir, "123-456"));
await symlink("../../sda2", join(byUuidDir, "789-ABC"));
await symlink("../../sda1", join(byLabelDir, "ROOT"));
await symlink("../../sda2", join(byLabelDir, "1tb\\x20\\x28test\\x29"));
// Create a broken symlink
await symlink("../../sdX1", join(byUuidDir, "BAD-LINK"));
});

afterAll(async () => {
await rm(tempDir, { recursive: true, force: true });
});

it("should find UUID for existing device", async () => {
const result = await getBasenameLinkedTo(byUuidDir, join(devDir, "sda1"));
expect(result).toBe("123-456");
});

it("should find label for existing device", async () => {
const result = await getBasenameLinkedTo(byLabelDir, join(devDir, "sda2"));
expect(result).toBe("1tb (test)");
});

it("should return undefined for non-existent device", async () => {
const result = await getBasenameLinkedTo(byUuidDir, join(devDir, "sdz9"));
expect(result).toBeUndefined();
});

it("should handle empty directory", async () => {
const emptyDir = join(devDir, "empty");
await mkdir(emptyDir);
const result = await getBasenameLinkedTo(emptyDir, join(devDir, "sda1"));
expect(result).toBeUndefined();
});
});
11 changes: 7 additions & 4 deletions src/linux/dev_disk.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Dirent } from "node:fs";
import { readdir, readlink } from "node:fs/promises";
import { join, resolve } from "node:path";
import { decodeEscapeSequences } from "../string.js";

/**
* Gets the UUID from symlinks for a given device path asynchronously
Expand All @@ -24,26 +25,28 @@ export function getLabelFromDevDisk(devicePath: string) {
);
}

async function getBasenameLinkedTo(
// only exposed for tests
export async function getBasenameLinkedTo(
linkDir: string,
linkPath: string,
): Promise<string | undefined> {
for await (const ea of readLinks(linkDir)) {
if (ea.linkTarget === linkPath) {
return ea.dirent.name;
// Expect the symlink to be named like '1tb\x20\x28test\x29'
return decodeEscapeSequences(ea.dirent.name);
}
}
return;
}

// only exposed for test mocking
export async function* readLinks(
async function* readLinks(
directory: string,
): AsyncGenerator<{ dirent: Dirent; linkTarget: string }, void, unknown> {
for (const dirent of await readdir(directory, { withFileTypes: true })) {
if (dirent.isSymbolicLink()) {
try {
const linkTarget = resolve(
directory,
await readlink(join(directory, dirent.name)),
);
yield { dirent, linkTarget };
Expand Down
17 changes: 17 additions & 0 deletions src/units.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/**
* KiB = 1024 bytes
* @see https://en.wikipedia.org/wiki/Kibibyte
*/
export const KiB = 1024;

/**
* MiB = 1024 KiB
* @see https://en.wikipedia.org/wiki/Mebibyte
*/
export const MiB = 1024 * KiB;

/**
* GiB = 1024 MiB
* @see https://en.wikipedia.org/wiki/Gibibyte
*/
export const GiB = 1024 * MiB;

0 comments on commit 8535d32

Please sign in to comment.