Skip to content

Commit

Permalink
test: add tests for multithread cloning
Browse files Browse the repository at this point in the history
  • Loading branch information
nachoaldamav committed Oct 18, 2023
1 parent b087a9d commit de30c93
Show file tree
Hide file tree
Showing 4 changed files with 637 additions and 3 deletions.
42 changes: 39 additions & 3 deletions __test__/main.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -255,16 +255,23 @@ describe('reflink', () => {

const clonedFiles = await Promise.all(
destFiles.map(async (file) => {
await reflinkFile(srcFile.path, file.path);
reflinkFileSync(srcFile.path, file.path);
return file;
})
);

clonedFiles.forEach((file) => {
const sourceContent = readFileSync(srcFile.path, 'utf-8');
const sourceHash = createHash('sha256')
.update(sourceContent)
.digest('hex');

expect(file.hash).toBe(sourceHash);

const destContent = readFileSync(file.path, 'utf-8');
const destHash = createHash('sha256').update(destContent).digest('hex');
expect(destContent).toBe(srcFile.content);
expect(destHash).toBe(file.hash);
expect(destContent).toBe(sourceContent);
expect(destHash).toBe(sourceHash);
});
});

Expand All @@ -288,6 +295,35 @@ describe('reflink', () => {
expect(destHash).toStrictEqual(destFile.hash);
});

/**
* The issue with empty cloned files doesnt seem related to ASCII characters
*/
it.skip('should clone "ascii-file.js" file correctly (sync)', async () => {
const srcFile = {
path: resolve(join('fixtures', 'ascii-file.js')),
content: readFileSync(join('fixtures', 'ascii-file.js')),
};

const destFile = {
path: join(sandboxDir, 'ascii-file.js'),
hash: createHash('sha256').update(srcFile.content).digest('hex'),
};

reflinkFileSync(srcFile.path, destFile.path);

const destContent = readFileSync(destFile.path);
const destHash = createHash('sha256').update(destContent).digest('hex');

const sourceContent = readFileSync(srcFile.path);
const sourceHash = createHash('sha256').update(sourceContent).digest('hex');

expect(sourceContent).toStrictEqual(srcFile.content);
expect(sourceHash).toStrictEqual(destFile.hash);

expect(destContent).toStrictEqual(srcFile.content);
expect(destHash).toStrictEqual(destFile.hash);
});

it('should clone "sample.pyc" file correctly (async)', async () => {
const srcFile = {
path: resolve(join('fixtures', 'sample.pyc')),
Expand Down
113 changes: 113 additions & 0 deletions __test__/threads.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import { afterAll, beforeEach, describe, expect, it } from 'vitest';
import { Worker } from 'worker_threads';
import { join, relative, resolve, sep } from 'path';
import { mkdir, rm, writeFile } from 'fs/promises';
import { readFileSync } from 'fs';
import { randomUUID, createHash } from 'crypto';

const TEST_DIR = resolve(__dirname, '__reflink-tests-' + randomUUID());
const workerFile =
`.${sep}` + relative(process.cwd(), join(__dirname, 'worker.js'));

describe('reflink worker', () => {
beforeEach(async () => {
await rm(TEST_DIR, { recursive: true, force: true });
await mkdir(TEST_DIR, { recursive: true });
});

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

it('clone the same file to different location simultaneously (sync)', async () => {
const src = {
path: join(process.cwd(), 'fixtures', 'ascii-file.js'),
content: readFileSync(join(process.cwd(), 'fixtures', 'ascii-file.js')),
};

const destFiles = Array.from({ length: 100 }, () => ({
path: join(TEST_DIR, `dest-${randomUUID()}.js`),
}));

await writeFile(src.path, src.content);

const workers = destFiles.map((dest) => {
const worker = new Worker(workerFile);

worker.on('error', (err) => {
throw err;
});

return worker;
});

workers.forEach((worker, i) => {
worker.postMessage({
type: 'sync',
src: src.path,
dest: destFiles[i].path,
});
});

await Promise.all(
workers.map(
(worker) => new Promise((resolve) => worker.on('message', resolve))
)
);

const srcHash = createHash('sha256').update(src.content).digest('hex');

for (const dest of destFiles) {
const destContent = readFileSync(dest.path, 'utf8');
const destHash = createHash('sha256').update(destContent).digest('hex');

expect(destHash).toBe(srcHash);
}
});

it('clone the same file to different location simultaneously (sync)', async () => {
const src = {
path: join(process.cwd(), 'fixtures', 'ascii-file.js'),
content: readFileSync(join(process.cwd(), 'fixtures', 'ascii-file.js')),
};

const destFiles = Array.from({ length: 100 }, () => ({
path: join(TEST_DIR, `dest-${randomUUID()}.js`),
}));

await writeFile(src.path, src.content);

const workers = destFiles.map((dest) => {
const worker = new Worker(workerFile);

worker.on('error', (err) => {
throw err;
});

return worker;
});

workers.forEach((worker, i) => {
worker.postMessage({
type: 'async',
src: src.path,
dest: destFiles[i].path,
});
});

await Promise.all(
workers.map(
(worker) => new Promise((resolve) => worker.on('message', resolve))
)
);

const srcHash = createHash('sha256').update(src.content).digest('hex');

for (const dest of destFiles) {
const destContent = readFileSync(dest.path, 'utf8');
const destHash = createHash('sha256').update(destContent).digest('hex');

expect(destHash).toBe(srcHash);
}
});
});
16 changes: 16 additions & 0 deletions __test__/worker.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
const { parentPort } = require('worker_threads');
const { reflinkFileSync, reflinkFile } = require('../index.js');

parentPort?.on('message', async (data) => {
if (data.type === 'sync') {
reflinkFileSync(data.src, data.dest);
} else {
await reflinkFile(data.src, data.dest);
}

// console.log(`Cloned to ${data.dest} at ${new Date().toISOString()}`);

parentPort?.postMessage({ type: 'done' });
// Kill the worker
parentPort?.close();
});
Loading

0 comments on commit de30c93

Please sign in to comment.