2024-11-08 05:21:56 -05:00
|
|
|
const fs = require('node:fs')
|
|
|
|
const Path = require('node:path')
|
2021-05-17 09:07:37 -04:00
|
|
|
const { expect } = require('chai')
|
|
|
|
|
|
|
|
const MODULE_PATH = '../../../app/js/ContentCacheManager'
|
|
|
|
|
|
|
|
describe('ContentCacheManager', function () {
|
2022-08-02 05:09:22 -04:00
|
|
|
let contentDir, pdfPath, xrefPath
|
2021-05-31 04:20:25 -04:00
|
|
|
let ContentCacheManager, files, Settings
|
|
|
|
before(function () {
|
2021-07-12 12:47:21 -04:00
|
|
|
Settings = require('@overleaf/settings')
|
2021-05-31 04:20:25 -04:00
|
|
|
ContentCacheManager = require(MODULE_PATH)
|
|
|
|
})
|
2021-05-18 13:06:15 -04:00
|
|
|
let contentRanges, newContentRanges, reclaimed
|
2022-10-25 05:24:11 -04:00
|
|
|
async function run(filePath, pdfSize, pdfCachingMinChunkSize) {
|
|
|
|
const result = await ContentCacheManager.promises.update({
|
2021-05-31 04:20:25 -04:00
|
|
|
contentDir,
|
|
|
|
filePath,
|
2022-10-25 05:24:11 -04:00
|
|
|
pdfSize,
|
|
|
|
pdfCachingMinChunkSize,
|
|
|
|
compileTime: 1337,
|
|
|
|
})
|
2021-05-31 04:20:25 -04:00
|
|
|
let newlyReclaimed
|
2022-07-20 10:17:41 -04:00
|
|
|
;({
|
|
|
|
contentRanges,
|
|
|
|
newContentRanges,
|
|
|
|
reclaimedSpace: newlyReclaimed,
|
|
|
|
} = result)
|
2021-05-31 04:20:25 -04:00
|
|
|
reclaimed += newlyReclaimed
|
|
|
|
|
|
|
|
const fileNames = await fs.promises.readdir(contentDir)
|
|
|
|
files = {}
|
|
|
|
for (const fileName of fileNames) {
|
|
|
|
const path = Path.join(contentDir, fileName)
|
|
|
|
files[path] = await fs.promises.readFile(path)
|
|
|
|
}
|
2021-05-17 09:07:37 -04:00
|
|
|
}
|
2021-05-31 04:20:25 -04:00
|
|
|
before(function () {
|
2021-05-17 09:07:37 -04:00
|
|
|
contentDir =
|
2022-01-06 10:02:36 -05:00
|
|
|
'/overleaf/services/clsi/output/602cee6f6460fca0ba7921e6/content/1797a7f48f9-5abc1998509dea1f'
|
2021-05-17 09:07:37 -04:00
|
|
|
pdfPath =
|
2022-01-06 10:02:36 -05:00
|
|
|
'/overleaf/services/clsi/output/602cee6f6460fca0ba7921e6/generated-files/1797a7f48ea-8ac6805139f43351/output.pdf'
|
2022-08-02 05:09:22 -04:00
|
|
|
xrefPath =
|
|
|
|
'/overleaf/services/clsi/output/602cee6f6460fca0ba7921e6/generated-files/1797a7f48ea-8ac6805139f43351/output.pdfxref'
|
2021-05-31 04:20:25 -04:00
|
|
|
|
|
|
|
reclaimed = 0
|
|
|
|
Settings.pdfCachingMinChunkSize = 1024
|
|
|
|
})
|
|
|
|
|
|
|
|
before(async function () {
|
2022-04-26 09:29:42 -04:00
|
|
|
await fs.promises.rm(contentDir, { recursive: true, force: true })
|
2021-05-31 04:20:25 -04:00
|
|
|
await fs.promises.mkdir(contentDir, { recursive: true })
|
|
|
|
await fs.promises.mkdir(Path.dirname(pdfPath), { recursive: true })
|
2021-05-17 09:07:37 -04:00
|
|
|
})
|
|
|
|
|
2021-05-31 04:20:25 -04:00
|
|
|
describe('minimal', function () {
|
2022-08-02 05:09:22 -04:00
|
|
|
const PATH_MINIMAL_PDF = 'test/acceptance/fixtures/minimal.pdf'
|
|
|
|
const PATH_MINIMAL_XREF = 'test/acceptance/fixtures/minimal.pdfxref'
|
2021-05-31 04:20:25 -04:00
|
|
|
const OBJECT_ID_1 = '9 0 '
|
|
|
|
const HASH_LARGE =
|
|
|
|
'd7cfc73ad2fba4578a437517923e3714927bbf35e63ea88bd93c7a8076cf1fcd'
|
|
|
|
const OBJECT_ID_2 = '10 0 '
|
|
|
|
const HASH_SMALL =
|
|
|
|
'896749b8343851b0dc385f71616916a7ba0434fcfb56d1fc7e27cd139eaa2f71'
|
|
|
|
function getChunkPath(hash) {
|
|
|
|
return Path.join('test/unit/js/snapshots/minimalCompile/chunks', hash)
|
|
|
|
}
|
|
|
|
let MINIMAL_SIZE, RANGE_1, RANGE_2, h1, h2, START_1, START_2, END_1, END_2
|
|
|
|
before(async function () {
|
2022-08-02 05:09:22 -04:00
|
|
|
await fs.promises.copyFile(PATH_MINIMAL_PDF, pdfPath)
|
|
|
|
await fs.promises.copyFile(PATH_MINIMAL_XREF, xrefPath)
|
|
|
|
const MINIMAL = await fs.promises.readFile(PATH_MINIMAL_PDF)
|
|
|
|
MINIMAL_SIZE = (await fs.promises.stat(PATH_MINIMAL_PDF)).size
|
2021-05-31 04:20:25 -04:00
|
|
|
RANGE_1 = await fs.promises.readFile(getChunkPath(HASH_LARGE))
|
|
|
|
RANGE_2 = await fs.promises.readFile(getChunkPath(HASH_SMALL))
|
|
|
|
h1 = HASH_LARGE
|
|
|
|
h2 = HASH_SMALL
|
|
|
|
START_1 = MINIMAL.indexOf(RANGE_1)
|
|
|
|
END_1 = START_1 + RANGE_1.byteLength
|
|
|
|
START_2 = MINIMAL.indexOf(RANGE_2)
|
|
|
|
END_2 = START_2 + RANGE_2.byteLength
|
2021-05-17 09:07:37 -04:00
|
|
|
})
|
2022-10-25 05:24:11 -04:00
|
|
|
async function runWithMinimal(pdfCachingMinChunkSize) {
|
|
|
|
await run(pdfPath, MINIMAL_SIZE, pdfCachingMinChunkSize)
|
2021-05-31 04:20:25 -04:00
|
|
|
}
|
2021-05-17 09:07:37 -04:00
|
|
|
|
2021-05-31 04:20:25 -04:00
|
|
|
describe('with two ranges qualifying', function () {
|
|
|
|
before(async function () {
|
2022-10-25 05:24:11 -04:00
|
|
|
await runWithMinimal(500)
|
2021-05-31 04:20:25 -04:00
|
|
|
})
|
|
|
|
it('should produce two ranges', function () {
|
|
|
|
expect(contentRanges).to.have.length(2)
|
2021-05-17 09:07:37 -04:00
|
|
|
})
|
|
|
|
|
|
|
|
it('should find the correct offsets', function () {
|
|
|
|
expect(contentRanges).to.deep.equal([
|
|
|
|
{
|
2021-05-31 04:20:25 -04:00
|
|
|
objectId: OBJECT_ID_1,
|
|
|
|
start: START_1,
|
|
|
|
end: END_1,
|
2021-07-13 07:04:48 -04:00
|
|
|
hash: h1,
|
2021-05-17 09:07:37 -04:00
|
|
|
},
|
|
|
|
{
|
2021-05-31 04:20:25 -04:00
|
|
|
objectId: OBJECT_ID_2,
|
|
|
|
start: START_2,
|
|
|
|
end: END_2,
|
2021-07-13 07:04:48 -04:00
|
|
|
hash: h2,
|
|
|
|
},
|
2021-05-17 09:07:37 -04:00
|
|
|
])
|
|
|
|
})
|
|
|
|
|
|
|
|
it('should store the contents', function () {
|
2021-05-31 04:20:25 -04:00
|
|
|
expect(files).to.deep.equal({
|
|
|
|
[Path.join(contentDir, h1)]: RANGE_1,
|
|
|
|
[Path.join(contentDir, h2)]: RANGE_2,
|
|
|
|
[Path.join(contentDir, '.state.v0.json')]: Buffer.from(
|
|
|
|
JSON.stringify({
|
2021-05-18 13:06:15 -04:00
|
|
|
hashAge: [
|
|
|
|
[h1, 0],
|
2021-07-13 07:04:48 -04:00
|
|
|
[h2, 0],
|
2021-05-18 13:06:15 -04:00
|
|
|
],
|
|
|
|
hashSize: [
|
2021-05-31 04:20:25 -04:00
|
|
|
[h1, RANGE_1.byteLength],
|
2021-07-13 07:04:48 -04:00
|
|
|
[h2, RANGE_2.byteLength],
|
|
|
|
],
|
2021-05-31 04:20:25 -04:00
|
|
|
})
|
2021-07-13 07:04:48 -04:00
|
|
|
),
|
2021-05-17 09:07:37 -04:00
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
it('should mark all ranges as new', function () {
|
|
|
|
expect(contentRanges).to.deep.equal(newContentRanges)
|
|
|
|
})
|
2021-05-18 13:06:15 -04:00
|
|
|
|
2021-05-31 04:20:25 -04:00
|
|
|
describe('when re-running with one range too small', function () {
|
|
|
|
before(async function () {
|
2022-10-25 05:24:11 -04:00
|
|
|
await runWithMinimal(1024)
|
2021-05-18 13:06:15 -04:00
|
|
|
})
|
|
|
|
|
2021-05-31 04:20:25 -04:00
|
|
|
it('should produce one range', function () {
|
|
|
|
expect(contentRanges).to.have.length(1)
|
2021-05-18 13:06:15 -04:00
|
|
|
})
|
|
|
|
|
|
|
|
it('should find the correct offsets', function () {
|
|
|
|
expect(contentRanges).to.deep.equal([
|
|
|
|
{
|
2021-05-31 04:20:25 -04:00
|
|
|
objectId: OBJECT_ID_1,
|
|
|
|
start: START_1,
|
|
|
|
end: END_1,
|
2021-07-13 07:04:48 -04:00
|
|
|
hash: h1,
|
|
|
|
},
|
2021-05-18 13:06:15 -04:00
|
|
|
])
|
|
|
|
})
|
|
|
|
|
|
|
|
it('should update the age of the 2nd range', function () {
|
2021-05-31 04:20:25 -04:00
|
|
|
expect(files).to.deep.equal({
|
|
|
|
[Path.join(contentDir, h1)]: RANGE_1,
|
|
|
|
[Path.join(contentDir, h2)]: RANGE_2,
|
|
|
|
[Path.join(contentDir, '.state.v0.json')]: Buffer.from(
|
|
|
|
JSON.stringify({
|
2021-05-18 13:06:15 -04:00
|
|
|
hashAge: [
|
|
|
|
[h1, 0],
|
2021-07-13 07:04:48 -04:00
|
|
|
[h2, 1],
|
2021-05-18 13:06:15 -04:00
|
|
|
],
|
|
|
|
hashSize: [
|
2021-05-31 04:20:25 -04:00
|
|
|
[h1, RANGE_1.byteLength],
|
2021-07-13 07:04:48 -04:00
|
|
|
[h2, RANGE_2.byteLength],
|
|
|
|
],
|
2021-05-31 04:20:25 -04:00
|
|
|
})
|
2021-07-13 07:04:48 -04:00
|
|
|
),
|
2021-05-18 13:06:15 -04:00
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
it('should find no new ranges', function () {
|
|
|
|
expect(newContentRanges).to.deep.equal([])
|
|
|
|
})
|
|
|
|
|
|
|
|
describe('when re-running 5 more times', function () {
|
|
|
|
for (let i = 0; i < 5; i++) {
|
2021-05-31 04:20:25 -04:00
|
|
|
before(async function () {
|
2022-10-25 05:24:11 -04:00
|
|
|
await runWithMinimal(1024)
|
2021-05-18 13:06:15 -04:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2021-05-31 04:20:25 -04:00
|
|
|
it('should still produce one range', function () {
|
|
|
|
expect(contentRanges).to.have.length(1)
|
2021-05-18 13:06:15 -04:00
|
|
|
})
|
|
|
|
|
|
|
|
it('should still find the correct offsets', function () {
|
|
|
|
expect(contentRanges).to.deep.equal([
|
|
|
|
{
|
2021-05-31 04:20:25 -04:00
|
|
|
objectId: OBJECT_ID_1,
|
|
|
|
start: START_1,
|
|
|
|
end: END_1,
|
2021-07-13 07:04:48 -04:00
|
|
|
hash: h1,
|
|
|
|
},
|
2021-05-18 13:06:15 -04:00
|
|
|
])
|
|
|
|
})
|
|
|
|
|
|
|
|
it('should delete the 2nd range', function () {
|
2021-05-31 04:20:25 -04:00
|
|
|
expect(files).to.deep.equal({
|
|
|
|
[Path.join(contentDir, h1)]: RANGE_1,
|
|
|
|
[Path.join(contentDir, '.state.v0.json')]: Buffer.from(
|
|
|
|
JSON.stringify({
|
|
|
|
hashAge: [[h1, 0]],
|
2021-07-13 07:04:48 -04:00
|
|
|
hashSize: [[h1, RANGE_1.byteLength]],
|
2021-05-31 04:20:25 -04:00
|
|
|
})
|
2021-07-13 07:04:48 -04:00
|
|
|
),
|
2021-05-18 13:06:15 -04:00
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
it('should find no new ranges', function () {
|
|
|
|
expect(newContentRanges).to.deep.equal([])
|
|
|
|
})
|
|
|
|
|
|
|
|
it('should yield the reclaimed space', function () {
|
2021-05-31 04:20:25 -04:00
|
|
|
expect(reclaimed).to.equal(RANGE_2.byteLength)
|
2021-05-18 13:06:15 -04:00
|
|
|
})
|
|
|
|
})
|
|
|
|
})
|
2021-05-17 09:07:37 -04:00
|
|
|
})
|
|
|
|
})
|
|
|
|
})
|