138 lines
4.1 KiB
JavaScript
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();
|
|
}
|
|
});
|