Files

93 lines
4.4 KiB
JavaScript

// Index tests (C2-05a): the cache key and its bound, failed reads, mapped-only contents, and the rebuild
// time on a 3,000-file fixture. Fixtures are made up and built under the scratch area.
import { test } from 'node:test';
import assert from 'node:assert/strict';
import { mkdirSync, symlinkSync, writeFileSync } from 'node:fs';
import { join } from 'node:path';
import { performance } from 'node:perf_hooks';
import { clearIndexCache, indexCacheSize, indexFor } from '../src/index-build.mjs';
import { git, mapping, MARKER } from './helpers.mjs';
import { note, scratchRepo } from './query-fixture.mjs';
const FILES = {
'Book One/Characters/Mara Vell.md': note('character', 'Mara Vell', MARKER),
'Book One/Chapters/Chapter 01.md': '# One\n[[Mara Vell]]\n',
'Inbox Note.md': `${MARKER}\n`,
};
// A mapping whose harbor universe has the given display name. Each name gives a new cache key.
const named = name => mapping(e => ({ ...e, universes: { ...e.universes, harbor: { ...e.universes.harbor, name } } }));
test('the same commit, repo path and mapping return the same index, and only mapped files are in it', async t => {
clearIndexCache();
const { repo, commit } = scratchRepo(t, FILES);
const a = await indexFor({ repo, commit, mapping: mapping() });
const b = await indexFor({ repo, commit, mapping: mapping() });
assert.equal(a, b);
assert.equal(indexCacheSize(), 1);
assert.equal(a.commit, commit);
assert.ok(a.files.has('Book One/Characters/Mara Vell.md'));
assert.ok(!a.files.has('Inbox Note.md'));
assert.deepEqual(a.names.get('mara vell'), ['Book One/Characters/Mara Vell.md']);
assert.deepEqual(a.linksIn.get('Book One/Characters/Mara Vell.md').map(l => l.path), ['Book One/Chapters/Chapter 01.md']);
});
test('a different repo path, mapping or commit gets its own index', async t => {
clearIndexCache();
const { root, repo, commit } = scratchRepo(t, FILES);
const base = await indexFor({ repo, commit, mapping: mapping() });
const alias = join(root, 'alias');
symlinkSync(repo, alias);
assert.notEqual(await indexFor({ repo: alias, commit, mapping: mapping() }), base);
assert.notEqual(await indexFor({ repo, commit, mapping: named('Renamed Harbor') }), base);
mkdirSync(join(repo, 'Book One/Places'), { recursive: true });
writeFileSync(join(repo, 'Book One/Places/New.md'), note('place', 'New'));
git(repo, 'add', '-A');
git(repo, 'commit', '-qm', 'second');
const next = git(repo, 'rev-parse', 'HEAD');
const later = await indexFor({ repo, commit: next, mapping: mapping() });
assert.notEqual(later, base);
assert.equal(later.commit, next);
assert.ok(later.files.has('Book One/Places/New.md'));
});
test('the cache holds at most eight indexes and evicts the least recently used', async t => {
clearIndexCache();
const { repo, commit } = scratchRepo(t, FILES);
const maps = Array.from({ length: 9 }, (_, i) => named(`Harbor ${i}`));
const first = await indexFor({ repo, commit, mapping: maps[0] });
for (const m of maps.slice(1)) await indexFor({ repo, commit, mapping: m });
assert.equal(indexCacheSize(), 8);
assert.notEqual(await indexFor({ repo, commit, mapping: maps[0] }), first);
assert.equal(indexCacheSize(), 8);
});
test('a failed read is not kept in the cache', async t => {
clearIndexCache();
const { repo } = scratchRepo(t, FILES);
await assert.rejects(indexFor({ repo, commit: '0'.repeat(40), mapping: mapping() }));
assert.equal(indexCacheSize(), 0);
});
test('a missing or unchecked mapping is refused before any read', async t => {
clearIndexCache();
const { repo, commit } = scratchRepo(t, FILES);
await assert.rejects(indexFor({ repo, commit, mapping: undefined }), { code: 'library-mapping-invalid' });
await assert.rejects(indexFor({ repo, commit, mapping: { kind: 'hybrid' } }), { code: 'library-mapping-invalid' });
});
test('a 3,000-file rebuild completes and its time is reported', { timeout: 300_000 }, async t => {
clearIndexCache();
const folders = ['Characters', 'Places', 'Research'];
const files = {};
for (let i = 0; i < 3000; i++) {
files[`Book One/${folders[i % 3]}/Note ${i}.md`] = note('character', `Note ${i}`, `Body ${i} [[Note ${(i + 1) % 3000}]]`);
}
const { repo, commit } = scratchRepo(t, files);
const started = performance.now();
const index = await indexFor({ repo, commit, mapping: mapping() });
const ms = performance.now() - started;
t.diagnostic(`3,000-file index rebuild: ${ms.toFixed(0)} ms`);
assert.equal(index.paths.length, 3000);
});