TpdsUpdateHandlerTests.js 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  1. /* eslint-disable
  2. camelcase,
  3. max-len,
  4. no-return-assign,
  5. no-unused-vars,
  6. */
  7. // TODO: This file was created by bulk-decaffeinate.
  8. // Fix any style issues and re-enable lint.
  9. /*
  10. * decaffeinate suggestions:
  11. * DS102: Remove unnecessary code created because of implicit returns
  12. * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
  13. */
  14. const SandboxedModule = require('sandboxed-module')
  15. const sinon = require('sinon')
  16. require('chai').should()
  17. const { expect } = require('chai')
  18. const modulePath = require('path').join(
  19. __dirname,
  20. '../../../../app/src/Features/ThirdPartyDataStore/TpdsUpdateHandler.js'
  21. )
  22. describe('TpdsUpdateHandler', function() {
  23. beforeEach(function() {
  24. this.requestQueuer = {}
  25. this.updateMerger = {
  26. deleteUpdate(user_id, project_id, path, source, cb) {
  27. return cb()
  28. },
  29. mergeUpdate(user_id, project_id, path, update, source, cb) {
  30. return cb()
  31. }
  32. }
  33. this.editorController = {}
  34. this.project_id = 'dsjajilknaksdn'
  35. this.project = { _id: this.project_id, name: 'projectNameHere' }
  36. this.projectLocator = {
  37. findUsersProjectByName: sinon
  38. .stub()
  39. .callsArgWith(2, null, { project: this.project })
  40. }
  41. this.projectCreationHandler = {
  42. createBlankProject: sinon.stub().callsArgWith(2, null, this.project)
  43. }
  44. this.projectDeleter = {
  45. markAsDeletedByExternalSource: sinon.stub().callsArgWith(1)
  46. }
  47. this.rootDocManager = { setRootDocAutomatically: sinon.stub() }
  48. this.FileTypeManager = {
  49. shouldIgnore: sinon.stub().callsArgWith(1, null, false)
  50. }
  51. this.CooldownManager = {
  52. isProjectOnCooldown: sinon.stub().callsArgWith(1, null, false)
  53. }
  54. this.handler = SandboxedModule.require(modulePath, {
  55. globals: {
  56. console: console
  57. },
  58. requires: {
  59. './UpdateMerger': this.updateMerger,
  60. './Editor/EditorController': this.editorController,
  61. '../Project/ProjectLocator': this.projectLocator,
  62. '../Project/ProjectCreationHandler': this.projectCreationHandler,
  63. '../Project/ProjectDeleter': this.projectDeleter,
  64. '../Project/ProjectRootDocManager': this.rootDocManager,
  65. '../Uploads/FileTypeManager': this.FileTypeManager,
  66. '../Cooldown/CooldownManager': this.CooldownManager,
  67. 'logger-sharelatex': {
  68. log() {}
  69. }
  70. }
  71. })
  72. this.user_id = 'dsad29jlkjas'
  73. return (this.source = 'dropbox')
  74. })
  75. describe('getting an update', function() {
  76. it('should send the update to the update merger', function(done) {
  77. const path = '/path/here'
  78. const update = {}
  79. this.updateMerger.mergeUpdate = sinon.stub()
  80. this.updateMerger.mergeUpdate
  81. .withArgs(this.user_id, this.project_id, path, update, this.source)
  82. .callsArg(5)
  83. return this.handler.newUpdate(
  84. this.user_id,
  85. this.project.name,
  86. path,
  87. update,
  88. this.source,
  89. () => {
  90. this.projectCreationHandler.createBlankProject.called.should.equal(
  91. false
  92. )
  93. return done()
  94. }
  95. )
  96. })
  97. it('should create a new project if one does not already exit', function(done) {
  98. this.projectLocator.findUsersProjectByName = sinon
  99. .stub()
  100. .callsArgWith(2, null, { project: null })
  101. const path = '/'
  102. return this.handler.newUpdate(
  103. this.user_id,
  104. this.project.name,
  105. path,
  106. {},
  107. this.source,
  108. () => {
  109. this.projectCreationHandler.createBlankProject
  110. .calledWith(this.user_id, this.project.name)
  111. .should.equal(true)
  112. return done()
  113. }
  114. )
  115. })
  116. it('should not create a new project if one with the same name is archived', function(done) {
  117. this.projectLocator.findUsersProjectByName = sinon
  118. .stub()
  119. .callsArgWith(2, null, {
  120. project: this.project,
  121. isArchivedOrTrashed: true
  122. })
  123. const path = '/'
  124. return this.handler.newUpdate(
  125. this.user_id,
  126. this.project.name,
  127. path,
  128. {},
  129. this.source,
  130. err => {
  131. expect(err).to.exist
  132. expect(err.name).to.equal('ProjectIsArchivedOrTrashedError')
  133. this.projectCreationHandler.createBlankProject
  134. .calledWith(this.user_id, this.project.name)
  135. .should.equal(false)
  136. return done()
  137. }
  138. )
  139. })
  140. it('should not create a new project if one is found', function(done) {
  141. this.projectLocator.findUsersProjectByName = sinon
  142. .stub()
  143. .callsArgWith(2, null, {
  144. project: this.project,
  145. isArchivedOrTrashed: false
  146. })
  147. const path = '/'
  148. return this.handler.newUpdate(
  149. this.user_id,
  150. this.project.name,
  151. path,
  152. {},
  153. this.source,
  154. err => {
  155. expect(err).to.not.exist
  156. this.projectCreationHandler.createBlankProject
  157. .calledWith(this.user_id, this.project.name)
  158. .should.equal(false)
  159. return done()
  160. }
  161. )
  162. })
  163. it('should set the root doc automatically if a new project is created', function(done) {
  164. this.projectLocator.findUsersProjectByName = sinon
  165. .stub()
  166. .callsArgWith(2, null, { project: null })
  167. this.handler._rootDocTimeoutLength = 0
  168. const path = '/'
  169. return this.handler.newUpdate(
  170. this.user_id,
  171. this.project.name,
  172. path,
  173. {},
  174. this.source,
  175. () => {
  176. return setTimeout(() => {
  177. this.rootDocManager.setRootDocAutomatically
  178. .calledWith(this.project._id)
  179. .should.equal(true)
  180. return done()
  181. }, 1)
  182. }
  183. )
  184. })
  185. it('should not update files that should be ignored', function(done) {
  186. this.FileTypeManager.shouldIgnore = sinon
  187. .stub()
  188. .callsArgWith(1, null, true)
  189. this.projectLocator.findUsersProjectByName = sinon
  190. .stub()
  191. .callsArgWith(2, null, { project: null })
  192. const path = '/.gitignore'
  193. this.updateMerger.mergeUpdate = sinon.stub()
  194. return this.handler.newUpdate(
  195. this.user_id,
  196. this.project.name,
  197. path,
  198. {},
  199. this.source,
  200. () => {
  201. this.updateMerger.mergeUpdate.called.should.equal(false)
  202. return done()
  203. }
  204. )
  205. })
  206. it('should check if the project is on cooldown', function(done) {
  207. this.CooldownManager.isProjectOnCooldown = sinon
  208. .stub()
  209. .callsArgWith(1, null, false)
  210. this.projectLocator.findUsersProjectByName = sinon
  211. .stub()
  212. .callsArgWith(2, null, { project: null })
  213. const path = '/path/here'
  214. const update = {}
  215. this.updateMerger.mergeUpdate = sinon.stub()
  216. this.updateMerger.mergeUpdate
  217. .withArgs(this.user_id, this.project_id, path, update, this.source)
  218. .callsArg(5)
  219. return this.handler.newUpdate(
  220. this.user_id,
  221. this.project.name,
  222. path,
  223. update,
  224. this.source,
  225. err => {
  226. expect(err).to.be.oneOf([null, undefined])
  227. this.CooldownManager.isProjectOnCooldown.callCount.should.equal(1)
  228. this.CooldownManager.isProjectOnCooldown
  229. .calledWith(this.project_id)
  230. .should.equal(true)
  231. this.FileTypeManager.shouldIgnore.callCount.should.equal(1)
  232. this.updateMerger.mergeUpdate.callCount.should.equal(1)
  233. return done()
  234. }
  235. )
  236. })
  237. it('should return error and not proceed with update if project is on cooldown', function(done) {
  238. this.CooldownManager.isProjectOnCooldown = sinon
  239. .stub()
  240. .callsArgWith(1, null, true)
  241. this.projectLocator.findUsersProjectByName = sinon
  242. .stub()
  243. .callsArgWith(2, null, { project: null })
  244. this.FileTypeManager.shouldIgnore = sinon
  245. .stub()
  246. .callsArgWith(1, null, false)
  247. const path = '/path/here'
  248. const update = {}
  249. this.updateMerger.mergeUpdate = sinon.stub()
  250. this.updateMerger.mergeUpdate
  251. .withArgs(this.user_id, this.project_id, path, update, this.source)
  252. .callsArg(5)
  253. return this.handler.newUpdate(
  254. this.user_id,
  255. this.project.name,
  256. path,
  257. update,
  258. this.source,
  259. err => {
  260. expect(err).to.not.be.oneOf([null, undefined])
  261. expect(err).to.be.instanceof(Error)
  262. this.CooldownManager.isProjectOnCooldown.callCount.should.equal(1)
  263. this.CooldownManager.isProjectOnCooldown
  264. .calledWith(this.project_id)
  265. .should.equal(true)
  266. this.FileTypeManager.shouldIgnore.callCount.should.equal(0)
  267. this.updateMerger.mergeUpdate.callCount.should.equal(0)
  268. return done()
  269. }
  270. )
  271. })
  272. })
  273. describe('getting a delete :', function() {
  274. it('should call deleteEntity in the collaberation manager', function(done) {
  275. const path = '/delete/this'
  276. const update = {}
  277. this.updateMerger.deleteUpdate = sinon.stub().callsArg(4)
  278. return this.handler.deleteUpdate(
  279. this.user_id,
  280. this.project.name,
  281. path,
  282. this.source,
  283. () => {
  284. this.projectDeleter.markAsDeletedByExternalSource
  285. .calledWith(this.project._id)
  286. .should.equal(false)
  287. this.updateMerger.deleteUpdate
  288. .calledWith(this.user_id, this.project_id, path, this.source)
  289. .should.equal(true)
  290. return done()
  291. }
  292. )
  293. })
  294. it('should mark the project as deleted by external source if path is a single slash', function(done) {
  295. const path = '/'
  296. return this.handler.deleteUpdate(
  297. this.user_id,
  298. this.project.name,
  299. path,
  300. this.source,
  301. () => {
  302. this.projectDeleter.markAsDeletedByExternalSource
  303. .calledWith(this.project._id)
  304. .should.equal(true)
  305. return done()
  306. }
  307. )
  308. })
  309. })
  310. })