mirror of
https://github.com/yu-i-i/overleaf-cep.git
synced 2026-06-08 16:50:44 +02:00
Merge pull request #24977 from overleaf/bg-history-buffer-improve-tests
add more tests for chunk buffer in history-v1 GitOrigin-RevId: 3cfa2492efd67597a2782ca7a5671889a67049d5
This commit is contained in:
@@ -8,6 +8,11 @@ const {
|
||||
History,
|
||||
File,
|
||||
AddFileOperation,
|
||||
EditFileOperation,
|
||||
AddCommentOperation,
|
||||
TextOperation,
|
||||
Range,
|
||||
TrackingProps,
|
||||
Change,
|
||||
} = require('overleaf-editor-core')
|
||||
const cleanup = require('./support/cleanup')
|
||||
@@ -59,6 +64,9 @@ describe('chunk buffer', function () {
|
||||
})
|
||||
|
||||
it('should load from chunk store and update cache on first access (cache miss)', async function () {
|
||||
// Load the underlying chunk from the chunk store for verification
|
||||
const storedChunk = await chunkStore.loadLatest(projectId)
|
||||
|
||||
// First access should load from chunk store and populate cache
|
||||
const firstResult = await chunkBuffer.loadLatest(projectId)
|
||||
|
||||
@@ -67,6 +75,9 @@ describe('chunk buffer', function () {
|
||||
expect(firstResult.getStartVersion()).to.equal(1)
|
||||
expect(firstResult.getEndVersion()).to.equal(2)
|
||||
|
||||
// Verify the chunk is the same as the one in the store
|
||||
expect(firstResult).to.deep.equal(storedChunk)
|
||||
|
||||
// Verify that we got a cache miss metric
|
||||
expect(
|
||||
metrics.inc.calledWith('chunk_buffer.loadLatest', 1, {
|
||||
@@ -85,6 +96,9 @@ describe('chunk buffer', function () {
|
||||
expect(secondResult.getStartVersion()).to.equal(1)
|
||||
expect(secondResult.getEndVersion()).to.equal(2)
|
||||
|
||||
// Verify the chunk is the same as the one in the store
|
||||
expect(secondResult).to.deep.equal(storedChunk)
|
||||
|
||||
// Verify that we got a cache hit metric
|
||||
expect(
|
||||
metrics.inc.calledWith('chunk_buffer.loadLatest', 1, {
|
||||
@@ -99,6 +113,7 @@ describe('chunk buffer', function () {
|
||||
expect(secondResult.getEndVersion()).to.equal(
|
||||
firstResult.getEndVersion()
|
||||
)
|
||||
expect(secondResult).to.deep.equal(firstResult)
|
||||
})
|
||||
|
||||
it('should refresh the cache when chunk changes in the store', async function () {
|
||||
@@ -129,12 +144,17 @@ describe('chunk buffer', function () {
|
||||
// Store the new chunk directly in the chunk store
|
||||
await chunkStore.create(projectId, newChunk)
|
||||
|
||||
// Load the underlying chunk from the chunk store for verification
|
||||
const storedChunk = await chunkStore.loadLatest(projectId)
|
||||
|
||||
// Access again - should detect the change and refresh cache
|
||||
const secondResult = await chunkBuffer.loadLatest(projectId)
|
||||
|
||||
// Verify we got the updated chunk
|
||||
expect(secondResult.getStartVersion()).to.equal(2)
|
||||
expect(secondResult.getEndVersion()).to.equal(3)
|
||||
// Verify that the chunk content is the same
|
||||
expect(secondResult).to.deep.equal(storedChunk)
|
||||
|
||||
// Verify that we got a cache miss metric (since the cached chunk was invalidated)
|
||||
expect(
|
||||
@@ -145,6 +165,9 @@ describe('chunk buffer', function () {
|
||||
})
|
||||
|
||||
it('should continue using cache when chunk in store has not changed', async function () {
|
||||
// Load the underlying chunk from the chunk store for verification
|
||||
const storedChunk = await chunkStore.loadLatest(projectId)
|
||||
|
||||
// First access to load into cache
|
||||
await chunkBuffer.loadLatest(projectId)
|
||||
|
||||
@@ -157,6 +180,7 @@ describe('chunk buffer', function () {
|
||||
// Verify we got the same chunk
|
||||
expect(result.getStartVersion()).to.equal(1)
|
||||
expect(result.getEndVersion()).to.equal(2)
|
||||
expect(result).to.deep.equal(storedChunk)
|
||||
|
||||
// Verify that we got a cache hit metric
|
||||
expect(
|
||||
@@ -167,11 +191,122 @@ describe('chunk buffer', function () {
|
||||
})
|
||||
})
|
||||
|
||||
it('should handle a chunk with metadata, comments and tracked changes', async function () {
|
||||
// Create a snapshot and initial file
|
||||
const snapshot = new Snapshot()
|
||||
const initialFileOp = new AddFileOperation(
|
||||
'test.tex',
|
||||
File.fromString('Initial line.\\nSecond line.', {
|
||||
meta1: 'abc',
|
||||
meta2: 'def',
|
||||
})
|
||||
)
|
||||
const initialChange = new Change([initialFileOp], new Date(), [])
|
||||
|
||||
// Add a comment
|
||||
const commentOp = new AddCommentOperation(
|
||||
'comment1',
|
||||
[new Range(0, 7)] // Range for "Initial"
|
||||
)
|
||||
const commentChange = new Change(
|
||||
[new EditFileOperation('test.tex', commentOp)],
|
||||
new Date(),
|
||||
[]
|
||||
)
|
||||
|
||||
// Tracked insert
|
||||
const trackedInsertOp = new TextOperation()
|
||||
.retain(14)
|
||||
.insert('Hello', {
|
||||
commentIds: ['comment1'],
|
||||
tracking: TrackingProps.fromRaw({
|
||||
ts: '2024-01-01T00:00:00.000Z',
|
||||
type: 'insert',
|
||||
userId: 'user1',
|
||||
}),
|
||||
})
|
||||
.retain(12)
|
||||
const insertChange = new Change(
|
||||
[new EditFileOperation('test.tex', trackedInsertOp)],
|
||||
new Date(),
|
||||
[]
|
||||
)
|
||||
|
||||
// Tracked delete
|
||||
const trackedDeleteOp = new TextOperation().retain(14, {
|
||||
tracking: TrackingProps.fromRaw({
|
||||
ts: '2024-01-01T00:00:00.000Z',
|
||||
type: 'delete',
|
||||
userId: 'user1',
|
||||
}),
|
||||
})
|
||||
const deleteChange = new Change(
|
||||
[new EditFileOperation('test.tex', trackedDeleteOp)],
|
||||
new Date(),
|
||||
[]
|
||||
)
|
||||
|
||||
// Combine changes into history and create chunk
|
||||
const history = new History(snapshot, [
|
||||
initialChange,
|
||||
commentChange,
|
||||
insertChange,
|
||||
deleteChange,
|
||||
])
|
||||
const chunk = new Chunk(history, 1) // Start version 0
|
||||
// Store the chunk
|
||||
await chunkStore.create(projectId, chunk)
|
||||
// Clear the cache
|
||||
await redisBackend.clearCache(projectId)
|
||||
metrics.inc.resetHistory()
|
||||
|
||||
// Load the underlying chunk from the chunk store for verification
|
||||
const storedChunk = await chunkStore.loadLatest(projectId)
|
||||
|
||||
// Load the chunk via buffer (cache miss)
|
||||
const firstResult = await chunkBuffer.loadLatest(projectId)
|
||||
|
||||
// Verify chunk details
|
||||
expect(firstResult.getStartVersion()).to.equal(1)
|
||||
expect(firstResult.getEndVersion()).to.equal(5) // 4 changes
|
||||
expect(firstResult.history.changes.length).to.equal(4)
|
||||
expect(firstResult).to.deep.equal(storedChunk)
|
||||
|
||||
// Verify cache miss metric
|
||||
expect(
|
||||
metrics.inc.calledWith('chunk_buffer.loadLatest', 1, {
|
||||
status: 'cache-miss',
|
||||
})
|
||||
).to.be.true
|
||||
|
||||
// Reset metrics
|
||||
metrics.inc.resetHistory()
|
||||
|
||||
// Second access should hit the cache
|
||||
const secondResult = await chunkBuffer.loadLatest(projectId)
|
||||
|
||||
// Verify we got the same chunk
|
||||
expect(secondResult.getStartVersion()).to.equal(1)
|
||||
expect(secondResult.getEndVersion()).to.equal(5)
|
||||
expect(secondResult.history.changes.length).to.equal(4)
|
||||
expect(secondResult).to.deep.equal(storedChunk)
|
||||
|
||||
// Verify cache hit metric
|
||||
expect(
|
||||
metrics.inc.calledWith('chunk_buffer.loadLatest', 1, {
|
||||
status: 'cache-hit',
|
||||
})
|
||||
).to.be.true
|
||||
})
|
||||
|
||||
describe('with an empty project', function () {
|
||||
it('should handle a case with empty chunks (no changes)', async function () {
|
||||
// Clear the cache
|
||||
await redisBackend.clearCache(projectId)
|
||||
|
||||
// Load the underlying chunk from the chunk store for verification
|
||||
const storedChunk = await chunkStore.loadLatest(projectId)
|
||||
|
||||
// Load the initial empty chunk via buffer
|
||||
const result = await chunkBuffer.loadLatest(projectId)
|
||||
|
||||
@@ -180,6 +315,9 @@ describe('chunk buffer', function () {
|
||||
expect(result.getEndVersion()).to.equal(0) // Start equals end for empty chunks
|
||||
expect(result.history.changes.length).to.equal(0)
|
||||
|
||||
// Verify that the chunk is the same as the one in the store
|
||||
expect(result).to.deep.equal(storedChunk)
|
||||
|
||||
// Verify cache miss metric
|
||||
expect(
|
||||
metrics.inc.calledWith('chunk_buffer.loadLatest', 1, {
|
||||
@@ -198,6 +336,9 @@ describe('chunk buffer', function () {
|
||||
expect(secondResult.getEndVersion()).to.equal(0)
|
||||
expect(secondResult.history.changes.length).to.equal(0)
|
||||
|
||||
// Verify that the chunk is the same as the one in the store
|
||||
expect(secondResult).to.deep.equal(storedChunk)
|
||||
|
||||
// Verify cache hit metric
|
||||
expect(
|
||||
metrics.inc.calledWith('chunk_buffer.loadLatest', 1, {
|
||||
|
||||
Reference in New Issue
Block a user