HistoryControllerTests.js 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290
  1. /* eslint-disable
  2. max-len,
  3. no-return-assign,
  4. */
  5. // TODO: This file was created by bulk-decaffeinate.
  6. // Fix any style issues and re-enable lint.
  7. /*
  8. * decaffeinate suggestions:
  9. * DS102: Remove unnecessary code created because of implicit returns
  10. * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
  11. */
  12. const sinon = require('sinon')
  13. const { expect } = require('chai')
  14. const Errors = require('../../../../app/src/Features/Errors/Errors')
  15. const modulePath = '../../../../app/src/Features/History/HistoryController'
  16. const SandboxedModule = require('sandboxed-module')
  17. describe('HistoryController', function () {
  18. beforeEach(function () {
  19. this.callback = sinon.stub()
  20. this.user_id = 'user-id-123'
  21. this.SessionManager = {
  22. getLoggedInUserId: sinon.stub().returns(this.user_id),
  23. }
  24. this.Stream = {
  25. pipeline: sinon.stub(),
  26. }
  27. this.HistoryController = SandboxedModule.require(modulePath, {
  28. requires: {
  29. request: (this.request = sinon.stub()),
  30. '@overleaf/settings': (this.settings = {}),
  31. stream: this.Stream,
  32. '../Authentication/SessionManager': this.SessionManager,
  33. './HistoryManager': (this.HistoryManager = {}),
  34. '../Project/ProjectDetailsHandler': (this.ProjectDetailsHandler = {}),
  35. '../Project/ProjectEntityUpdateHandler':
  36. (this.ProjectEntityUpdateHandler = {}),
  37. '../User/UserGetter': (this.UserGetter = {}),
  38. '../Project/ProjectGetter': (this.ProjectGetter = {}),
  39. './RestoreManager': (this.RestoreManager = {}),
  40. '../../infrastructure/Features': (this.Features = sinon
  41. .stub()
  42. .withArgs('saas')
  43. .returns(true)),
  44. },
  45. })
  46. return (this.settings.apis = {
  47. project_history: {
  48. url: 'http://project_history.example.com',
  49. },
  50. })
  51. })
  52. describe('proxyToHistoryApi', function () {
  53. beforeEach(function () {
  54. this.req = { url: '/mock/url', method: 'POST' }
  55. this.res = 'mock-res'
  56. this.next = sinon.stub()
  57. this.proxy = sinon.stub()
  58. this.request.returns(this.proxy)
  59. })
  60. describe('for a project with the project history flag', function () {
  61. beforeEach(function () {
  62. this.req.useProjectHistory = true
  63. return this.HistoryController.proxyToHistoryApi(
  64. this.req,
  65. this.res,
  66. this.next
  67. )
  68. })
  69. it('should get the user id', function () {
  70. return this.SessionManager.getLoggedInUserId
  71. .calledWith(this.req.session)
  72. .should.equal(true)
  73. })
  74. it('should call the project history api', function () {
  75. return this.request
  76. .calledWith({
  77. url: `${this.settings.apis.project_history.url}${this.req.url}`,
  78. method: this.req.method,
  79. headers: {
  80. 'X-User-Id': this.user_id,
  81. },
  82. })
  83. .should.equal(true)
  84. })
  85. it('should pipe the response to the client', function () {
  86. expect(this.Stream.pipeline).to.have.been.calledWith(
  87. this.proxy,
  88. this.res
  89. )
  90. })
  91. })
  92. describe('for a project without the project history flag', function () {
  93. beforeEach(function () {
  94. this.req.useProjectHistory = false
  95. return this.HistoryController.proxyToHistoryApi(
  96. this.req,
  97. this.res,
  98. this.next
  99. )
  100. })
  101. it('should get the user id', function () {
  102. return this.SessionManager.getLoggedInUserId
  103. .calledWith(this.req.session)
  104. .should.equal(true)
  105. })
  106. it('should pipe the response to the client', function () {
  107. expect(this.Stream.pipeline).to.have.been.calledWith(
  108. this.proxy,
  109. this.res
  110. )
  111. })
  112. })
  113. })
  114. describe('proxyToHistoryApiAndInjectUserDetails', function () {
  115. beforeEach(function () {
  116. this.req = { url: '/mock/url', method: 'POST' }
  117. this.res = { json: sinon.stub() }
  118. this.next = sinon.stub()
  119. this.request.yields(null, { statusCode: 200 }, (this.data = 'mock-data'))
  120. return (this.HistoryManager.injectUserDetails = sinon
  121. .stub()
  122. .yields(null, (this.data_with_users = 'mock-injected-data')))
  123. })
  124. describe('for a project with the project history flag', function () {
  125. beforeEach(function () {
  126. this.req.useProjectHistory = true
  127. return this.HistoryController.proxyToHistoryApiAndInjectUserDetails(
  128. this.req,
  129. this.res,
  130. this.next
  131. )
  132. })
  133. it('should get the user id', function () {
  134. return this.SessionManager.getLoggedInUserId
  135. .calledWith(this.req.session)
  136. .should.equal(true)
  137. })
  138. it('should call the project history api', function () {
  139. return this.request
  140. .calledWith({
  141. url: `${this.settings.apis.project_history.url}${this.req.url}`,
  142. method: this.req.method,
  143. json: true,
  144. headers: {
  145. 'X-User-Id': this.user_id,
  146. },
  147. })
  148. .should.equal(true)
  149. })
  150. it('should inject the user data', function () {
  151. return this.HistoryManager.injectUserDetails
  152. .calledWith(this.data)
  153. .should.equal(true)
  154. })
  155. it('should return the data with users to the client', function () {
  156. return this.res.json.calledWith(this.data_with_users).should.equal(true)
  157. })
  158. })
  159. describe('for a project without the project history flag', function () {
  160. beforeEach(function () {
  161. this.req.useProjectHistory = false
  162. return this.HistoryController.proxyToHistoryApiAndInjectUserDetails(
  163. this.req,
  164. this.res,
  165. this.next
  166. )
  167. })
  168. it('should get the user id', function () {
  169. return this.SessionManager.getLoggedInUserId
  170. .calledWith(this.req.session)
  171. .should.equal(true)
  172. })
  173. it('should inject the user data', function () {
  174. return this.HistoryManager.injectUserDetails
  175. .calledWith(this.data)
  176. .should.equal(true)
  177. })
  178. it('should return the data with users to the client', function () {
  179. return this.res.json.calledWith(this.data_with_users).should.equal(true)
  180. })
  181. })
  182. })
  183. describe('proxyToHistoryApiAndInjectUserDetails (with the history API failing)', function () {
  184. beforeEach(function () {
  185. this.req = { url: '/mock/url', method: 'POST', useProjectHistory: true }
  186. this.res = { json: sinon.stub() }
  187. this.next = sinon.stub()
  188. this.request.yields(null, { statusCode: 500 }, (this.data = 'mock-data'))
  189. this.HistoryManager.injectUserDetails = sinon
  190. .stub()
  191. .yields(null, (this.data_with_users = 'mock-injected-data'))
  192. return this.HistoryController.proxyToHistoryApiAndInjectUserDetails(
  193. this.req,
  194. this.res,
  195. this.next
  196. )
  197. })
  198. it('should not inject the user data', function () {
  199. return this.HistoryManager.injectUserDetails
  200. .calledWith(this.data)
  201. .should.equal(false)
  202. })
  203. it('should not return the data with users to the client', function () {
  204. return this.res.json.calledWith(this.data_with_users).should.equal(false)
  205. })
  206. })
  207. describe('resyncProjectHistory', function () {
  208. describe('for a project without project-history enabled', function () {
  209. beforeEach(function () {
  210. this.project_id = 'mock-project-id'
  211. this.req = { params: { Project_id: this.project_id }, body: {} }
  212. this.res = { setTimeout: sinon.stub(), sendStatus: sinon.stub() }
  213. this.next = sinon.stub()
  214. this.error = new Errors.ProjectHistoryDisabledError()
  215. this.ProjectEntityUpdateHandler.resyncProjectHistory = sinon
  216. .stub()
  217. .yields(this.error)
  218. return this.HistoryController.resyncProjectHistory(
  219. this.req,
  220. this.res,
  221. this.next
  222. )
  223. })
  224. it('response with a 404', function () {
  225. return this.res.sendStatus.calledWith(404).should.equal(true)
  226. })
  227. })
  228. describe('for a project with project-history enabled', function () {
  229. beforeEach(function () {
  230. this.project_id = 'mock-project-id'
  231. this.req = { params: { Project_id: this.project_id }, body: {} }
  232. this.res = { setTimeout: sinon.stub(), sendStatus: sinon.stub() }
  233. this.next = sinon.stub()
  234. this.ProjectEntityUpdateHandler.resyncProjectHistory = sinon
  235. .stub()
  236. .yields()
  237. return this.HistoryController.resyncProjectHistory(
  238. this.req,
  239. this.res,
  240. this.next
  241. )
  242. })
  243. it('sets an extended response timeout', function () {
  244. this.res.setTimeout.should.have.been.calledWith(6 * 60 * 1000)
  245. })
  246. it('resyncs the project', function () {
  247. return this.ProjectEntityUpdateHandler.resyncProjectHistory
  248. .calledWith(this.project_id)
  249. .should.equal(true)
  250. })
  251. it('responds with a 204', function () {
  252. return this.res.sendStatus.calledWith(204).should.equal(true)
  253. })
  254. })
  255. })
  256. })