AppendingUpdatesTests.coffee 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311
  1. sinon = require "sinon"
  2. chai = require("chai")
  3. chai.should()
  4. expect = chai.expect
  5. mongojs = require "../../../app/js/mongojs"
  6. ObjectId = mongojs.ObjectId
  7. Settings = require "settings-sharelatex"
  8. request = require "request"
  9. rclient = require("redis").createClient(Settings.redis.history) # Only works locally for now
  10. TrackChangesApp = require "./helpers/TrackChangesApp"
  11. TrackChangesClient = require "./helpers/TrackChangesClient"
  12. MockWebApi = require "./helpers/MockWebApi"
  13. describe "Appending doc ops to the history", ->
  14. before (done)->
  15. TrackChangesApp.ensureRunning done
  16. describe "when the history does not exist yet", ->
  17. before (done) ->
  18. @project_id = ObjectId().toString()
  19. @doc_id = ObjectId().toString()
  20. @user_id = ObjectId().toString()
  21. MockWebApi.projects[@project_id] = features: versioning: false
  22. TrackChangesClient.pushRawUpdates @project_id, @doc_id, [{
  23. op: [{ i: "f", p: 3 }]
  24. meta: { ts: Date.now(), user_id: @user_id }
  25. v: 3
  26. }, {
  27. op: [{ i: "o", p: 4 }]
  28. meta: { ts: Date.now(), user_id: @user_id }
  29. v: 4
  30. }, {
  31. op: [{ i: "o", p: 5 }]
  32. meta: { ts: Date.now(), user_id: @user_id }
  33. v: 5
  34. }], (error) =>
  35. throw error if error?
  36. TrackChangesClient.flushAndGetCompressedUpdates @project_id, @doc_id, (error, @updates) =>
  37. throw error if error?
  38. done()
  39. return null
  40. it "should insert the compressed op into mongo", ->
  41. expect(@updates[0].pack[0].op).to.deep.equal [{
  42. p: 3, i: "foo"
  43. }]
  44. it "should insert the correct version number into mongo", ->
  45. expect(@updates[0].v).to.equal 5
  46. it "should store the doc id", ->
  47. expect(@updates[0].doc_id.toString()).to.equal @doc_id
  48. it "should store the project id", ->
  49. expect(@updates[0].project_id.toString()).to.equal @project_id
  50. it "should clear the doc from the DocsWithHistoryOps set", (done) ->
  51. rclient.sismember "DocsWithHistoryOps:#{@project_id}", @doc_id, (error, member) ->
  52. member.should.equal 0
  53. done()
  54. return null
  55. describe "when the history has already been started", ->
  56. beforeEach (done) ->
  57. @project_id = ObjectId().toString()
  58. @doc_id = ObjectId().toString()
  59. @user_id = ObjectId().toString()
  60. MockWebApi.projects[@project_id] = features: versioning: false
  61. TrackChangesClient.pushRawUpdates @project_id, @doc_id, [{
  62. op: [{ i: "f", p: 3 }]
  63. meta: { ts: Date.now(), user_id: @user_id }
  64. v: 3
  65. }, {
  66. op: [{ i: "o", p: 4 }]
  67. meta: { ts: Date.now(), user_id: @user_id }
  68. v: 4
  69. }, {
  70. op: [{ i: "o", p: 5 }]
  71. meta: { ts: Date.now(), user_id: @user_id }
  72. v: 5
  73. }], (error) =>
  74. throw error if error?
  75. TrackChangesClient.flushAndGetCompressedUpdates @project_id, @doc_id, (error, updates) =>
  76. throw error if error?
  77. done()
  78. return null
  79. describe "when the updates are recent and from the same user", ->
  80. beforeEach (done) ->
  81. TrackChangesClient.pushRawUpdates @project_id, @doc_id, [{
  82. op: [{ i: "b", p: 6 }]
  83. meta: { ts: Date.now(), user_id: @user_id }
  84. v: 6
  85. }, {
  86. op: [{ i: "a", p: 7 }]
  87. meta: { ts: Date.now(), user_id: @user_id }
  88. v: 7
  89. }, {
  90. op: [{ i: "r", p: 8 }]
  91. meta: { ts: Date.now(), user_id: @user_id }
  92. v: 8
  93. }], (error) =>
  94. throw error if error?
  95. TrackChangesClient.flushAndGetCompressedUpdates @project_id, @doc_id, (error, @updates) =>
  96. throw error if error?
  97. done()
  98. return null
  99. it "should combine all the updates into one pack", ->
  100. expect(@updates[0].pack[1].op).to.deep.equal [{
  101. p: 6, i: "bar"
  102. }]
  103. it "should insert the correct version number into mongo", ->
  104. expect(@updates[0].v_end).to.equal 8
  105. describe "when the updates are far apart", ->
  106. beforeEach (done) ->
  107. oneDay = 24 * 60 * 60 * 1000
  108. TrackChangesClient.pushRawUpdates @project_id, @doc_id, [{
  109. op: [{ i: "b", p: 6 }]
  110. meta: { ts: Date.now() + oneDay, user_id: @user_id }
  111. v: 6
  112. }, {
  113. op: [{ i: "a", p: 7 }]
  114. meta: { ts: Date.now() + oneDay, user_id: @user_id }
  115. v: 7
  116. }, {
  117. op: [{ i: "r", p: 8 }]
  118. meta: { ts: Date.now() + oneDay, user_id: @user_id }
  119. v: 8
  120. }], (error) =>
  121. throw error if error?
  122. TrackChangesClient.flushAndGetCompressedUpdates @project_id, @doc_id, (error, @updates) =>
  123. throw error if error?
  124. done()
  125. return null
  126. it "should combine the updates into one pack", ->
  127. expect(@updates[0].pack[0].op).to.deep.equal [{
  128. p: 3, i: "foo"
  129. }]
  130. expect(@updates[0].pack[1].op).to.deep.equal [{
  131. p: 6, i: "bar"
  132. }]
  133. describe "when the updates need processing in batches", ->
  134. before (done) ->
  135. @project_id = ObjectId().toString()
  136. @doc_id = ObjectId().toString()
  137. @user_id = ObjectId().toString()
  138. MockWebApi.projects[@project_id] = features: versioning: false
  139. updates = []
  140. @expectedOp = [{ p:0, i: "" }]
  141. for i in [0..250]
  142. updates.push {
  143. op: [{i: "a", p: 0}]
  144. meta: { ts: Date.now(), user_id: @user_id }
  145. v: i
  146. }
  147. @expectedOp[0].i = "a" + @expectedOp[0].i
  148. TrackChangesClient.pushRawUpdates @project_id, @doc_id, updates, (error) =>
  149. throw error if error?
  150. TrackChangesClient.flushAndGetCompressedUpdates @project_id, @doc_id, (error, @updates) =>
  151. throw error if error?
  152. done()
  153. return null
  154. it "should concat the compressed op into mongo", ->
  155. expect(@updates[0].pack.length).to.deep.equal 3 # batch size is 100
  156. it "should insert the correct version number into mongo", ->
  157. expect(@updates[0].v_end).to.equal 250
  158. describe "when there are multiple ops in each update", ->
  159. before (done) ->
  160. @project_id = ObjectId().toString()
  161. @doc_id = ObjectId().toString()
  162. @user_id = ObjectId().toString()
  163. MockWebApi.projects[@project_id] = features: versioning: false
  164. oneDay = 24 * 60 * 60 * 1000
  165. TrackChangesClient.pushRawUpdates @project_id, @doc_id, [{
  166. op: [{ i: "f", p: 3 }, { i: "o", p: 4 }, { i: "o", p: 5 }]
  167. meta: { ts: Date.now(), user_id: @user_id }
  168. v: 3
  169. }, {
  170. op: [{ i: "b", p: 6 }, { i: "a", p: 7 }, { i: "r", p: 8 }]
  171. meta: { ts: Date.now() + oneDay, user_id: @user_id }
  172. v: 4
  173. }], (error) =>
  174. throw error if error?
  175. TrackChangesClient.flushAndGetCompressedUpdates @project_id, @doc_id, (error, @updates) =>
  176. throw error if error?
  177. done()
  178. return null
  179. it "should insert the compressed ops into mongo", ->
  180. expect(@updates[0].pack[0].op).to.deep.equal [{
  181. p: 3, i: "foo"
  182. }]
  183. expect(@updates[0].pack[1].op).to.deep.equal [{
  184. p: 6, i: "bar"
  185. }]
  186. it "should insert the correct version numbers into mongo", ->
  187. expect(@updates[0].pack[0].v).to.equal 3
  188. expect(@updates[0].pack[1].v).to.equal 4
  189. describe "when there is a no-op update", ->
  190. before (done) ->
  191. @project_id = ObjectId().toString()
  192. @doc_id = ObjectId().toString()
  193. @user_id = ObjectId().toString()
  194. MockWebApi.projects[@project_id] = features: versioning: false
  195. oneDay = 24 * 60 * 60 * 1000
  196. TrackChangesClient.pushRawUpdates @project_id, @doc_id, [{
  197. op: []
  198. meta: { ts: Date.now(), user_id: @user_id }
  199. v: 3
  200. }, {
  201. op: [{ i: "foo", p: 3 }]
  202. meta: { ts: Date.now() + oneDay, user_id: @user_id }
  203. v: 4
  204. }], (error) =>
  205. throw error if error?
  206. TrackChangesClient.flushAndGetCompressedUpdates @project_id, @doc_id, (error, @updates) =>
  207. throw error if error?
  208. done()
  209. return null
  210. it "should insert the compressed no-op into mongo", ->
  211. expect(@updates[0].pack[0].op).to.deep.equal []
  212. it "should insert the compressed next update into mongo", ->
  213. expect(@updates[0].pack[1].op).to.deep.equal [{
  214. p: 3, i: "foo"
  215. }]
  216. it "should insert the correct version numbers into mongo", ->
  217. expect(@updates[0].pack[0].v).to.equal 3
  218. expect(@updates[0].pack[1].v).to.equal 4
  219. describe "when there is a comment update", ->
  220. before (done) ->
  221. @project_id = ObjectId().toString()
  222. @doc_id = ObjectId().toString()
  223. @user_id = ObjectId().toString()
  224. MockWebApi.projects[@project_id] = features: versioning: false
  225. TrackChangesClient.pushRawUpdates @project_id, @doc_id, [{
  226. op: [{ c: "foo", p: 3 }, {d: "bar", p: 6}]
  227. meta: { ts: Date.now(), user_id: @user_id }
  228. v: 3
  229. }], (error) =>
  230. throw error if error?
  231. TrackChangesClient.flushAndGetCompressedUpdates @project_id, @doc_id, (error, @updates) =>
  232. throw error if error?
  233. done()
  234. return null
  235. it "should ignore the comment op", ->
  236. expect(@updates[0].pack[0].op).to.deep.equal [{d: "bar", p: 6}]
  237. it "should insert the correct version numbers into mongo", ->
  238. expect(@updates[0].pack[0].v).to.equal 3
  239. describe "when the project has versioning enabled", ->
  240. before (done) ->
  241. @project_id = ObjectId().toString()
  242. @doc_id = ObjectId().toString()
  243. @user_id = ObjectId().toString()
  244. MockWebApi.projects[@project_id] = features: versioning: true
  245. TrackChangesClient.pushRawUpdates @project_id, @doc_id, [{
  246. op: [{ i: "f", p: 3 }]
  247. meta: { ts: Date.now(), user_id: @user_id }
  248. v: 3
  249. }], (error) =>
  250. throw error if error?
  251. TrackChangesClient.flushAndGetCompressedUpdates @project_id, @doc_id, (error, @updates) =>
  252. throw error if error?
  253. done()
  254. return null
  255. it "should not add a expiresAt entry in the update in mongo", ->
  256. expect(@updates[0].expiresAt).to.be.undefined
  257. describe "when the project does not have versioning enabled", ->
  258. before (done) ->
  259. @project_id = ObjectId().toString()
  260. @doc_id = ObjectId().toString()
  261. @user_id = ObjectId().toString()
  262. MockWebApi.projects[@project_id] = features: versioning: false
  263. TrackChangesClient.pushRawUpdates @project_id, @doc_id, [{
  264. op: [{ i: "f", p: 3 }]
  265. meta: { ts: Date.now(), user_id: @user_id }
  266. v: 3
  267. }], (error) =>
  268. throw error if error?
  269. TrackChangesClient.flushAndGetCompressedUpdates @project_id, @doc_id, (error, @updates) =>
  270. throw error if error?
  271. done()
  272. return null
  273. it "should add a expiresAt entry in the update in mongo", ->
  274. expect(@updates[0].expiresAt).to.exist