HttpControllerTests.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450
  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. * 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 SandboxedModule = require('sandboxed-module');
  13. const {
  14. assert
  15. } = require("chai");
  16. const sinon = require('sinon');
  17. const chai = require('chai');
  18. chai.should();
  19. const {
  20. expect
  21. } = chai;
  22. const modulePath = require('path').join(__dirname, '../../../app/js/HttpController');
  23. const {
  24. ObjectId
  25. } = require("mongojs");
  26. describe("HttpController", function() {
  27. beforeEach(function() {
  28. this.HttpController = SandboxedModule.require(modulePath, { requires: {
  29. "./DocManager": (this.DocManager = {}),
  30. "./DocArchiveManager": (this.DocArchiveManager = {}),
  31. "logger-sharelatex": (this.logger = { log: sinon.stub(), error: sinon.stub() }),
  32. "./HealthChecker": {}
  33. }
  34. });
  35. this.res = { send: sinon.stub(), json: sinon.stub(), setHeader:sinon.stub() };
  36. this.res.status = sinon.stub().returns(this.res);
  37. this.req = { query:{}};
  38. this.next = sinon.stub();
  39. this.project_id = "mock-project-id";
  40. this.doc_id = "mock-doc-id";
  41. this.doc = {
  42. _id: this.doc_id,
  43. lines: ["mock", "lines", " here", "", "", " spaces "],
  44. version: 42,
  45. rev: 5
  46. };
  47. return this.deletedDoc = {
  48. deleted:true,
  49. _id: this.doc_id,
  50. lines: ["mock", "lines", " here", "", "", " spaces "],
  51. version: 42,
  52. rev: 5
  53. };});
  54. describe("getDoc", function() {
  55. describe("without deleted docs", function() {
  56. beforeEach(function() {
  57. this.req.params = {
  58. project_id: this.project_id,
  59. doc_id: this.doc_id
  60. };
  61. this.DocManager.getFullDoc = sinon.stub().callsArgWith(2, null, this.doc);
  62. return this.HttpController.getDoc(this.req, this.res, this.next);
  63. });
  64. it("should get the document with the version (including deleted)", function() {
  65. return this.DocManager.getFullDoc
  66. .calledWith(this.project_id, this.doc_id)
  67. .should.equal(true);
  68. });
  69. return it("should return the doc as JSON", function() {
  70. return this.res.json
  71. .calledWith({
  72. _id: this.doc_id,
  73. lines: this.doc.lines,
  74. rev: this.doc.rev,
  75. version: this.doc.version
  76. })
  77. .should.equal(true);
  78. });
  79. });
  80. return describe("which is deleted", function() {
  81. beforeEach(function() {
  82. this.req.params = {
  83. project_id: this.project_id,
  84. doc_id: this.doc_id
  85. };
  86. return this.DocManager.getFullDoc = sinon.stub().callsArgWith(2, null, this.deletedDoc);
  87. });
  88. it("should get the doc from the doc manager", function() {
  89. this.HttpController.getDoc(this.req, this.res, this.next);
  90. return this.DocManager.getFullDoc.calledWith(this.project_id, this.doc_id).should.equal(true);
  91. });
  92. it("should return 404 if the query string delete is not set ", function() {
  93. this.HttpController.getDoc(this.req, this.res, this.next);
  94. return this.res.send.calledWith(404).should.equal(true);
  95. });
  96. return it("should return the doc as JSON if include_deleted is set to true", function() {
  97. this.req.query.include_deleted = "true";
  98. this.HttpController.getDoc(this.req, this.res, this.next);
  99. return this.res.json
  100. .calledWith({
  101. _id: this.doc_id,
  102. lines: this.doc.lines,
  103. rev: this.doc.rev,
  104. deleted: true,
  105. version: this.doc.version
  106. })
  107. .should.equal(true);
  108. });
  109. });
  110. });
  111. describe("getRawDoc", function() {
  112. beforeEach(function() {
  113. this.req.params = {
  114. project_id: this.project_id,
  115. doc_id: this.doc_id
  116. };
  117. this.DocManager.getDocLines = sinon.stub().callsArgWith(2, null, this.doc);
  118. return this.HttpController.getRawDoc(this.req, this.res, this.next);
  119. });
  120. it("should get the document without the version", function() {
  121. return this.DocManager.getDocLines
  122. .calledWith(this.project_id, this.doc_id)
  123. .should.equal(true);
  124. });
  125. it("should set the content type header", function() {
  126. return this.res.setHeader.calledWith('content-type', 'text/plain').should.equal(true);
  127. });
  128. return it("should send the raw version of the doc", function() {
  129. return assert.deepEqual(this.res.send.args[0][0], `${this.doc.lines[0]}\n${this.doc.lines[1]}\n${this.doc.lines[2]}\n${this.doc.lines[3]}\n${this.doc.lines[4]}\n${this.doc.lines[5]}`);
  130. });
  131. });
  132. describe("getAllDocs", function() {
  133. describe("normally", function() {
  134. beforeEach(function() {
  135. this.req.params =
  136. {project_id: this.project_id};
  137. this.docs = [{
  138. _id: ObjectId(),
  139. lines: ["mock", "lines", "one"],
  140. rev: 2
  141. }, {
  142. _id: ObjectId(),
  143. lines: ["mock", "lines", "two"],
  144. rev: 4
  145. }];
  146. this.DocManager.getAllNonDeletedDocs = sinon.stub().callsArgWith(2, null, this.docs);
  147. return this.HttpController.getAllDocs(this.req, this.res, this.next);
  148. });
  149. it("should get all the (non-deleted) docs", function() {
  150. return this.DocManager.getAllNonDeletedDocs
  151. .calledWith(this.project_id, {lines: true, rev: true})
  152. .should.equal(true);
  153. });
  154. return it("should return the doc as JSON", function() {
  155. return this.res.json
  156. .calledWith([{
  157. _id: this.docs[0]._id.toString(),
  158. lines: this.docs[0].lines,
  159. rev: this.docs[0].rev
  160. }, {
  161. _id: this.docs[1]._id.toString(),
  162. lines: this.docs[1].lines,
  163. rev: this.docs[1].rev
  164. }])
  165. .should.equal(true);
  166. });
  167. });
  168. return describe("with a null doc", function() {
  169. beforeEach(function() {
  170. this.req.params =
  171. {project_id: this.project_id};
  172. this.docs = [{
  173. _id: ObjectId(),
  174. lines: ["mock", "lines", "one"],
  175. rev: 2
  176. },
  177. null,
  178. {
  179. _id: ObjectId(),
  180. lines: ["mock", "lines", "two"],
  181. rev: 4
  182. }];
  183. this.DocManager.getAllNonDeletedDocs = sinon.stub().callsArgWith(2, null, this.docs);
  184. return this.HttpController.getAllDocs(this.req, this.res, this.next);
  185. });
  186. it("should return the non null docs as JSON", function() {
  187. return this.res.json
  188. .calledWith([{
  189. _id: this.docs[0]._id.toString(),
  190. lines: this.docs[0].lines,
  191. rev: this.docs[0].rev
  192. }, {
  193. _id: this.docs[2]._id.toString(),
  194. lines: this.docs[2].lines,
  195. rev: this.docs[2].rev
  196. }])
  197. .should.equal(true);
  198. });
  199. return it("should log out an error", function() {
  200. return this.logger.error
  201. .calledWith({
  202. err: sinon.match.has('message', "null doc"),
  203. project_id: this.project_id
  204. },
  205. "encountered null doc"
  206. )
  207. .should.equal(true);
  208. });
  209. });
  210. });
  211. describe("getAllRanges", function() { return describe("normally", function() {
  212. beforeEach(function() {
  213. this.req.params =
  214. {project_id: this.project_id};
  215. this.docs = [{
  216. _id: ObjectId(),
  217. ranges: {"mock_ranges": "one"}
  218. }, {
  219. _id: ObjectId(),
  220. ranges: {"mock_ranges": "two"}
  221. }];
  222. this.DocManager.getAllNonDeletedDocs = sinon.stub().callsArgWith(2, null, this.docs);
  223. return this.HttpController.getAllRanges(this.req, this.res, this.next);
  224. });
  225. it("should get all the (non-deleted) doc ranges", function() {
  226. return this.DocManager.getAllNonDeletedDocs
  227. .calledWith(this.project_id, {ranges: true})
  228. .should.equal(true);
  229. });
  230. return it("should return the doc as JSON", function() {
  231. return this.res.json
  232. .calledWith([{
  233. _id: this.docs[0]._id.toString(),
  234. ranges: this.docs[0].ranges
  235. }, {
  236. _id: this.docs[1]._id.toString(),
  237. ranges: this.docs[1].ranges
  238. }])
  239. .should.equal(true);
  240. });
  241. }); });
  242. describe("updateDoc", function() {
  243. beforeEach(function() {
  244. return this.req.params = {
  245. project_id: this.project_id,
  246. doc_id: this.doc_id
  247. };
  248. });
  249. describe("when the doc lines exist and were updated", function() {
  250. beforeEach(function() {
  251. this.req.body = {
  252. lines: (this.lines = ["hello", "world"]),
  253. version: (this.version = 42),
  254. ranges: (this.ranges = { changes: "mock" })
  255. };
  256. this.DocManager.updateDoc = sinon.stub().yields(null, true, (this.rev = 5));
  257. return this.HttpController.updateDoc(this.req, this.res, this.next);
  258. });
  259. it("should update the document", function() {
  260. return this.DocManager.updateDoc
  261. .calledWith(this.project_id, this.doc_id, this.lines, this.version, this.ranges)
  262. .should.equal(true);
  263. });
  264. return it("should return a modified status", function() {
  265. return this.res.json
  266. .calledWith({modified: true, rev: this.rev})
  267. .should.equal(true);
  268. });
  269. });
  270. describe("when the doc lines exist and were not updated", function() {
  271. beforeEach(function() {
  272. this.req.body = {
  273. lines: (this.lines = ["hello", "world"]),
  274. version: (this.version = 42),
  275. ranges: {}
  276. };
  277. this.DocManager.updateDoc = sinon.stub().yields(null, false, (this.rev = 5));
  278. return this.HttpController.updateDoc(this.req, this.res, this.next);
  279. });
  280. return it("should return a modified status", function() {
  281. return this.res.json
  282. .calledWith({modified: false, rev: this.rev})
  283. .should.equal(true);
  284. });
  285. });
  286. describe("when the doc lines are not provided", function() {
  287. beforeEach(function() {
  288. this.req.body = { version: 42, ranges: {} };
  289. this.DocManager.updateDoc = sinon.stub().yields(null, false);
  290. return this.HttpController.updateDoc(this.req, this.res, this.next);
  291. });
  292. it("should not update the document", function() {
  293. return this.DocManager.updateDoc.called.should.equal(false);
  294. });
  295. return it("should return a 400 (bad request) response", function() {
  296. return this.res.send
  297. .calledWith(400)
  298. .should.equal(true);
  299. });
  300. });
  301. describe("when the doc version are not provided", function() {
  302. beforeEach(function() {
  303. this.req.body = { version: 42, lines: ["hello world"] };
  304. this.DocManager.updateDoc = sinon.stub().yields(null, false);
  305. return this.HttpController.updateDoc(this.req, this.res, this.next);
  306. });
  307. it("should not update the document", function() {
  308. return this.DocManager.updateDoc.called.should.equal(false);
  309. });
  310. return it("should return a 400 (bad request) response", function() {
  311. return this.res.send
  312. .calledWith(400)
  313. .should.equal(true);
  314. });
  315. });
  316. describe("when the doc ranges is not provided", function() {
  317. beforeEach(function() {
  318. this.req.body = { lines : [ "foo" ], version: 42 };
  319. this.DocManager.updateDoc = sinon.stub().yields(null, false);
  320. return this.HttpController.updateDoc(this.req, this.res, this.next);
  321. });
  322. it("should not update the document", function() {
  323. return this.DocManager.updateDoc.called.should.equal(false);
  324. });
  325. return it("should return a 400 (bad request) response", function() {
  326. return this.res.send
  327. .calledWith(400)
  328. .should.equal(true);
  329. });
  330. });
  331. return describe("when the doc body is too large", function() {
  332. beforeEach(function() {
  333. this.req.body = {
  334. lines: (this.lines = Array(2049).fill('a'.repeat(1024))),
  335. version: (this.version = 42),
  336. ranges: (this.ranges = { changes: "mock" })
  337. };
  338. return this.HttpController.updateDoc(this.req, this.res, this.next);
  339. });
  340. it("should return a 413 (too large) response", function() {
  341. return sinon.assert.calledWith(this.res.status, 413);
  342. });
  343. return it("should report that the document body is too large", function() {
  344. return sinon.assert.calledWith(this.res.send, "document body too large");
  345. });
  346. });
  347. });
  348. describe("deleteDoc", function() {
  349. beforeEach(function() {
  350. this.req.params = {
  351. project_id: this.project_id,
  352. doc_id: this.doc_id
  353. };
  354. this.DocManager.deleteDoc = sinon.stub().callsArg(2);
  355. return this.HttpController.deleteDoc(this.req, this.res, this.next);
  356. });
  357. it("should delete the document", function() {
  358. return this.DocManager.deleteDoc
  359. .calledWith(this.project_id, this.doc_id)
  360. .should.equal(true);
  361. });
  362. return it("should return a 204 (No Content)", function() {
  363. return this.res.send
  364. .calledWith(204)
  365. .should.equal(true);
  366. });
  367. });
  368. describe("archiveAllDocs", function() {
  369. beforeEach(function() {
  370. this.req.params =
  371. {project_id: this.project_id};
  372. this.DocArchiveManager.archiveAllDocs = sinon.stub().callsArg(1);
  373. return this.HttpController.archiveAllDocs(this.req, this.res, this.next);
  374. });
  375. it("should archive the project", function() {
  376. return this.DocArchiveManager.archiveAllDocs
  377. .calledWith(this.project_id)
  378. .should.equal(true);
  379. });
  380. return it("should return a 204 (No Content)", function() {
  381. return this.res.send
  382. .calledWith(204)
  383. .should.equal(true);
  384. });
  385. });
  386. return describe("destroyAllDocs", function() {
  387. beforeEach(function() {
  388. this.req.params =
  389. {project_id: this.project_id};
  390. this.DocArchiveManager.destroyAllDocs = sinon.stub().callsArg(1);
  391. return this.HttpController.destroyAllDocs(this.req, this.res, this.next);
  392. });
  393. it("should destroy the docs", function() {
  394. return sinon.assert.calledWith(this.DocArchiveManager.destroyAllDocs, this.project_id);
  395. });
  396. return it("should return 204", function() {
  397. return sinon.assert.calledWith(this.res.send, 204);
  398. });
  399. });
  400. });