CompileManagerTests.coffee 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. sinon = require('sinon')
  2. chai = require('chai')
  3. should = chai.should()
  4. expect = chai.expect
  5. modulePath = "../../../../app/js/Features/Compile/CompileManager.js"
  6. assert = require("chai").assert
  7. SandboxedModule = require('sandboxed-module')
  8. describe "CompileManager", ->
  9. beforeEach ->
  10. @rateLimitGetStub = sinon.stub()
  11. rateLimitGetStub = @rateLimitGetStub
  12. @ratelimiter = class RateLimiter
  13. constructor: ->
  14. return {
  15. get: rateLimitGetStub
  16. }
  17. @CompileManager = SandboxedModule.require modulePath, requires:
  18. "settings-sharelatex": @settings =
  19. redis: web: {host: "localhost", port: 42}
  20. "redis":
  21. createClient: () => @rclient = { auth: () -> }
  22. "../DocumentUpdater/DocumentUpdaterHandler": @DocumentUpdaterHandler = {}
  23. "../Project/ProjectRootDocManager": @ProjectRootDocManager = {}
  24. "../../models/Project": Project: @Project = {}
  25. "./ClsiManager": @ClsiManager = {}
  26. "../../managers/LatexManager": @LatexManager = {}
  27. "ratelimiter":@ratelimiter
  28. "../../infrastructure/Metrics": @Metrics =
  29. Timer: class Timer
  30. done: sinon.stub()
  31. inc: sinon.stub()
  32. "logger-sharelatex": @logger = { log: sinon.stub() }
  33. @project_id = "mock-project-id-123"
  34. @user_id = "mock-user-id-123"
  35. @callback = sinon.stub()
  36. describe "compile", ->
  37. beforeEach ->
  38. @CompileManager._checkIfRecentlyCompiled = sinon.stub().callsArgWith(2, null, false)
  39. @CompileManager._ensureRootDocumentIsSet = sinon.stub().callsArgWith(1, null)
  40. @DocumentUpdaterHandler.flushProjectToMongo = sinon.stub().callsArgWith(1, null)
  41. @ClsiManager.sendRequest = sinon.stub().callsArgWith(1, null, @status = "mock-status")
  42. @LatexManager.compile = sinon.stub().callsArgWith(1, null, @status = "mock-status")
  43. describe "succesfully", ->
  44. beforeEach ->
  45. @CompileManager._checkIfAutoCompileLimitHasBeenHit = (_, cb)-> cb(null, true)
  46. @CompileManager.compile @project_id, @user_id, {}, @callback
  47. it "should check the project has not been recently compiled", ->
  48. @CompileManager._checkIfRecentlyCompiled
  49. .calledWith(@project_id, @user_id)
  50. .should.equal true
  51. it "should flush the project to the database", ->
  52. @DocumentUpdaterHandler.flushProjectToMongo
  53. .calledWith(@project_id)
  54. .should.equal true
  55. it "should ensure that the root document is set", ->
  56. @CompileManager._ensureRootDocumentIsSet
  57. .calledWith(@project_id)
  58. .should.equal true
  59. it "should run the compile with the new compiler API", ->
  60. @ClsiManager.sendRequest
  61. .calledWith(@project_id)
  62. .should.equal true
  63. it "should call the callback", ->
  64. @callback
  65. .calledWith(null, @status)
  66. .should.equal true
  67. it "should time the compile", ->
  68. @Metrics.Timer::done.called.should.equal true
  69. it "should log out the compile", ->
  70. @logger.log
  71. .calledWith(project_id: @project_id, user_id: @user_id, "compiling project")
  72. .should.equal true
  73. describe "when the project has been recently compiled", ->
  74. beforeEach ->
  75. @CompileManager._checkIfAutoCompileLimitHasBeenHit = (_, cb)-> cb(null, true)
  76. @CompileManager._checkIfRecentlyCompiled = sinon.stub().callsArgWith(2, null, true)
  77. @CompileManager.compile @project_id, @user_id, {}, @callback
  78. it "should return the callback with an error", ->
  79. @callback
  80. .calledWith(new Error("project was recently compiled so not continuing"))
  81. .should.equal true
  82. describe "should check the rate limit", ->
  83. it "should return", (done)->
  84. @CompileManager._checkIfAutoCompileLimitHasBeenHit = sinon.stub().callsArgWith(1, null, false)
  85. @CompileManager.compile @project_id, @user_id, {}, (err)->
  86. done()
  87. it "should not error if the autocompile limit has not been hit", (done)->
  88. @CompileManager._checkIfAutoCompileLimitHasBeenHit = sinon.stub().callsArgWith(1, null, true)
  89. @CompileManager.compile @project_id, @user_id, {}, (err)->
  90. assert.equal null, err
  91. done()
  92. describe "getLogLines", ->
  93. beforeEach ->
  94. @ClsiManager.getLogLines = sinon.stub().callsArgWith(1, null, @lines = ["log", "lines"])
  95. @CompileManager.getLogLines @project_id, @callback
  96. it "should call the new api", ->
  97. @ClsiManager.getLogLines
  98. .calledWith(@project_id)
  99. .should.equal true
  100. it "should call the callback with the lines", ->
  101. @callback
  102. .calledWith(null, @lines)
  103. .should.equal true
  104. it "should increase the log count metric", ->
  105. @Metrics.inc
  106. .calledWith("editor.raw-logs")
  107. .should.equal true
  108. describe "_checkIfRecentlyCompiled", ->
  109. describe "when the key exists in redis", ->
  110. beforeEach ->
  111. @rclient.set = sinon.stub().callsArgWith(5, null, null)
  112. @CompileManager._checkIfRecentlyCompiled(@project_id, @user_id, @callback)
  113. it "should try to set the key", ->
  114. @rclient.set
  115. .calledWith("compile:#{@project_id}:#{@user_id}", true, "EX", @CompileManager.COMPILE_DELAY, "NX")
  116. .should.equal true
  117. it "should call the callback with true", ->
  118. @callback.calledWith(null, true).should.equal true
  119. describe "when the key does not exist in redis", ->
  120. beforeEach ->
  121. @rclient.set = sinon.stub().callsArgWith(5, null, "OK")
  122. @CompileManager._checkIfRecentlyCompiled(@project_id, @user_id, @callback)
  123. it "should try to set the key", ->
  124. @rclient.set
  125. .calledWith("compile:#{@project_id}:#{@user_id}", true, "EX", @CompileManager.COMPILE_DELAY, "NX")
  126. .should.equal true
  127. it "should call the callback with false", ->
  128. @callback.calledWith(null, false).should.equal true
  129. describe "_ensureRootDocumentIsSet", ->
  130. beforeEach ->
  131. @project = {}
  132. @Project.findById = sinon.stub().callsArgWith(2, null, @project)
  133. @ProjectRootDocManager.setRootDocAutomatically = sinon.stub().callsArgWith(1, null)
  134. describe "when the root doc is set", ->
  135. beforeEach ->
  136. @project.rootDoc_id = "root-doc-id"
  137. @CompileManager._ensureRootDocumentIsSet(@project_id, @callback)
  138. it "should find the project with only the rootDoc_id fiel", ->
  139. @Project.findById
  140. .calledWith(@project_id, "rootDoc_id")
  141. .should.equal true
  142. it "should not try to update the project rootDoc_id", ->
  143. @ProjectRootDocManager.setRootDocAutomatically
  144. .called.should.equal false
  145. it "should call the callback", ->
  146. @callback.called.should.equal true
  147. describe "when the root doc is not set", ->
  148. beforeEach ->
  149. @CompileManager._ensureRootDocumentIsSet(@project_id, @callback)
  150. it "should find the project with only the rootDoc_id fiel", ->
  151. @Project.findById
  152. .calledWith(@project_id, "rootDoc_id")
  153. .should.equal true
  154. it "should update the project rootDoc_id", ->
  155. @ProjectRootDocManager.setRootDocAutomatically
  156. .calledWith(@project_id)
  157. .should.equal true
  158. it "should call the callback", ->
  159. @callback.called.should.equal true
  160. describe "when the project does not exist", ->
  161. beforeEach ->
  162. @Project.findById = sinon.stub().callsArgWith(2, null, null)
  163. @CompileManager._ensureRootDocumentIsSet(@project_id, @callback)
  164. it "should call the callback with an error", ->
  165. @callback.calledWith(new Error("project not found")).should.equal true
  166. describe "_checkIfAutoCompileLimitHasBeenHit", ->
  167. it "should be able to compile if it is not an autocompile", (done)->
  168. limit = {remaining:-1}
  169. @rateLimitGetStub.callsArgWith(0, null, limit)
  170. @CompileManager._checkIfAutoCompileLimitHasBeenHit false, (err, canCompile)=>
  171. canCompile.should.equal true
  172. done()
  173. it "should be able to compile if rate limit has remianing", (done)->
  174. limit = {remaining:3}
  175. @rateLimitGetStub.callsArgWith(0, null, limit)
  176. @CompileManager._checkIfAutoCompileLimitHasBeenHit true, (err, canCompile)=>
  177. canCompile.should.equal true
  178. done()
  179. it "should be not able to compile if rate limit has no remianing", (done)->
  180. limit = {remaining:0}
  181. @rateLimitGetStub.callsArgWith(0, null, limit)
  182. @CompileManager._checkIfAutoCompileLimitHasBeenHit true, (err, canCompile)=>
  183. canCompile.should.equal false
  184. done()
  185. it "should return false if there is an error in the rate limit", (done)->
  186. limit = {remaining:4}
  187. @rateLimitGetStub.callsArgWith(0, "Err", limit)
  188. @CompileManager._checkIfAutoCompileLimitHasBeenHit true, (err, canCompile)=>
  189. canCompile.should.equal false
  190. done()