UrlCachingTests.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449
  1. /* eslint-disable
  2. no-unused-vars,
  3. */
  4. // TODO: This file was created by bulk-decaffeinate.
  5. // Fix any style issues and re-enable lint.
  6. /*
  7. * decaffeinate suggestions:
  8. * DS102: Remove unnecessary code created because of implicit returns
  9. * DS207: Consider shorter variations of null checks
  10. * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
  11. */
  12. const express = require('express')
  13. const Path = require('node:path')
  14. const Client = require('./helpers/Client')
  15. const sinon = require('sinon')
  16. const ClsiApp = require('./helpers/ClsiApp')
  17. const Server = {
  18. run() {
  19. const app = express()
  20. const staticServer = express.static(Path.join(__dirname, '../fixtures/'))
  21. const alreadyFailed = new Map()
  22. app.get('/fail/:times/:id', (req, res) => {
  23. this.getFile(req.url)
  24. const soFar = alreadyFailed.get(req.params.id) || 0
  25. const wanted = parseInt(req.params.times, 10)
  26. if (soFar < wanted) {
  27. alreadyFailed.set(req.params.id, soFar + 1)
  28. res.status(503).end()
  29. } else {
  30. res.send('THE CONTENT')
  31. }
  32. })
  33. app.get('/:random_id/*', (req, res, next) => {
  34. this.getFile(req.url)
  35. req.url = `/${req.params[0]}`
  36. return staticServer(req, res, next)
  37. })
  38. Client.startFakeFilestoreApp(app)
  39. },
  40. getFile() {},
  41. randomId() {
  42. return Math.random().toString(16).slice(2)
  43. },
  44. }
  45. describe('Url Caching', function () {
  46. Server.run()
  47. describe('Retries', function () {
  48. before(function (done) {
  49. this.project_id = Client.randomId()
  50. this.happyFile = `${Server.randomId()}/lion.png`
  51. this.retryFileOnce = `fail/1/${Server.randomId()}`
  52. this.retryFileTwice = `fail/2/${Server.randomId()}`
  53. this.fatalFile = `fail/42/${Server.randomId()}`
  54. this.request = {
  55. resources: [
  56. {
  57. path: 'main.tex',
  58. content: `\
  59. \\documentclass{article}
  60. \\usepackage{graphicx}
  61. \\begin{document}
  62. \\includegraphics{lion.png}
  63. \\end{document}\
  64. `,
  65. },
  66. {
  67. path: 'lion.png',
  68. url: `http://filestore/${this.happyFile}`,
  69. },
  70. {
  71. path: 'foo.tex',
  72. url: `http://filestore/${this.retryFileOnce}`,
  73. },
  74. {
  75. path: 'foo.tex',
  76. url: `http://filestore/${this.retryFileTwice}`,
  77. },
  78. {
  79. path: 'foo.tex',
  80. url: `http://filestore/${this.fatalFile}`,
  81. },
  82. ],
  83. }
  84. sinon.spy(Server, 'getFile')
  85. ClsiApp.ensureRunning(() => {
  86. Client.compile(this.project_id, this.request, (error, res, body) => {
  87. this.error = error
  88. this.res = res
  89. this.body = body
  90. done()
  91. })
  92. })
  93. })
  94. after(function () {
  95. Server.getFile.restore()
  96. })
  97. function expectNFilestoreRequests(file, count) {
  98. Server.getFile.args.filter(a => a[0] === file).should.have.length(count)
  99. }
  100. it('should download the happy file once', function () {
  101. expectNFilestoreRequests(`/${this.happyFile}`, 1)
  102. })
  103. it('should retry the download of the unhappy files', function () {
  104. expectNFilestoreRequests(`/${this.retryFileOnce}`, 2)
  105. expectNFilestoreRequests(`/${this.retryFileTwice}`, 3)
  106. expectNFilestoreRequests(`/${this.fatalFile}`, 3)
  107. })
  108. })
  109. describe('Downloading an image for the first time', function () {
  110. before(function (done) {
  111. this.project_id = Client.randomId()
  112. this.file = `${Server.randomId()}/lion.png`
  113. this.request = {
  114. resources: [
  115. {
  116. path: 'main.tex',
  117. content: `\
  118. \\documentclass{article}
  119. \\usepackage{graphicx}
  120. \\begin{document}
  121. \\includegraphics{lion.png}
  122. \\end{document}\
  123. `,
  124. },
  125. {
  126. path: 'lion.png',
  127. url: `http://filestore/${this.file}`,
  128. },
  129. ],
  130. }
  131. sinon.spy(Server, 'getFile')
  132. return ClsiApp.ensureRunning(() => {
  133. return Client.compile(
  134. this.project_id,
  135. this.request,
  136. (error, res, body) => {
  137. this.error = error
  138. this.res = res
  139. this.body = body
  140. return done()
  141. }
  142. )
  143. })
  144. })
  145. afterEach(function () {
  146. return Server.getFile.restore()
  147. })
  148. return it('should download the image', function () {
  149. return Server.getFile.calledWith(`/${this.file}`).should.equal(true)
  150. })
  151. })
  152. describe('When an image is in the cache and the last modified date is unchanged', function () {
  153. before(function (done) {
  154. this.project_id = Client.randomId()
  155. this.file = `${Server.randomId()}/lion.png`
  156. this.request = {
  157. resources: [
  158. {
  159. path: 'main.tex',
  160. content: `\
  161. \\documentclass{article}
  162. \\usepackage{graphicx}
  163. \\begin{document}
  164. \\includegraphics{lion.png}
  165. \\end{document}\
  166. `,
  167. },
  168. (this.image_resource = {
  169. path: 'lion.png',
  170. url: `http://filestore/${this.file}`,
  171. modified: Date.now(),
  172. }),
  173. ],
  174. }
  175. return Client.compile(
  176. this.project_id,
  177. this.request,
  178. (error, res, body) => {
  179. this.error = error
  180. this.res = res
  181. this.body = body
  182. sinon.spy(Server, 'getFile')
  183. return Client.compile(
  184. this.project_id,
  185. this.request,
  186. (error1, res1, body1) => {
  187. this.error = error1
  188. this.res = res1
  189. this.body = body1
  190. return done()
  191. }
  192. )
  193. }
  194. )
  195. })
  196. after(function () {
  197. return Server.getFile.restore()
  198. })
  199. return it('should not download the image again', function () {
  200. return Server.getFile.called.should.equal(false)
  201. })
  202. })
  203. describe('When an image is in the cache and the last modified date is advanced', function () {
  204. before(function (done) {
  205. this.project_id = Client.randomId()
  206. this.file = `${Server.randomId()}/lion.png`
  207. this.request = {
  208. resources: [
  209. {
  210. path: 'main.tex',
  211. content: `\
  212. \\documentclass{article}
  213. \\usepackage{graphicx}
  214. \\begin{document}
  215. \\includegraphics{lion.png}
  216. \\end{document}\
  217. `,
  218. },
  219. (this.image_resource = {
  220. path: 'lion.png',
  221. url: `http://filestore/${this.file}`,
  222. modified: (this.last_modified = Date.now()),
  223. }),
  224. ],
  225. }
  226. return Client.compile(
  227. this.project_id,
  228. this.request,
  229. (error, res, body) => {
  230. this.error = error
  231. this.res = res
  232. this.body = body
  233. sinon.spy(Server, 'getFile')
  234. this.image_resource.modified = new Date(this.last_modified + 3000)
  235. return Client.compile(
  236. this.project_id,
  237. this.request,
  238. (error1, res1, body1) => {
  239. this.error = error1
  240. this.res = res1
  241. this.body = body1
  242. return done()
  243. }
  244. )
  245. }
  246. )
  247. })
  248. afterEach(function () {
  249. return Server.getFile.restore()
  250. })
  251. return it('should download the image again', function () {
  252. return Server.getFile.called.should.equal(true)
  253. })
  254. })
  255. describe('When an image is in the cache and the last modified date is further in the past', function () {
  256. before(function (done) {
  257. this.project_id = Client.randomId()
  258. this.file = `${Server.randomId()}/lion.png`
  259. this.request = {
  260. resources: [
  261. {
  262. path: 'main.tex',
  263. content: `\
  264. \\documentclass{article}
  265. \\usepackage{graphicx}
  266. \\begin{document}
  267. \\includegraphics{lion.png}
  268. \\end{document}\
  269. `,
  270. },
  271. (this.image_resource = {
  272. path: 'lion.png',
  273. url: `http://filestore/${this.file}`,
  274. modified: (this.last_modified = Date.now()),
  275. }),
  276. ],
  277. }
  278. return Client.compile(
  279. this.project_id,
  280. this.request,
  281. (error, res, body) => {
  282. this.error = error
  283. this.res = res
  284. this.body = body
  285. sinon.spy(Server, 'getFile')
  286. this.image_resource.modified = new Date(this.last_modified - 3000)
  287. return Client.compile(
  288. this.project_id,
  289. this.request,
  290. (error1, res1, body1) => {
  291. this.error = error1
  292. this.res = res1
  293. this.body = body1
  294. return done()
  295. }
  296. )
  297. }
  298. )
  299. })
  300. afterEach(function () {
  301. return Server.getFile.restore()
  302. })
  303. return it('should download the other revision', function () {
  304. return Server.getFile.called.should.equal(true)
  305. })
  306. })
  307. describe('When an image is in the cache and the last modified date is not specified', function () {
  308. before(function (done) {
  309. this.project_id = Client.randomId()
  310. this.file = `${Server.randomId()}/lion.png`
  311. this.request = {
  312. resources: [
  313. {
  314. path: 'main.tex',
  315. content: `\
  316. \\documentclass{article}
  317. \\usepackage{graphicx}
  318. \\begin{document}
  319. \\includegraphics{lion.png}
  320. \\end{document}\
  321. `,
  322. },
  323. (this.image_resource = {
  324. path: 'lion.png',
  325. url: `http://filestore/${this.file}`,
  326. modified: (this.last_modified = Date.now()),
  327. }),
  328. ],
  329. }
  330. return Client.compile(
  331. this.project_id,
  332. this.request,
  333. (error, res, body) => {
  334. this.error = error
  335. this.res = res
  336. this.body = body
  337. sinon.spy(Server, 'getFile')
  338. delete this.image_resource.modified
  339. return Client.compile(
  340. this.project_id,
  341. this.request,
  342. (error1, res1, body1) => {
  343. this.error = error1
  344. this.res = res1
  345. this.body = body1
  346. return done()
  347. }
  348. )
  349. }
  350. )
  351. })
  352. afterEach(function () {
  353. return Server.getFile.restore()
  354. })
  355. return it('should download the image again', function () {
  356. return Server.getFile.called.should.equal(true)
  357. })
  358. })
  359. return describe('After clearing the cache', function () {
  360. before(function (done) {
  361. this.project_id = Client.randomId()
  362. this.file = `${Server.randomId()}/lion.png`
  363. this.request = {
  364. resources: [
  365. {
  366. path: 'main.tex',
  367. content: `\
  368. \\documentclass{article}
  369. \\usepackage{graphicx}
  370. \\begin{document}
  371. \\includegraphics{lion.png}
  372. \\end{document}\
  373. `,
  374. },
  375. (this.image_resource = {
  376. path: 'lion.png',
  377. url: `http://filestore/${this.file}`,
  378. modified: (this.last_modified = Date.now()),
  379. }),
  380. ],
  381. }
  382. return Client.compile(this.project_id, this.request, error => {
  383. if (error != null) {
  384. throw error
  385. }
  386. return Client.clearCache(this.project_id, (error, res, body) => {
  387. if (error != null) {
  388. throw error
  389. }
  390. sinon.spy(Server, 'getFile')
  391. return Client.compile(
  392. this.project_id,
  393. this.request,
  394. (error1, res1, body1) => {
  395. this.error = error1
  396. this.res = res1
  397. this.body = body1
  398. return done()
  399. }
  400. )
  401. })
  402. })
  403. })
  404. afterEach(function () {
  405. return Server.getFile.restore()
  406. })
  407. return it('should download the image again', function () {
  408. return Server.getFile.called.should.equal(true)
  409. })
  410. })
  411. })