RequestParserTests.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386
  1. /* eslint-disable
  2. handle-callback-err,
  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 SandboxedModule = require('sandboxed-module');
  13. const sinon = require('sinon');
  14. require('chai').should();
  15. const { expect } = require('chai');
  16. const modulePath = require('path').join(__dirname, '../../../app/js/RequestParser');
  17. const tk = require("timekeeper");
  18. describe("RequestParser", function() {
  19. beforeEach(function() {
  20. tk.freeze();
  21. this.callback = sinon.stub();
  22. this.validResource = {
  23. path: "main.tex",
  24. date: "12:00 01/02/03",
  25. content: "Hello world"
  26. };
  27. this.validRequest = {
  28. compile: {
  29. token: "token-123",
  30. options: {
  31. imageName: "basicImageName/here:2017-1",
  32. compiler: "pdflatex",
  33. timeout: 42
  34. },
  35. resources: []
  36. }
  37. };
  38. return this.RequestParser = SandboxedModule.require(modulePath, { requires: {
  39. "settings-sharelatex": (this.settings = {})
  40. }
  41. });});
  42. afterEach(function() { return tk.reset(); });
  43. describe("without a top level object", function() {
  44. beforeEach(function() {
  45. return this.RequestParser.parse([], this.callback);
  46. });
  47. return it("should return an error", function() {
  48. return this.callback.calledWith("top level object should have a compile attribute")
  49. .should.equal(true);
  50. });
  51. });
  52. describe("without a compile attribute", function() {
  53. beforeEach(function() {
  54. return this.RequestParser.parse({}, this.callback);
  55. });
  56. return it("should return an error", function() {
  57. return this.callback.calledWith("top level object should have a compile attribute")
  58. .should.equal(true);
  59. });
  60. });
  61. describe("without a valid compiler", function() {
  62. beforeEach(function() {
  63. this.validRequest.compile.options.compiler = "not-a-compiler";
  64. return this.RequestParser.parse(this.validRequest, this.callback);
  65. });
  66. return it("should return an error", function() {
  67. return this.callback.calledWith("compiler attribute should be one of: pdflatex, latex, xelatex, lualatex")
  68. .should.equal(true);
  69. });
  70. });
  71. describe("without a compiler specified", function() {
  72. beforeEach(function() {
  73. delete this.validRequest.compile.options.compiler;
  74. return this.RequestParser.parse(this.validRequest, (error, data) => {
  75. this.data = data;
  76. });
  77. });
  78. return it("should set the compiler to pdflatex by default", function() {
  79. return this.data.compiler.should.equal("pdflatex");
  80. });
  81. });
  82. describe("with imageName set", function() {
  83. beforeEach(function() {
  84. return this.RequestParser.parse(this.validRequest, (error, data) => {
  85. this.data = data;
  86. });
  87. });
  88. return it("should set the imageName", function() {
  89. return this.data.imageName.should.equal("basicImageName/here:2017-1");
  90. });
  91. });
  92. describe("with flags set", function() {
  93. beforeEach(function() {
  94. this.validRequest.compile.options.flags = ["-file-line-error"];
  95. return this.RequestParser.parse(this.validRequest, (error, data) => {
  96. this.data = data;
  97. });
  98. });
  99. return it("should set the flags attribute", function() {
  100. return expect(this.data.flags).to.deep.equal(["-file-line-error"]);
  101. });
  102. });
  103. describe("with flags not specified", function() {
  104. beforeEach(function() {
  105. return this.RequestParser.parse(this.validRequest, (error, data) => {
  106. this.data = data;
  107. });
  108. });
  109. return it("it should have an empty flags list", function() {
  110. return expect(this.data.flags).to.deep.equal([]);
  111. });
  112. });
  113. describe("without a timeout specified", function() {
  114. beforeEach(function() {
  115. delete this.validRequest.compile.options.timeout;
  116. return this.RequestParser.parse(this.validRequest, (error, data) => {
  117. this.data = data;
  118. });
  119. });
  120. return it("should set the timeout to MAX_TIMEOUT", function() {
  121. return this.data.timeout.should.equal(this.RequestParser.MAX_TIMEOUT * 1000);
  122. });
  123. });
  124. describe("with a timeout larger than the maximum", function() {
  125. beforeEach(function() {
  126. this.validRequest.compile.options.timeout = this.RequestParser.MAX_TIMEOUT + 1;
  127. return this.RequestParser.parse(this.validRequest, (error, data) => {
  128. this.data = data;
  129. });
  130. });
  131. return it("should set the timeout to MAX_TIMEOUT", function() {
  132. return this.data.timeout.should.equal(this.RequestParser.MAX_TIMEOUT * 1000);
  133. });
  134. });
  135. describe("with a timeout", function() {
  136. beforeEach(function() {
  137. return this.RequestParser.parse(this.validRequest, (error, data) => {
  138. this.data = data;
  139. });
  140. });
  141. return it("should set the timeout (in milliseconds)", function() {
  142. return this.data.timeout.should.equal(this.validRequest.compile.options.timeout * 1000);
  143. });
  144. });
  145. describe("with a resource without a path", function() {
  146. beforeEach(function() {
  147. delete this.validResource.path;
  148. this.validRequest.compile.resources.push(this.validResource);
  149. return this.RequestParser.parse(this.validRequest, this.callback);
  150. });
  151. return it("should return an error", function() {
  152. return this.callback.calledWith("all resources should have a path attribute")
  153. .should.equal(true);
  154. });
  155. });
  156. describe("with a resource with a path", function() {
  157. beforeEach(function() {
  158. this.validResource.path = (this.path = "test.tex");
  159. this.validRequest.compile.resources.push(this.validResource);
  160. this.RequestParser.parse(this.validRequest, this.callback);
  161. return this.data = this.callback.args[0][1];});
  162. return it("should return the path in the parsed response", function() {
  163. return this.data.resources[0].path.should.equal(this.path);
  164. });
  165. });
  166. describe("with a resource with a malformed modified date", function() {
  167. beforeEach(function() {
  168. this.validResource.modified = "not-a-date";
  169. this.validRequest.compile.resources.push(this.validResource);
  170. return this.RequestParser.parse(this.validRequest, this.callback);
  171. });
  172. return it("should return an error", function() {
  173. return this.callback
  174. .calledWith(
  175. "resource modified date could not be understood: "+
  176. this.validResource.modified
  177. )
  178. .should.equal(true);
  179. });
  180. });
  181. describe("with a resource with a valid date", function() {
  182. beforeEach(function() {
  183. this.date = "12:00 01/02/03";
  184. this.validResource.modified = this.date;
  185. this.validRequest.compile.resources.push(this.validResource);
  186. this.RequestParser.parse(this.validRequest, this.callback);
  187. return this.data = this.callback.args[0][1];});
  188. return it("should return the date as a Javascript Date object", function() {
  189. (this.data.resources[0].modified instanceof Date).should.equal(true);
  190. return this.data.resources[0].modified.getTime().should.equal(Date.parse(this.date));
  191. });
  192. });
  193. describe("with a resource without either a content or URL attribute", function() {
  194. beforeEach(function() {
  195. delete this.validResource.url;
  196. delete this.validResource.content;
  197. this.validRequest.compile.resources.push(this.validResource);
  198. return this.RequestParser.parse(this.validRequest, this.callback);
  199. });
  200. return it("should return an error", function() {
  201. return this.callback.calledWith("all resources should have either a url or content attribute")
  202. .should.equal(true);
  203. });
  204. });
  205. describe("with a resource where the content is not a string", function() {
  206. beforeEach(function() {
  207. this.validResource.content = [];
  208. this.validRequest.compile.resources.push(this.validResource);
  209. return this.RequestParser.parse((this.validRequest), this.callback);
  210. });
  211. return it("should return an error", function() {
  212. return this.callback.calledWith("content attribute should be a string")
  213. .should.equal(true);
  214. });
  215. });
  216. describe("with a resource where the url is not a string", function() {
  217. beforeEach(function() {
  218. this.validResource.url = [];
  219. this.validRequest.compile.resources.push(this.validResource);
  220. return this.RequestParser.parse((this.validRequest), this.callback);
  221. });
  222. return it("should return an error", function() {
  223. return this.callback.calledWith("url attribute should be a string")
  224. .should.equal(true);
  225. });
  226. });
  227. describe("with a resource with a url", function() {
  228. beforeEach(function() {
  229. this.validResource.url = (this.url = "www.example.com");
  230. this.validRequest.compile.resources.push(this.validResource);
  231. this.RequestParser.parse((this.validRequest), this.callback);
  232. return this.data = this.callback.args[0][1];});
  233. return it("should return the url in the parsed response", function() {
  234. return this.data.resources[0].url.should.equal(this.url);
  235. });
  236. });
  237. describe("with a resource with a content attribute", function() {
  238. beforeEach(function() {
  239. this.validResource.content = (this.content = "Hello world");
  240. this.validRequest.compile.resources.push(this.validResource);
  241. this.RequestParser.parse((this.validRequest), this.callback);
  242. return this.data = this.callback.args[0][1];});
  243. return it("should return the content in the parsed response", function() {
  244. return this.data.resources[0].content.should.equal(this.content);
  245. });
  246. });
  247. describe("without a root resource path", function() {
  248. beforeEach(function() {
  249. delete this.validRequest.compile.rootResourcePath;
  250. this.RequestParser.parse((this.validRequest), this.callback);
  251. return this.data = this.callback.args[0][1];});
  252. return it("should set the root resource path to 'main.tex' by default", function() {
  253. return this.data.rootResourcePath.should.equal("main.tex");
  254. });
  255. });
  256. describe("with a root resource path", function() {
  257. beforeEach(function() {
  258. this.validRequest.compile.rootResourcePath = (this.path = "test.tex");
  259. this.RequestParser.parse((this.validRequest), this.callback);
  260. return this.data = this.callback.args[0][1];});
  261. return it("should return the root resource path in the parsed response", function() {
  262. return this.data.rootResourcePath.should.equal(this.path);
  263. });
  264. });
  265. describe("with a root resource path that is not a string", function() {
  266. beforeEach(function() {
  267. this.validRequest.compile.rootResourcePath = [];
  268. return this.RequestParser.parse((this.validRequest), this.callback);
  269. });
  270. return it("should return an error", function() {
  271. return this.callback.calledWith("rootResourcePath attribute should be a string")
  272. .should.equal(true);
  273. });
  274. });
  275. describe("with a root resource path that needs escaping", function() {
  276. beforeEach(function() {
  277. this.badPath = "`rm -rf foo`.tex";
  278. this.goodPath = "rm -rf foo.tex";
  279. this.validRequest.compile.rootResourcePath = this.badPath;
  280. this.validRequest.compile.resources.push({
  281. path: this.badPath,
  282. date: "12:00 01/02/03",
  283. content: "Hello world"
  284. });
  285. this.RequestParser.parse(this.validRequest, this.callback);
  286. return this.data = this.callback.args[0][1];});
  287. it("should return the escaped resource", function() {
  288. return this.data.rootResourcePath.should.equal(this.goodPath);
  289. });
  290. return it("should also escape the resource path", function() {
  291. return this.data.resources[0].path.should.equal(this.goodPath);
  292. });
  293. });
  294. describe("with a root resource path that has a relative path", function() {
  295. beforeEach(function() {
  296. this.validRequest.compile.rootResourcePath = "foo/../../bar.tex";
  297. this.RequestParser.parse(this.validRequest, this.callback);
  298. return this.data = this.callback.args[0][1];});
  299. return it("should return an error", function() {
  300. return this.callback.calledWith("relative path in root resource")
  301. .should.equal(true);
  302. });
  303. });
  304. describe("with a root resource path that has unescaped + relative path", function() {
  305. beforeEach(function() {
  306. this.validRequest.compile.rootResourcePath = "foo/#../bar.tex";
  307. this.RequestParser.parse(this.validRequest, this.callback);
  308. return this.data = this.callback.args[0][1];});
  309. return it("should return an error", function() {
  310. return this.callback.calledWith("relative path in root resource")
  311. .should.equal(true);
  312. });
  313. });
  314. return describe("with an unknown syncType", function() {
  315. beforeEach(function() {
  316. this.validRequest.compile.options.syncType = "unexpected";
  317. this.RequestParser.parse(this.validRequest, this.callback);
  318. return this.data = this.callback.args[0][1];});
  319. return it("should return an error", function() {
  320. return this.callback.calledWith("syncType attribute should be one of: full, incremental")
  321. .should.equal(true);
  322. });
  323. });
  324. });