HttpControllerTests.coffee 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376
  1. sinon = require('sinon')
  2. chai = require('chai')
  3. should = chai.should()
  4. modulePath = "../../../../app/js/HttpController.js"
  5. SandboxedModule = require('sandboxed-module')
  6. Errors = require "../../../../app/js/Errors.js"
  7. describe "HttpController", ->
  8. beforeEach ->
  9. @HttpController = SandboxedModule.require modulePath, requires:
  10. "./DocumentManager": @DocumentManager = {}
  11. "./ProjectManager": @ProjectManager = {}
  12. "logger-sharelatex" : @logger = { log: sinon.stub() }
  13. "./Metrics": @Metrics = {}
  14. @Metrics.Timer = class Timer
  15. done: sinon.stub()
  16. @project_id = "project-id-123"
  17. @doc_id = "doc-id-123"
  18. @next = sinon.stub()
  19. @res =
  20. send: sinon.stub()
  21. describe "getDoc", ->
  22. beforeEach ->
  23. @lines = ["one", "two", "three"]
  24. @ops = ["mock-op-1", "mock-op-2"]
  25. @version = 42
  26. @fromVersion = 42
  27. @ranges = { changes: "mock", comments: "mock" }
  28. @req =
  29. params:
  30. project_id: @project_id
  31. doc_id: @doc_id
  32. describe "when the document exists and no recent ops are requested", ->
  33. beforeEach ->
  34. @DocumentManager.getDocAndRecentOpsWithLock = sinon.stub().callsArgWith(3, null, @lines, @version, [], @ranges)
  35. @HttpController.getDoc(@req, @res, @next)
  36. it "should get the doc", ->
  37. @DocumentManager.getDocAndRecentOpsWithLock
  38. .calledWith(@project_id, @doc_id, -1)
  39. .should.equal true
  40. it "should return the doc as JSON", ->
  41. @res.send
  42. .calledWith(JSON.stringify({
  43. id: @doc_id
  44. lines: @lines
  45. version: @version
  46. ops: []
  47. ranges: @ranges
  48. }))
  49. .should.equal true
  50. it "should log the request", ->
  51. @logger.log
  52. .calledWith(doc_id: @doc_id, project_id: @project_id, "getting doc via http")
  53. .should.equal true
  54. it "should time the request", ->
  55. @Metrics.Timer::done.called.should.equal true
  56. describe "when recent ops are requested", ->
  57. beforeEach ->
  58. @DocumentManager.getDocAndRecentOpsWithLock = sinon.stub().callsArgWith(3, null, @lines, @version, @ops)
  59. @req.query = fromVersion: "#{@fromVersion}"
  60. @HttpController.getDoc(@req, @res, @next)
  61. it "should get the doc", ->
  62. @DocumentManager.getDocAndRecentOpsWithLock
  63. .calledWith(@project_id, @doc_id, @fromVersion)
  64. .should.equal true
  65. it "should return the doc as JSON", ->
  66. @res.send
  67. .calledWith(JSON.stringify({
  68. id: @doc_id
  69. lines: @lines
  70. version: @version
  71. ops: @ops
  72. }))
  73. .should.equal true
  74. it "should log the request", ->
  75. @logger.log
  76. .calledWith(doc_id: @doc_id, project_id: @project_id, "getting doc via http")
  77. .should.equal true
  78. it "should time the request", ->
  79. @Metrics.Timer::done.called.should.equal true
  80. describe "when the document does not exist", ->
  81. beforeEach ->
  82. @DocumentManager.getDocAndRecentOpsWithLock = sinon.stub().callsArgWith(3, null, null, null)
  83. @HttpController.getDoc(@req, @res, @next)
  84. it "should call next with NotFoundError", ->
  85. @next
  86. .calledWith(new Errors.NotFoundError("not found"))
  87. .should.equal true
  88. describe "when an errors occurs", ->
  89. beforeEach ->
  90. @DocumentManager.getDocAndRecentOpsWithLock = sinon.stub().callsArgWith(3, new Error("oops"), null, null)
  91. @HttpController.getDoc(@req, @res, @next)
  92. it "should call next with the error", ->
  93. @next
  94. .calledWith(new Error("oops"))
  95. .should.equal true
  96. describe "setDoc", ->
  97. beforeEach ->
  98. @lines = ["one", "two", "three"]
  99. @source = "dropbox"
  100. @user_id = "user-id-123"
  101. @req =
  102. headers: {}
  103. params:
  104. project_id: @project_id
  105. doc_id: @doc_id
  106. body:
  107. lines: @lines
  108. source: @source
  109. user_id: @user_id
  110. describe "successfully", ->
  111. beforeEach ->
  112. @DocumentManager.setDocWithLock = sinon.stub().callsArgWith(5)
  113. @HttpController.setDoc(@req, @res, @next)
  114. it "should set the doc", ->
  115. @DocumentManager.setDocWithLock
  116. .calledWith(@project_id, @doc_id, @lines, @source, @user_id)
  117. .should.equal true
  118. it "should return a successful No Content response", ->
  119. @res.send
  120. .calledWith(204)
  121. .should.equal true
  122. it "should log the request", ->
  123. @logger.log
  124. .calledWith(doc_id: @doc_id, project_id: @project_id, lines: @lines, source: @source, user_id: @user_id, "setting doc via http")
  125. .should.equal true
  126. it "should time the request", ->
  127. @Metrics.Timer::done.called.should.equal true
  128. describe "when an errors occurs", ->
  129. beforeEach ->
  130. @DocumentManager.setDocWithLock = sinon.stub().callsArgWith(5, new Error("oops"))
  131. @HttpController.setDoc(@req, @res, @next)
  132. it "should call next with the error", ->
  133. @next
  134. .calledWith(new Error("oops"))
  135. .should.equal true
  136. describe "when the payload is too large", ->
  137. beforeEach ->
  138. lines = []
  139. for _ in [0..200000]
  140. lines.push "test test test"
  141. @req.body.lines = lines
  142. @DocumentManager.setDocWithLock = sinon.stub().callsArgWith(5)
  143. @HttpController.setDoc(@req, @res, @next)
  144. it 'should send back a 406 response', ->
  145. @res.send.calledWith(406).should.equal true
  146. it 'should not call setDocWithLock', ->
  147. @DocumentManager.setDocWithLock.callCount.should.equal 0
  148. describe "flushProject", ->
  149. beforeEach ->
  150. @req =
  151. params:
  152. project_id: @project_id
  153. describe "successfully", ->
  154. beforeEach ->
  155. @ProjectManager.flushProjectWithLocks = sinon.stub().callsArgWith(1)
  156. @HttpController.flushProject(@req, @res, @next)
  157. it "should flush the project", ->
  158. @ProjectManager.flushProjectWithLocks
  159. .calledWith(@project_id)
  160. .should.equal true
  161. it "should return a successful No Content response", ->
  162. @res.send
  163. .calledWith(204)
  164. .should.equal true
  165. it "should log the request", ->
  166. @logger.log
  167. .calledWith(project_id: @project_id, "flushing project via http")
  168. .should.equal true
  169. it "should time the request", ->
  170. @Metrics.Timer::done.called.should.equal true
  171. describe "when an errors occurs", ->
  172. beforeEach ->
  173. @ProjectManager.flushProjectWithLocks = sinon.stub().callsArgWith(1, new Error("oops"))
  174. @HttpController.flushProject(@req, @res, @next)
  175. it "should call next with the error", ->
  176. @next
  177. .calledWith(new Error("oops"))
  178. .should.equal true
  179. describe "flushDocIfLoaded", ->
  180. beforeEach ->
  181. @lines = ["one", "two", "three"]
  182. @version = 42
  183. @req =
  184. params:
  185. project_id: @project_id
  186. doc_id: @doc_id
  187. describe "successfully", ->
  188. beforeEach ->
  189. @DocumentManager.flushDocIfLoadedWithLock = sinon.stub().callsArgWith(2)
  190. @HttpController.flushDocIfLoaded(@req, @res, @next)
  191. it "should flush the doc", ->
  192. @DocumentManager.flushDocIfLoadedWithLock
  193. .calledWith(@project_id, @doc_id)
  194. .should.equal true
  195. it "should return a successful No Content response", ->
  196. @res.send
  197. .calledWith(204)
  198. .should.equal true
  199. it "should log the request", ->
  200. @logger.log
  201. .calledWith(doc_id: @doc_id, project_id: @project_id, "flushing doc via http")
  202. .should.equal true
  203. it "should time the request", ->
  204. @Metrics.Timer::done.called.should.equal true
  205. describe "when an errors occurs", ->
  206. beforeEach ->
  207. @DocumentManager.flushDocIfLoadedWithLock = sinon.stub().callsArgWith(2, new Error("oops"))
  208. @HttpController.flushDocIfLoaded(@req, @res, @next)
  209. it "should call next with the error", ->
  210. @next
  211. .calledWith(new Error("oops"))
  212. .should.equal true
  213. describe "flushAndDeleteDoc", ->
  214. beforeEach ->
  215. @req =
  216. params:
  217. project_id: @project_id
  218. doc_id: @doc_id
  219. describe "successfully", ->
  220. beforeEach ->
  221. @DocumentManager.flushAndDeleteDocWithLock = sinon.stub().callsArgWith(2)
  222. @HttpController.flushAndDeleteDoc(@req, @res, @next)
  223. it "should flush and delete the doc", ->
  224. @DocumentManager.flushAndDeleteDocWithLock
  225. .calledWith(@project_id, @doc_id)
  226. .should.equal true
  227. it "should return a successful No Content response", ->
  228. @res.send
  229. .calledWith(204)
  230. .should.equal true
  231. it "should log the request", ->
  232. @logger.log
  233. .calledWith(doc_id: @doc_id, project_id: @project_id, "deleting doc via http")
  234. .should.equal true
  235. it "should time the request", ->
  236. @Metrics.Timer::done.called.should.equal true
  237. describe "when an errors occurs", ->
  238. beforeEach ->
  239. @DocumentManager.flushAndDeleteDocWithLock = sinon.stub().callsArgWith(2, new Error("oops"))
  240. @HttpController.flushAndDeleteDoc(@req, @res, @next)
  241. it "should call next with the error", ->
  242. @next
  243. .calledWith(new Error("oops"))
  244. .should.equal true
  245. describe "deleteProject", ->
  246. beforeEach ->
  247. @req =
  248. params:
  249. project_id: @project_id
  250. describe "successfully", ->
  251. beforeEach ->
  252. @ProjectManager.flushAndDeleteProjectWithLocks = sinon.stub().callsArgWith(1)
  253. @HttpController.deleteProject(@req, @res, @next)
  254. it "should delete the project", ->
  255. @ProjectManager.flushAndDeleteProjectWithLocks
  256. .calledWith(@project_id)
  257. .should.equal true
  258. it "should return a successful No Content response", ->
  259. @res.send
  260. .calledWith(204)
  261. .should.equal true
  262. it "should log the request", ->
  263. @logger.log
  264. .calledWith(project_id: @project_id, "deleting project via http")
  265. .should.equal true
  266. it "should time the request", ->
  267. @Metrics.Timer::done.called.should.equal true
  268. describe "when an errors occurs", ->
  269. beforeEach ->
  270. @ProjectManager.flushAndDeleteProjectWithLocks = sinon.stub().callsArgWith(1, new Error("oops"))
  271. @HttpController.deleteProject(@req, @res, @next)
  272. it "should call next with the error", ->
  273. @next
  274. .calledWith(new Error("oops"))
  275. .should.equal true
  276. describe "acceptChange", ->
  277. beforeEach ->
  278. @req =
  279. params:
  280. project_id: @project_id
  281. doc_id: @doc_id
  282. change_id: @change_id = "mock-change-od-1"
  283. describe "successfully", ->
  284. beforeEach ->
  285. @DocumentManager.acceptChangeWithLock = sinon.stub().callsArgWith(3)
  286. @HttpController.acceptChange(@req, @res, @next)
  287. it "should accept the change", ->
  288. @DocumentManager.acceptChangeWithLock
  289. .calledWith(@project_id, @doc_id, @change_id)
  290. .should.equal true
  291. it "should return a successful No Content response", ->
  292. @res.send
  293. .calledWith(204)
  294. .should.equal true
  295. it "should log the request", ->
  296. @logger.log
  297. .calledWith({@project_id, @doc_id, @change_id}, "accepting change via http")
  298. .should.equal true
  299. it "should time the request", ->
  300. @Metrics.Timer::done.called.should.equal true
  301. describe "when an errors occurs", ->
  302. beforeEach ->
  303. @DocumentManager.acceptChangeWithLock = sinon.stub().callsArgWith(3, new Error("oops"))
  304. @HttpController.acceptChange(@req, @res, @next)
  305. it "should call next with the error", ->
  306. @next
  307. .calledWith(new Error("oops"))
  308. .should.equal true