mirror of
https://github.com/immich-app/immich.git
synced 2025-12-21 17:25:35 +03:00
test: write tests for ProcessRepository#createSpawnDuplexStream
This commit is contained in:
85
server/src/repositories/process.repository.spec.ts
Normal file
85
server/src/repositories/process.repository.spec.ts
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
import { ChildProcessWithoutNullStreams } from 'node:child_process';
|
||||||
|
import { Readable, Writable } from 'node:stream';
|
||||||
|
import { pipeline } from 'node:stream/promises';
|
||||||
|
import { ProcessRepository } from 'src/repositories/process.repository';
|
||||||
|
|
||||||
|
describe(ProcessRepository.name, () => {
|
||||||
|
let sut: ProcessRepository;
|
||||||
|
let sink: Writable;
|
||||||
|
|
||||||
|
beforeAll(() => {
|
||||||
|
sut = new ProcessRepository();
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
sink = new Writable({
|
||||||
|
write(_chunk, _encoding, callback) {
|
||||||
|
callback();
|
||||||
|
},
|
||||||
|
|
||||||
|
final(callback) {
|
||||||
|
callback();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('createSpawnDuplexStream', () => {
|
||||||
|
it('should work (drain to stdout)', async () => {
|
||||||
|
const process = sut.createSpawnDuplexStream('bash', ['-c', 'exit 0']);
|
||||||
|
await pipeline(process, sink);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should throw on non-zero exit code', async () => {
|
||||||
|
const process = sut.createSpawnDuplexStream('bash', ['-c', 'echo "error message" >&2; exit 1']);
|
||||||
|
await expect(pipeline(process, sink)).rejects.toThrowErrorMatchingInlineSnapshot(`
|
||||||
|
[Error: bash non-zero exit code (1)
|
||||||
|
error message
|
||||||
|
]
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should accept stdin / output stdout', async () => {
|
||||||
|
async function* data() {
|
||||||
|
yield 'Hello, world!';
|
||||||
|
}
|
||||||
|
|
||||||
|
let output = '';
|
||||||
|
const sink = new Writable({
|
||||||
|
write(chunk, _encoding, callback) {
|
||||||
|
output += chunk;
|
||||||
|
callback();
|
||||||
|
},
|
||||||
|
|
||||||
|
final(callback) {
|
||||||
|
callback();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const echoProcess = sut.createSpawnDuplexStream('cat');
|
||||||
|
await pipeline(Readable.from(data()), echoProcess, sink);
|
||||||
|
expect(output).toBe('Hello, world!');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should drain stdin on process exit', async () => {
|
||||||
|
let resolve1: () => void;
|
||||||
|
let resolve2: () => void;
|
||||||
|
const promise1 = new Promise<void>((r) => (resolve1 = r));
|
||||||
|
const promise2 = new Promise<void>((r) => (resolve2 = r));
|
||||||
|
|
||||||
|
async function* data() {
|
||||||
|
yield 'Hello, world!';
|
||||||
|
await promise1;
|
||||||
|
await promise2;
|
||||||
|
yield 'Write after stdin close / process exit!';
|
||||||
|
}
|
||||||
|
|
||||||
|
const process = sut.createSpawnDuplexStream('bash', ['-c', 'exit 0']);
|
||||||
|
|
||||||
|
const realProcess = (process as never as { _process: ChildProcessWithoutNullStreams })._process;
|
||||||
|
realProcess.on('close', () => setImmediate(() => resolve1()));
|
||||||
|
realProcess.stdin.on('close', () => setImmediate(() => resolve2()));
|
||||||
|
|
||||||
|
await pipeline(Readable.from(data()), process);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user