updateProjectTests.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399
  1. /* eslint-disable
  2. no-return-assign,
  3. no-unused-vars,
  4. */
  5. // TODO: This file was created by bulk-decaffeinate.
  6. // Fix any style issues and re-enable lint.
  7. /*
  8. * decaffeinate suggestions:
  9. * DS206: Consider reworking classes to avoid initClass
  10. * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
  11. */
  12. const sinon = require('sinon')
  13. const chai = require('chai')
  14. const should = chai.should()
  15. const modulePath = '../../../../app/js/ProjectManager.js'
  16. const SandboxedModule = require('sandboxed-module')
  17. const _ = require('lodash')
  18. describe('ProjectManager', function () {
  19. beforeEach(function () {
  20. let Timer
  21. this.ProjectManager = SandboxedModule.require(modulePath, {
  22. requires: {
  23. './RedisManager': (this.RedisManager = {}),
  24. './ProjectHistoryRedisManager': (this.ProjectHistoryRedisManager = {}),
  25. './DocumentManager': (this.DocumentManager = {}),
  26. 'logger-sharelatex': (this.logger = {
  27. log: sinon.stub(),
  28. error: sinon.stub()
  29. }),
  30. './HistoryManager': (this.HistoryManager = {}),
  31. './Metrics': (this.Metrics = {
  32. Timer: (Timer = (function () {
  33. Timer = class Timer {
  34. static initClass() {
  35. this.prototype.done = sinon.stub()
  36. }
  37. }
  38. Timer.initClass()
  39. return Timer
  40. })())
  41. })
  42. }
  43. })
  44. this.project_id = 'project-id-123'
  45. this.projectHistoryId = 'history-id-123'
  46. this.user_id = 'user-id-123'
  47. this.version = 1234567
  48. this.HistoryManager.shouldFlushHistoryOps = sinon.stub().returns(false)
  49. this.HistoryManager.flushProjectChangesAsync = sinon.stub()
  50. this.callback = sinon.stub()
  51. })
  52. describe('updateProjectWithLocks', function () {
  53. describe('rename operations', function () {
  54. beforeEach(function () {
  55. this.firstDocUpdate = {
  56. id: 1,
  57. pathname: 'foo',
  58. newPathname: 'foo'
  59. }
  60. this.secondDocUpdate = {
  61. id: 2,
  62. pathname: 'bar',
  63. newPathname: 'bar2'
  64. }
  65. this.docUpdates = [this.firstDocUpdate, this.secondDocUpdate]
  66. this.firstFileUpdate = {
  67. id: 2,
  68. pathname: 'bar',
  69. newPathname: 'bar2'
  70. }
  71. this.fileUpdates = [this.firstFileUpdate]
  72. this.DocumentManager.renameDocWithLock = sinon.stub().yields()
  73. this.ProjectHistoryRedisManager.queueRenameEntity = sinon
  74. .stub()
  75. .yields()
  76. })
  77. describe('successfully', function () {
  78. beforeEach(function () {
  79. this.ProjectManager.updateProjectWithLocks(
  80. this.project_id,
  81. this.projectHistoryId,
  82. this.user_id,
  83. this.docUpdates,
  84. this.fileUpdates,
  85. this.version,
  86. this.callback
  87. )
  88. })
  89. it('should rename the docs in the updates', function () {
  90. const firstDocUpdateWithVersion = _.extend({}, this.firstDocUpdate, {
  91. version: `${this.version}.0`
  92. })
  93. const secondDocUpdateWithVersion = _.extend(
  94. {},
  95. this.secondDocUpdate,
  96. { version: `${this.version}.1` }
  97. )
  98. this.DocumentManager.renameDocWithLock
  99. .calledWith(
  100. this.project_id,
  101. this.firstDocUpdate.id,
  102. this.user_id,
  103. firstDocUpdateWithVersion,
  104. this.projectHistoryId
  105. )
  106. .should.equal(true)
  107. this.DocumentManager.renameDocWithLock
  108. .calledWith(
  109. this.project_id,
  110. this.secondDocUpdate.id,
  111. this.user_id,
  112. secondDocUpdateWithVersion,
  113. this.projectHistoryId
  114. )
  115. .should.equal(true)
  116. })
  117. it('should rename the files in the updates', function () {
  118. const firstFileUpdateWithVersion = _.extend(
  119. {},
  120. this.firstFileUpdate,
  121. { version: `${this.version}.2` }
  122. )
  123. this.ProjectHistoryRedisManager.queueRenameEntity
  124. .calledWith(
  125. this.project_id,
  126. this.projectHistoryId,
  127. 'file',
  128. this.firstFileUpdate.id,
  129. this.user_id,
  130. firstFileUpdateWithVersion
  131. )
  132. .should.equal(true)
  133. })
  134. it('should not flush the history', function () {
  135. this.HistoryManager.flushProjectChangesAsync
  136. .calledWith(this.project_id)
  137. .should.equal(false)
  138. })
  139. it('should call the callback', function () {
  140. this.callback.called.should.equal(true)
  141. })
  142. })
  143. describe('when renaming a doc fails', function () {
  144. beforeEach(function () {
  145. this.error = new Error('error')
  146. this.DocumentManager.renameDocWithLock = sinon
  147. .stub()
  148. .yields(this.error)
  149. this.ProjectManager.updateProjectWithLocks(
  150. this.project_id,
  151. this.projectHistoryId,
  152. this.user_id,
  153. this.docUpdates,
  154. this.fileUpdates,
  155. this.version,
  156. this.callback
  157. )
  158. })
  159. it('should call the callback with the error', function () {
  160. this.callback.calledWith(this.error).should.equal(true)
  161. })
  162. })
  163. describe('when renaming a file fails', function () {
  164. beforeEach(function () {
  165. this.error = new Error('error')
  166. this.ProjectHistoryRedisManager.queueRenameEntity = sinon
  167. .stub()
  168. .yields(this.error)
  169. this.ProjectManager.updateProjectWithLocks(
  170. this.project_id,
  171. this.projectHistoryId,
  172. this.user_id,
  173. this.docUpdates,
  174. this.fileUpdates,
  175. this.version,
  176. this.callback
  177. )
  178. })
  179. it('should call the callback with the error', function () {
  180. this.callback.calledWith(this.error).should.equal(true)
  181. })
  182. })
  183. describe('with enough ops to flush', function () {
  184. beforeEach(function () {
  185. this.HistoryManager.shouldFlushHistoryOps = sinon.stub().returns(true)
  186. this.ProjectManager.updateProjectWithLocks(
  187. this.project_id,
  188. this.projectHistoryId,
  189. this.user_id,
  190. this.docUpdates,
  191. this.fileUpdates,
  192. this.version,
  193. this.callback
  194. )
  195. })
  196. it('should flush the history', function () {
  197. this.HistoryManager.flushProjectChangesAsync
  198. .calledWith(this.project_id)
  199. .should.equal(true)
  200. })
  201. })
  202. })
  203. describe('add operations', function () {
  204. beforeEach(function () {
  205. this.firstDocUpdate = {
  206. id: 1,
  207. docLines: 'a\nb'
  208. }
  209. this.secondDocUpdate = {
  210. id: 2,
  211. docLines: 'a\nb'
  212. }
  213. this.docUpdates = [this.firstDocUpdate, this.secondDocUpdate]
  214. this.firstFileUpdate = {
  215. id: 3,
  216. url: 'filestore.example.com/2'
  217. }
  218. this.secondFileUpdate = {
  219. id: 4,
  220. url: 'filestore.example.com/3'
  221. }
  222. this.fileUpdates = [this.firstFileUpdate, this.secondFileUpdate]
  223. this.ProjectHistoryRedisManager.queueAddEntity = sinon.stub().yields()
  224. })
  225. describe('successfully', function () {
  226. beforeEach(function () {
  227. this.ProjectManager.updateProjectWithLocks(
  228. this.project_id,
  229. this.projectHistoryId,
  230. this.user_id,
  231. this.docUpdates,
  232. this.fileUpdates,
  233. this.version,
  234. this.callback
  235. )
  236. })
  237. it('should add the docs in the updates', function () {
  238. const firstDocUpdateWithVersion = _.extend({}, this.firstDocUpdate, {
  239. version: `${this.version}.0`
  240. })
  241. const secondDocUpdateWithVersion = _.extend(
  242. {},
  243. this.secondDocUpdate,
  244. { version: `${this.version}.1` }
  245. )
  246. this.ProjectHistoryRedisManager.queueAddEntity
  247. .getCall(0)
  248. .calledWith(
  249. this.project_id,
  250. this.projectHistoryId,
  251. 'doc',
  252. this.firstDocUpdate.id,
  253. this.user_id,
  254. firstDocUpdateWithVersion
  255. )
  256. .should.equal(true)
  257. this.ProjectHistoryRedisManager.queueAddEntity
  258. .getCall(1)
  259. .calledWith(
  260. this.project_id,
  261. this.projectHistoryId,
  262. 'doc',
  263. this.secondDocUpdate.id,
  264. this.user_id,
  265. secondDocUpdateWithVersion
  266. )
  267. .should.equal(true)
  268. })
  269. it('should add the files in the updates', function () {
  270. const firstFileUpdateWithVersion = _.extend(
  271. {},
  272. this.firstFileUpdate,
  273. { version: `${this.version}.2` }
  274. )
  275. const secondFileUpdateWithVersion = _.extend(
  276. {},
  277. this.secondFileUpdate,
  278. { version: `${this.version}.3` }
  279. )
  280. this.ProjectHistoryRedisManager.queueAddEntity
  281. .getCall(2)
  282. .calledWith(
  283. this.project_id,
  284. this.projectHistoryId,
  285. 'file',
  286. this.firstFileUpdate.id,
  287. this.user_id,
  288. firstFileUpdateWithVersion
  289. )
  290. .should.equal(true)
  291. this.ProjectHistoryRedisManager.queueAddEntity
  292. .getCall(3)
  293. .calledWith(
  294. this.project_id,
  295. this.projectHistoryId,
  296. 'file',
  297. this.secondFileUpdate.id,
  298. this.user_id,
  299. secondFileUpdateWithVersion
  300. )
  301. .should.equal(true)
  302. })
  303. it('should not flush the history', function () {
  304. this.HistoryManager.flushProjectChangesAsync
  305. .calledWith(this.project_id)
  306. .should.equal(false)
  307. })
  308. it('should call the callback', function () {
  309. this.callback.called.should.equal(true)
  310. })
  311. })
  312. describe('when adding a doc fails', function () {
  313. beforeEach(function () {
  314. this.error = new Error('error')
  315. this.ProjectHistoryRedisManager.queueAddEntity = sinon
  316. .stub()
  317. .yields(this.error)
  318. this.ProjectManager.updateProjectWithLocks(
  319. this.project_id,
  320. this.projectHistoryId,
  321. this.user_id,
  322. this.docUpdates,
  323. this.fileUpdates,
  324. this.version,
  325. this.callback
  326. )
  327. })
  328. it('should call the callback with the error', function () {
  329. this.callback.calledWith(this.error).should.equal(true)
  330. })
  331. })
  332. describe('when adding a file fails', function () {
  333. beforeEach(function () {
  334. this.error = new Error('error')
  335. this.ProjectHistoryRedisManager.queueAddEntity = sinon
  336. .stub()
  337. .yields(this.error)
  338. this.ProjectManager.updateProjectWithLocks(
  339. this.project_id,
  340. this.projectHistoryId,
  341. this.user_id,
  342. this.docUpdates,
  343. this.fileUpdates,
  344. this.version,
  345. this.callback
  346. )
  347. })
  348. it('should call the callback with the error', function () {
  349. this.callback.calledWith(this.error).should.equal(true)
  350. })
  351. })
  352. describe('with enough ops to flush', function () {
  353. beforeEach(function () {
  354. this.HistoryManager.shouldFlushHistoryOps = sinon.stub().returns(true)
  355. this.ProjectManager.updateProjectWithLocks(
  356. this.project_id,
  357. this.projectHistoryId,
  358. this.user_id,
  359. this.docUpdates,
  360. this.fileUpdates,
  361. this.version,
  362. this.callback
  363. )
  364. })
  365. it('should flush the history', function () {
  366. this.HistoryManager.flushProjectChangesAsync
  367. .calledWith(this.project_id)
  368. .should.equal(true)
  369. })
  370. })
  371. })
  372. })
  373. })