ApplyingUpdatesToProjectStructureTests.coffee 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. sinon = require "sinon"
  2. chai = require("chai")
  3. chai.should()
  4. Settings = require('settings-sharelatex')
  5. rclient_history = require("redis-sharelatex").createClient(Settings.redis.history)
  6. ProjectHistoryKeys = Settings.redis.project_history.key_schema
  7. SandboxedModule = require('sandboxed-module')
  8. HistoryManagerModulePath = require('path').join __dirname, '../../../app/js/HistoryManager.js'
  9. ProjectManagerModulePath = require('path').join __dirname, '../../../app/js/ProjectManager.js'
  10. RedisManagerModulePath = require('path').join __dirname, '../../../app/js/RedisManager.js'
  11. MockWebApi = require "./helpers/MockWebApi"
  12. DocUpdaterClient = require "./helpers/DocUpdaterClient"
  13. describe "Applying updates to a project's structure", ->
  14. before ->
  15. @user_id = 'user-id-123'
  16. describe "renaming a file", ->
  17. before (done) ->
  18. @project_id = DocUpdaterClient.randomId()
  19. @fileUpdate =
  20. id: DocUpdaterClient.randomId()
  21. pathname: '/file-path'
  22. newPathname: '/new-file-path'
  23. @fileUpdates = [ @fileUpdate ]
  24. DocUpdaterClient.sendProjectUpdate @project_id, @user_id, [], @fileUpdates, (error) ->
  25. throw error if error?
  26. setTimeout done, 200
  27. it "should push the applied file renames to the project history api", (done) ->
  28. rclient_history.lrange ProjectHistoryKeys.projectHistoryOps({@project_id}), 0, -1, (error, updates) =>
  29. throw error if error?
  30. update = JSON.parse(updates[0])
  31. update.file.should.equal @fileUpdate.id
  32. update.pathname.should.equal '/file-path'
  33. update.new_pathname.should.equal '/new-file-path'
  34. update.meta.user_id.should.equal @user_id
  35. update.meta.ts.should.be.a('string')
  36. done()
  37. describe "renaming a document", ->
  38. before ->
  39. @docUpdate =
  40. id: DocUpdaterClient.randomId()
  41. pathname: '/doc-path'
  42. newPathname: '/new-doc-path'
  43. @docUpdates = [ @docUpdate ]
  44. describe "when the document is not loaded", ->
  45. before (done) ->
  46. @project_id = DocUpdaterClient.randomId()
  47. DocUpdaterClient.sendProjectUpdate @project_id, @user_id, @docUpdates, [], (error) ->
  48. throw error if error?
  49. setTimeout done, 200
  50. it "should push the applied doc renames to the project history api", (done) ->
  51. rclient_history.lrange ProjectHistoryKeys.projectHistoryOps({@project_id}), 0, -1, (error, updates) =>
  52. throw error if error?
  53. update = JSON.parse(updates[0])
  54. update.doc.should.equal @docUpdate.id
  55. update.pathname.should.equal '/doc-path'
  56. update.new_pathname.should.equal '/new-doc-path'
  57. update.meta.user_id.should.equal @user_id
  58. update.meta.ts.should.be.a('string')
  59. done()
  60. describe "when the document is loaded", ->
  61. before (done) ->
  62. @project_id = DocUpdaterClient.randomId()
  63. MockWebApi.insertDoc @project_id, @docUpdate.id, {}
  64. DocUpdaterClient.preloadDoc @project_id, @docUpdate.id, (error) =>
  65. throw error if error?
  66. sinon.spy MockWebApi, "getDocument"
  67. DocUpdaterClient.sendProjectUpdate @project_id, @user_id, @docUpdates, [], (error) ->
  68. throw error if error?
  69. setTimeout done, 200
  70. after ->
  71. MockWebApi.getDocument.restore()
  72. it "should update the doc", (done) ->
  73. DocUpdaterClient.getDoc @project_id, @docUpdate.id, (error, res, doc) =>
  74. doc.pathname.should.equal @docUpdate.newPathname
  75. done()
  76. it "should push the applied doc renames to the project history api", (done) ->
  77. rclient_history.lrange ProjectHistoryKeys.projectHistoryOps({@project_id}), 0, -1, (error, updates) =>
  78. throw error if error?
  79. update = JSON.parse(updates[0])
  80. update.doc.should.equal @docUpdate.id
  81. update.pathname.should.equal '/doc-path'
  82. update.new_pathname.should.equal '/new-doc-path'
  83. update.meta.user_id.should.equal @user_id
  84. update.meta.ts.should.be.a('string')
  85. done()
  86. describe "adding a file", ->
  87. before (done) ->
  88. @project_id = DocUpdaterClient.randomId()
  89. @fileUpdate =
  90. id: DocUpdaterClient.randomId()
  91. pathname: '/file-path'
  92. url: 'filestore.example.com'
  93. @fileUpdates = [ @fileUpdate ]
  94. DocUpdaterClient.sendProjectUpdate @project_id, @user_id, [], @fileUpdates, (error) ->
  95. throw error if error?
  96. setTimeout done, 200
  97. it "should push the file addition to the project history api", (done) ->
  98. rclient_history.lrange ProjectHistoryKeys.projectHistoryOps({@project_id}), 0, -1, (error, updates) =>
  99. throw error if error?
  100. update = JSON.parse(updates[0])
  101. update.file.should.equal @fileUpdate.id
  102. update.pathname.should.equal '/file-path'
  103. update.url.should.equal 'filestore.example.com'
  104. update.meta.user_id.should.equal @user_id
  105. update.meta.ts.should.be.a('string')
  106. done()
  107. describe "adding a doc", ->
  108. before (done) ->
  109. @project_id = DocUpdaterClient.randomId()
  110. @docUpdate =
  111. id: DocUpdaterClient.randomId()
  112. pathname: '/file-path'
  113. docLines: 'a\nb'
  114. @docUpdates = [ @docUpdate ]
  115. DocUpdaterClient.sendProjectUpdate @project_id, @user_id, @docUpdates, [], (error) ->
  116. throw error if error?
  117. setTimeout done, 200
  118. it "should push the doc addition to the project history api", (done) ->
  119. rclient_history.lrange ProjectHistoryKeys.projectHistoryOps({@project_id}), 0, -1, (error, updates) =>
  120. throw error if error?
  121. update = JSON.parse(updates[0])
  122. update.doc.should.equal @docUpdate.id
  123. update.pathname.should.equal '/file-path'
  124. update.docLines.should.equal 'a\nb'
  125. update.meta.user_id.should.equal @user_id
  126. update.meta.ts.should.be.a('string')
  127. done()
  128. describe "with enough updates to flush to the history service", ->
  129. before (done) ->
  130. @RedisManager = SandboxedModule.require RedisManagerModulePath, requires:
  131. "logger-sharelatex": @logger = { log: sinon.stub(), error: sinon.stub() }
  132. @HistoryManager = SandboxedModule.require HistoryManagerModulePath, requires:
  133. "request": {}
  134. "settings-sharelatex": {}
  135. "logger-sharelatex": @logger
  136. "./HistoryRedisManager": {}
  137. @HistoryManager.flushProjectChangesAsync = sinon.stub()
  138. @ProjectManager = SandboxedModule.require ProjectManagerModulePath, requires:
  139. './HistoryManager': @HistoryManager
  140. 'logger-sharelatex' : @logger
  141. './Metrics': @Metrics = {}
  142. './RedisManager': @RedisManager
  143. @Metrics.Timer = class Timer
  144. done: sinon.stub()
  145. @project_id = DocUpdaterClient.randomId()
  146. @user_id = DocUpdaterClient.randomId()
  147. updates = []
  148. for v in [0..599] # Should flush after 500 ops
  149. updates.push
  150. id: DocUpdaterClient.randomId(),
  151. pathname: '/file-' + v
  152. docLines: 'a\nb'
  153. # Send updates in chunks to causes multiple flushes
  154. @ProjectManager.updateProjectWithLocks @project_id, @user_id, updates.slice(0, 250), [], (error) =>
  155. throw error if error?
  156. @ProjectManager.updateProjectWithLocks @project_id, @user_id, updates.slice(250), [], (error) =>
  157. throw error if error?
  158. setTimeout done, 2000
  159. it "should flush project history", ->
  160. @HistoryManager.flushProjectChangesAsync.calledWith(@project_id).should.equal true