persist_changes.test.js 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. 'use strict'
  2. const { expect } = require('chai')
  3. const cleanup = require('./support/cleanup')
  4. const fixtures = require('./support/fixtures')
  5. const storage = require('../../../../storage')
  6. const chunkStore = storage.chunkStore
  7. const persistChanges = storage.persistChanges
  8. const core = require('overleaf-editor-core')
  9. const AddFileOperation = core.AddFileOperation
  10. const Change = core.Change
  11. const Chunk = core.Chunk
  12. const File = core.File
  13. const History = core.History
  14. const Snapshot = core.Snapshot
  15. describe('persistChanges', function () {
  16. beforeEach(cleanup.everything)
  17. beforeEach(fixtures.create)
  18. let farFuture
  19. before(function () {
  20. // used to provide a limit which forces us to persist all of the changes.
  21. farFuture = new Date()
  22. farFuture.setTime(farFuture.getTime() + 7 * 24 * 3600 * 1000)
  23. })
  24. it('persists changes', function () {
  25. const limitsToPersistImmediately = {
  26. minChangeTimestamp: farFuture,
  27. maxChangeTimestamp: farFuture,
  28. }
  29. const projectId = fixtures.docs.uninitializedProject.id
  30. const change = new Change(
  31. [new AddFileOperation('test.tex', File.fromString(''))],
  32. new Date(),
  33. []
  34. )
  35. const changes = [change]
  36. return chunkStore
  37. .initializeProject(projectId)
  38. .then(() => {
  39. return persistChanges(projectId, changes, limitsToPersistImmediately, 0)
  40. })
  41. .then(result => {
  42. const history = new History(new Snapshot(), changes)
  43. const currentChunk = new Chunk(history, 0)
  44. expect(result).to.deep.equal({
  45. numberOfChangesPersisted: 1,
  46. originalEndVersion: 0,
  47. currentChunk,
  48. })
  49. return chunkStore.loadLatest(projectId)
  50. })
  51. .then(chunk => {
  52. expect(chunk.getStartVersion()).to.equal(0)
  53. expect(chunk.getEndVersion()).to.equal(1)
  54. expect(chunk.getChanges().length).to.equal(1)
  55. })
  56. })
  57. it('persists changes in two chunks', function () {
  58. const limitsToPersistImmediately = {
  59. maxChunkChanges: 1,
  60. minChangeTimestamp: farFuture,
  61. maxChangeTimestamp: farFuture,
  62. }
  63. const projectId = fixtures.docs.uninitializedProject.id
  64. const firstChange = new Change(
  65. [new AddFileOperation('a.tex', File.fromString(''))],
  66. new Date(),
  67. []
  68. )
  69. const secondChange = new Change(
  70. [new AddFileOperation('b.tex', File.fromString(''))],
  71. new Date(),
  72. []
  73. )
  74. const changes = [firstChange, secondChange]
  75. return chunkStore
  76. .initializeProject(projectId)
  77. .then(() => {
  78. return persistChanges(projectId, changes, limitsToPersistImmediately, 0)
  79. })
  80. .then(result => {
  81. const snapshot = Snapshot.fromRaw({
  82. files: {
  83. 'a.tex': {
  84. content: '',
  85. },
  86. },
  87. })
  88. const history = new History(snapshot, [secondChange])
  89. const currentChunk = new Chunk(history, 1)
  90. expect(result).to.deep.equal({
  91. numberOfChangesPersisted: 2,
  92. originalEndVersion: 0,
  93. currentChunk,
  94. })
  95. return chunkStore.loadLatest(projectId)
  96. })
  97. .then(chunk => {
  98. expect(chunk.getStartVersion()).to.equal(1)
  99. expect(chunk.getEndVersion()).to.equal(2)
  100. expect(chunk.getChanges().length).to.equal(1)
  101. })
  102. })
  103. it('persists the snapshot at the start of the chunk', function () {
  104. const limitsToPersistImmediately = {
  105. maxChunkChanges: 2,
  106. minChangeTimestamp: farFuture,
  107. maxChangeTimestamp: farFuture,
  108. }
  109. const projectId = fixtures.docs.uninitializedProject.id
  110. const firstChange = new Change(
  111. [new AddFileOperation('a.tex', File.fromString(''))],
  112. new Date(),
  113. []
  114. )
  115. const secondChange = new Change(
  116. [new AddFileOperation('b.tex', File.fromString(''))],
  117. new Date(),
  118. []
  119. )
  120. const changes = [firstChange, secondChange]
  121. return chunkStore
  122. .initializeProject(projectId)
  123. .then(() => {
  124. return persistChanges(projectId, changes, limitsToPersistImmediately, 0)
  125. })
  126. .then(result => {
  127. const history = new History(new Snapshot(), changes)
  128. const currentChunk = new Chunk(history, 0)
  129. expect(result).to.deep.equal({
  130. numberOfChangesPersisted: 2,
  131. originalEndVersion: 0,
  132. currentChunk,
  133. })
  134. return chunkStore.loadLatest(projectId)
  135. })
  136. .then(chunk => {
  137. expect(chunk.getStartVersion()).to.equal(0)
  138. expect(chunk.getEndVersion()).to.equal(2)
  139. expect(chunk.getChanges().length).to.equal(2)
  140. })
  141. })
  142. it("errors if the version doesn't match the latest chunk", function () {
  143. const limitsToPersistImmediately = {
  144. minChangeTimestamp: farFuture,
  145. maxChangeTimestamp: farFuture,
  146. }
  147. const projectId = fixtures.docs.uninitializedProject.id
  148. const firstChange = new Change(
  149. [new AddFileOperation('a.tex', File.fromString(''))],
  150. new Date(),
  151. []
  152. )
  153. const secondChange = new Change(
  154. [new AddFileOperation('b.tex', File.fromString(''))],
  155. new Date(),
  156. []
  157. )
  158. const changes = [firstChange, secondChange]
  159. return chunkStore
  160. .initializeProject(projectId)
  161. .then(() => {
  162. return persistChanges(projectId, changes, limitsToPersistImmediately, 1)
  163. })
  164. .then(() => {
  165. expect.fail()
  166. })
  167. .catch(err => {
  168. expect(err.message).to.equal(
  169. 'client sent updates with end_version 1 but latest chunk has end_version 0'
  170. )
  171. })
  172. })
  173. })