Files
duplicati_preview/test/repository.integration.test.js
T

138 lines
4.1 KiB
JavaScript

import test from 'node:test';
import assert from 'node:assert/strict';
import fs from 'node:fs';
import os from 'node:os';
import path from 'node:path';
import { DuplicatiRepository } from '../src/db/duplicatiRepository.js';
import { openWritableSqlite } from '../src/db/sqlite.js';
import { createDuplicatiFixture } from './support/duplicatiFixture.js';
function createAppDatabasePath() {
const tempDirectory = fs.mkdtempSync(path.join(os.tmpdir(), 'duplicati-app-'));
return {
appDbPath: path.join(tempDirectory, 'app.sqlite'),
cleanup() {
fs.rmSync(tempDirectory, { recursive: true, force: true });
}
};
}
async function openAttachedRepository(sourceOverrides = {}) {
const fixture = createDuplicatiFixture(sourceOverrides);
const appDb = createAppDatabasePath();
const database = await openWritableSqlite(appDb.appDbPath);
await database.attachDatabase('source', fixture.databasePath, { readOnly: true });
const sourceLayout = sourceOverrides.layout ?? 'file';
const repository = new DuplicatiRepository({
database,
previewMaxBytes: 1024,
source: {
id: 'source-1',
storagePath: fixture.databasePath,
sha256: 'sha-demo',
capabilities: {
archiveEntryIndex: true,
volumeCryptoCache: true
}
},
sourceLayout
});
return {
fixture,
appDb,
repository,
database
};
}
test('listDirectory returns immediate directory and file children', async () => {
const session = await openAttachedRepository();
try {
const result = await session.repository.listDirectory({
apiPath: '/C:/media',
snapshotId: 'latest'
});
assert.equal(result.path, '/C:/media');
assert.equal(result.entries.length, 2);
assert.deepEqual(
result.entries.map((entry) => ({
type: entry.type,
path: entry.path
})),
[
{ type: 'dir', path: '/C:/media/movies' },
{ type: 'file', path: '/C:/media/readme.txt' }
]
);
} finally {
await session.database.detachDatabase('source');
await session.database.close();
session.fixture.cleanup();
session.appDb.cleanup();
}
});
test('getFileInfo expands ordered segments and required dblocks', async () => {
const session = await openAttachedRepository();
try {
const listing = await session.repository.listDirectory({
apiPath: '/C:/media/movies',
snapshotId: 'latest'
});
const fileId = listing.entries.find((entry) => entry.type === 'file')?.id;
assert.ok(fileId);
const result = await session.repository.getFileInfo(fileId);
assert.equal(result.file.path, '/C:/media/movies/demo.mp4');
assert.equal(result.restorePlan.segmentCount, 3);
assert.equal(result.restorePlan.blockSize, 102400);
assert.equal(result.requiredDblocks.length, 1);
assert.equal(result.requiredDblocks[0], 'duplicati-demo.dblock.zip.aes');
assert.equal(result.volumes[0].encryption.streamFormat, 'v2');
assert.equal(result.segments[0].logicalOffset, 0);
assert.equal(result.segments[1].logicalOffset, 102400);
assert.equal(result.segments[2].zip.compressionMethod, 'deflate');
} finally {
await session.database.detachDatabase('source');
await session.database.close();
session.fixture.cleanup();
session.appDb.cleanup();
}
});
test('listDirectory supports FileLookup plus PathPrefix based databases', async () => {
const session = await openAttachedRepository({ layout: 'file_lookup' });
try {
const result = await session.repository.listDirectory({
apiPath: '/source/media',
snapshotId: 'latest'
});
assert.equal(result.path, '/source/media');
assert.equal(result.entries.length, 2);
assert.deepEqual(
result.entries.map((entry) => ({
type: entry.type,
path: entry.path
})),
[
{ type: 'dir', path: '/source/media/movies' },
{ type: 'file', path: '/source/media/readme.txt' }
]
);
} finally {
await session.database.detachDatabase('source');
await session.database.close();
session.fixture.cleanup();
session.appDb.cleanup();
}
});