Files
iptvnator/apps/electron-backend-e2e/src/performance/performance-artifact-preflight.ts
T

77 lines
2.4 KiB
TypeScript

import { statfs } from 'node:fs/promises';
import { dirname, resolve } from 'node:path';
export const MIN_PERFORMANCE_ARTIFACT_FREE_BYTES =
2n * 1_024n * 1_024n * 1_024n;
interface FileSystemCapacity {
readonly bavail: bigint;
readonly bsize: bigint;
}
interface PerformanceArtifactPreflightDependencies {
readonly statfs?: (path: string) => Promise<FileSystemCapacity>;
}
export interface PerformanceArtifactCapacity {
readonly availableBytes: bigint;
readonly checkedPath: string;
readonly minimumBytes: bigint;
}
async function readFileSystemCapacity(
path: string
): Promise<FileSystemCapacity> {
const capacity = await statfs(path, { bigint: true });
return {
bavail: capacity.bavail,
bsize: capacity.bsize,
};
}
function isMissingPath(error: unknown): boolean {
return (
typeof error === 'object' &&
error !== null &&
'code' in error &&
error.code === 'ENOENT'
);
}
export async function assertPerformanceArtifactCapacity(
targetPath: string,
dependencies: PerformanceArtifactPreflightDependencies = {}
): Promise<PerformanceArtifactCapacity> {
const readCapacity = dependencies.statfs ?? readFileSystemCapacity;
let checkedPath = resolve(targetPath);
while (true) {
try {
const capacity = await readCapacity(checkedPath);
const availableBytes = capacity.bavail * capacity.bsize;
if (availableBytes < MIN_PERFORMANCE_ARTIFACT_FREE_BYTES) {
throw new Error(
`performance-artifact-space-insufficient: benchmark requires at least ${MIN_PERFORMANCE_ARTIFACT_FREE_BYTES} available bytes; ${availableBytes} available at ${checkedPath}`
);
}
return Object.freeze({
availableBytes,
checkedPath,
minimumBytes: MIN_PERFORMANCE_ARTIFACT_FREE_BYTES,
});
} catch (error) {
if (!isMissingPath(error)) {
throw error;
}
const parent = dirname(checkedPath);
if (parent === checkedPath) {
throw new Error(
`performance-artifact-space-unavailable: no existing ancestor for ${targetPath}`,
{ cause: error }
);
}
checkedPath = parent;
}
}
}