Files
quasar/backend/tests/services/archiveReader.integration.spec.ts
Benito Rodríguez 79c42fad55 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
2026-02-09 19:49:56 +01:00

55 lines
1.8 KiB
TypeScript

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 });
});
}