feat: stream hashing y entradas en archivos
- Añade `computeHashesFromStream` para hashing desde streams - Añade `streamArchiveEntry` e integra en `importDirectory` (path codificado con ::) - Extiende `scanDirectory` para exponer entradas internas, normaliza rutas POSIX y evita traversal; `ARCHIVE_MAX_ENTRIES` configurable - Limpia listeners en hashing y mejora robustez/logging - Añade tests unitarios e integración; actualiza mocks a `Mock` types - CI: instala `unzip` junto a `p7zip` para soportar tests de integración
This commit is contained in:
54
backend/tests/services/archiveReader.integration.spec.ts
Normal file
54
backend/tests/services/archiveReader.integration.spec.ts
Normal file
@@ -0,0 +1,54 @@
|
||||
import { test, expect } from 'vitest';
|
||||
import { promises as fs } from 'fs';
|
||||
import path from 'path';
|
||||
import { execSync } from 'child_process';
|
||||
import { computeHashesFromStream } from '../../src/services/checksumService';
|
||||
import { streamArchiveEntry } from '../../src/services/archiveReader';
|
||||
import { createHash } from 'crypto';
|
||||
|
||||
function hasBinary(bin: string): boolean {
|
||||
try {
|
||||
execSync(`which ${bin}`, { stdio: 'ignore' });
|
||||
return true;
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
const wantIntegration = process.env.INTEGRATION === '1';
|
||||
const canCreate = hasBinary('7z') || hasBinary('zip');
|
||||
|
||||
if (!wantIntegration) {
|
||||
test.skip('archiveReader integration tests require INTEGRATION=1', () => {});
|
||||
} else if (!canCreate) {
|
||||
test.skip('archiveReader integration tests skipped: no archive creation tool (7z or zip) available', () => {});
|
||||
} else {
|
||||
test('reads entry from zip using system tools', async () => {
|
||||
const tmpDir = await fs.mkdtemp(path.join(process.cwd(), 'tmp-arc-'));
|
||||
const inner = path.join(tmpDir, 'game.rom');
|
||||
const content = 'QUASAR-INTEGRATION-TEST';
|
||||
await fs.writeFile(inner, content);
|
||||
|
||||
const archivePath = path.join(tmpDir, 'simple.zip');
|
||||
|
||||
// create zip using available tool
|
||||
if (hasBinary('7z')) {
|
||||
execSync(`7z a -tzip ${JSON.stringify(archivePath)} ${JSON.stringify(inner)}`, {
|
||||
stdio: 'ignore',
|
||||
});
|
||||
} else {
|
||||
execSync(`zip -j ${JSON.stringify(archivePath)} ${JSON.stringify(inner)}`, {
|
||||
stdio: 'ignore',
|
||||
});
|
||||
}
|
||||
|
||||
const stream = await streamArchiveEntry(archivePath, path.basename(inner));
|
||||
expect(stream).not.toBeNull();
|
||||
const hashes = await computeHashesFromStream(stream as any);
|
||||
|
||||
const expectedMd5 = createHash('md5').update(content).digest('hex');
|
||||
expect(hashes.md5).toBe(expectedMd5);
|
||||
|
||||
await fs.rm(tmpDir, { recursive: true, force: true });
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user