ProjectEntityHandlerTests.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384
  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. * DS205: Consider reworking code to avoid use of IIFEs
  13. * DS206: Consider reworking classes to avoid initClass
  14. * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
  15. */
  16. const chai = require('chai')
  17. const { assert } = require('chai')
  18. const should = chai.should()
  19. const { expect } = chai
  20. const sinon = require('sinon')
  21. const modulePath = '../../../../app/src/Features/Project/ProjectEntityHandler'
  22. const SandboxedModule = require('sandboxed-module')
  23. const { ObjectId } = require('mongoose').Types
  24. const Errors = require('../../../../app/src/Features/Errors/Errors')
  25. describe('ProjectEntityHandler', function() {
  26. const project_id = '4eecb1c1bffa66588e0000a1'
  27. const doc_id = '4eecb1c1bffa66588e0000a2'
  28. const folder_id = '4eecaffcbffa66588e000008'
  29. const rootFolderId = '4eecaffcbffa66588e000007'
  30. const userId = 1234
  31. beforeEach(function() {
  32. let Project
  33. this.TpdsUpdateSender = {
  34. addDoc: sinon.stub().callsArg(1),
  35. addFile: sinon.stub().callsArg(1)
  36. }
  37. this.ProjectModel = Project = (function() {
  38. Project = class Project {
  39. static initClass() {
  40. this.prototype.rootFolder = [this.rootFolder]
  41. }
  42. constructor(options) {
  43. this._id = project_id
  44. this.name = 'project_name_here'
  45. this.rev = 0
  46. }
  47. }
  48. Project.initClass()
  49. return Project
  50. })()
  51. this.project = new this.ProjectModel()
  52. this.ProjectLocator = { findElement: sinon.stub() }
  53. this.DocumentUpdaterHandler = {
  54. updateProjectStructure: sinon.stub().yields()
  55. }
  56. this.callback = sinon.stub()
  57. return (this.ProjectEntityHandler = SandboxedModule.require(modulePath, {
  58. requires: {
  59. 'logger-sharelatex': (this.logger = {
  60. log: sinon.stub(),
  61. error: sinon.stub(),
  62. err() {}
  63. }),
  64. '../Docstore/DocstoreManager': (this.DocstoreManager = {}),
  65. '../../Features/DocumentUpdater/DocumentUpdaterHandler': this
  66. .DocumentUpdaterHandler,
  67. '../../models/Project': {
  68. Project: this.ProjectModel
  69. },
  70. './ProjectLocator': this.ProjectLocator,
  71. './ProjectGetter': (this.ProjectGetter = {}),
  72. '../ThirdPartyDataStore/TpdsUpdateSender': this.TpdsUpdateSender
  73. }
  74. }))
  75. })
  76. describe('getting folders, docs and files', function() {
  77. beforeEach(function() {
  78. this.project.rootFolder = [
  79. {
  80. docs: [
  81. (this.doc1 = {
  82. name: 'doc1',
  83. _id: 'doc1_id'
  84. })
  85. ],
  86. fileRefs: [
  87. (this.file1 = {
  88. rev: 1,
  89. _id: 'file1_id',
  90. name: 'file1'
  91. })
  92. ],
  93. folders: [
  94. (this.folder1 = {
  95. name: 'folder1',
  96. docs: [
  97. (this.doc2 = {
  98. name: 'doc2',
  99. _id: 'doc2_id'
  100. })
  101. ],
  102. fileRefs: [
  103. (this.file2 = {
  104. rev: 2,
  105. name: 'file2',
  106. _id: 'file2_id'
  107. })
  108. ],
  109. folders: []
  110. })
  111. ]
  112. }
  113. ]
  114. return (this.ProjectGetter.getProjectWithoutDocLines = sinon
  115. .stub()
  116. .yields(null, this.project))
  117. })
  118. describe('getAllDocs', function() {
  119. beforeEach(function() {
  120. this.docs = [
  121. {
  122. _id: this.doc1._id,
  123. lines: (this.lines1 = ['one']),
  124. rev: (this.rev1 = 1)
  125. },
  126. {
  127. _id: this.doc2._id,
  128. lines: (this.lines2 = ['two']),
  129. rev: (this.rev2 = 2)
  130. }
  131. ]
  132. this.DocstoreManager.getAllDocs = sinon
  133. .stub()
  134. .callsArgWith(1, null, this.docs)
  135. return this.ProjectEntityHandler.getAllDocs(project_id, this.callback)
  136. })
  137. it('should get the doc lines and rev from the docstore', function() {
  138. return this.DocstoreManager.getAllDocs
  139. .calledWith(project_id)
  140. .should.equal(true)
  141. })
  142. it('should call the callback with the docs with the lines and rev included', function() {
  143. return this.callback
  144. .calledWith(null, {
  145. '/doc1': {
  146. _id: this.doc1._id,
  147. lines: this.lines1,
  148. name: this.doc1.name,
  149. rev: this.rev1
  150. },
  151. '/folder1/doc2': {
  152. _id: this.doc2._id,
  153. lines: this.lines2,
  154. name: this.doc2.name,
  155. rev: this.rev2
  156. }
  157. })
  158. .should.equal(true)
  159. })
  160. })
  161. describe('getAllFiles', function() {
  162. beforeEach(function() {
  163. this.callback = sinon.stub()
  164. return this.ProjectEntityHandler.getAllFiles(project_id, this.callback)
  165. })
  166. it('should call the callback with the files', function() {
  167. return this.callback
  168. .calledWith(null, {
  169. '/file1': this.file1,
  170. '/folder1/file2': this.file2
  171. })
  172. .should.equal(true)
  173. })
  174. })
  175. describe('getAllDocPathsFromProject', function() {
  176. beforeEach(function() {
  177. this.docs = [
  178. {
  179. _id: this.doc1._id,
  180. lines: (this.lines1 = ['one']),
  181. rev: (this.rev1 = 1)
  182. },
  183. {
  184. _id: this.doc2._id,
  185. lines: (this.lines2 = ['two']),
  186. rev: (this.rev2 = 2)
  187. }
  188. ]
  189. this.callback = sinon.stub()
  190. return this.ProjectEntityHandler.getAllDocPathsFromProject(
  191. this.project,
  192. this.callback
  193. )
  194. })
  195. it('should call the callback with the path for each doc_id', function() {
  196. this.expected = {}
  197. this.expected[this.doc1._id] = `/${this.doc1.name}`
  198. this.expected[this.doc2._id] = `/folder1/${this.doc2.name}`
  199. return this.callback.calledWith(null, this.expected).should.equal(true)
  200. })
  201. })
  202. describe('_getAllFolders', function() {
  203. beforeEach(function() {
  204. this.callback = sinon.stub()
  205. return this.ProjectEntityHandler._getAllFolders(
  206. project_id,
  207. this.callback
  208. )
  209. })
  210. it('should get the project without the docs lines', function() {
  211. return this.ProjectGetter.getProjectWithoutDocLines
  212. .calledWith(project_id)
  213. .should.equal(true)
  214. })
  215. it('should call the callback with the folders', function() {
  216. return this.callback
  217. .calledWith(null, {
  218. '/': this.project.rootFolder[0],
  219. '/folder1': this.folder1
  220. })
  221. .should.equal(true)
  222. })
  223. })
  224. describe('_getAllFoldersFromProject', function() {
  225. beforeEach(function() {
  226. this.callback = sinon.stub()
  227. return this.ProjectEntityHandler._getAllFoldersFromProject(
  228. this.project,
  229. this.callback
  230. )
  231. })
  232. it('should call the callback with the folders', function() {
  233. return this.callback
  234. .calledWith(null, {
  235. '/': this.project.rootFolder[0],
  236. '/folder1': this.folder1
  237. })
  238. .should.equal(true)
  239. })
  240. })
  241. })
  242. describe('flushProjectToThirdPartyDataStore', function() {
  243. beforeEach(function(done) {
  244. this.project = {
  245. _id: project_id,
  246. name: 'Mock project name'
  247. }
  248. this.DocumentUpdaterHandler.flushProjectToMongo = sinon.stub().yields()
  249. this.docs = {
  250. '/doc/one': (this.doc1 = { _id: 'mock-doc-1', lines: ['one'], rev: 5 }),
  251. '/doc/two': (this.doc2 = { _id: 'mock-doc-2', lines: ['two'], rev: 6 })
  252. }
  253. this.files = {
  254. '/file/one': (this.file1 = { _id: 'mock-file-1', rev: 7 }),
  255. '/file/two': (this.file2 = { _id: 'mock-file-2', rev: 8 })
  256. }
  257. this.ProjectEntityHandler.getAllDocs = sinon
  258. .stub()
  259. .yields(null, this.docs)
  260. this.ProjectEntityHandler.getAllFiles = sinon
  261. .stub()
  262. .yields(null, this.files)
  263. this.ProjectGetter.getProject = sinon.stub().yields(null, this.project)
  264. return this.ProjectEntityHandler.flushProjectToThirdPartyDataStore(
  265. project_id,
  266. () => done()
  267. )
  268. })
  269. it('should flush the project from the doc updater', function() {
  270. return this.DocumentUpdaterHandler.flushProjectToMongo
  271. .calledWith(project_id)
  272. .should.equal(true)
  273. })
  274. it('should look up the project in mongo', function() {
  275. return this.ProjectGetter.getProject
  276. .calledWith(project_id)
  277. .should.equal(true)
  278. })
  279. it('should get all the docs in the project', function() {
  280. return this.ProjectEntityHandler.getAllDocs
  281. .calledWith(project_id)
  282. .should.equal(true)
  283. })
  284. it('should get all the files in the project', function() {
  285. return this.ProjectEntityHandler.getAllFiles
  286. .calledWith(project_id)
  287. .should.equal(true)
  288. })
  289. it('should flush each doc to the TPDS', function() {
  290. return (() => {
  291. const result = []
  292. for (let path in this.docs) {
  293. const doc = this.docs[path]
  294. result.push(
  295. this.TpdsUpdateSender.addDoc
  296. .calledWith({
  297. project_id,
  298. doc_id: doc._id,
  299. project_name: this.project.name,
  300. rev: doc.rev,
  301. path
  302. })
  303. .should.equal(true)
  304. )
  305. }
  306. return result
  307. })()
  308. })
  309. it('should flush each file to the TPDS', function() {
  310. return (() => {
  311. const result = []
  312. for (let path in this.files) {
  313. const file = this.files[path]
  314. result.push(
  315. this.TpdsUpdateSender.addFile
  316. .calledWith({
  317. project_id,
  318. file_id: file._id,
  319. project_name: this.project.name,
  320. rev: file.rev,
  321. path
  322. })
  323. .should.equal(true)
  324. )
  325. }
  326. return result
  327. })()
  328. })
  329. })
  330. describe('getDoc', function() {
  331. beforeEach(function() {
  332. this.lines = ['mock', 'doc', 'lines']
  333. this.rev = 5
  334. this.version = 42
  335. this.ranges = { mock: 'ranges' }
  336. this.DocstoreManager.getDoc = sinon
  337. .stub()
  338. .callsArgWith(3, null, this.lines, this.rev, this.version, this.ranges)
  339. return this.ProjectEntityHandler.getDoc(project_id, doc_id, this.callback)
  340. })
  341. it('should call the docstore', function() {
  342. return this.DocstoreManager.getDoc
  343. .calledWith(project_id, doc_id)
  344. .should.equal(true)
  345. })
  346. it('should call the callback with the lines, version and rev', function() {
  347. return this.callback
  348. .calledWith(null, this.lines, this.rev, this.version, this.ranges)
  349. .should.equal(true)
  350. })
  351. })
  352. })