SmokeTests.mjs 2.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. import fs from 'fs'
  2. import Path from 'path'
  3. import Settings from '@overleaf/settings'
  4. import { getCsrfTokenForFactory } from './support/Csrf.mjs'
  5. import { SmokeTestFailure } from './support/Errors.mjs'
  6. import {
  7. requestFactory,
  8. assertHasStatusCode,
  9. } from './support/requestHelper.mjs'
  10. import { processWithTimeout } from './support/timeoutHelper.mjs'
  11. const STEP_TIMEOUT = Settings.smokeTest.stepTimeout
  12. const PATH_STEPS = Path.join(import.meta.dirname, './steps')
  13. const sortedSteps = fs.readdirSync(PATH_STEPS).sort()
  14. const STEPS = []
  15. for (const name of sortedSteps) {
  16. const step = (await import(Path.join(PATH_STEPS, name))).default
  17. step.name = Path.basename(name, '.mjs')
  18. STEPS.push(step)
  19. }
  20. async function runSmokeTests({ isAborted, stats }) {
  21. let lastStep = stats.start
  22. function completeStep(key) {
  23. const step = Date.now()
  24. stats.steps.push({ [key]: step - lastStep })
  25. lastStep = step
  26. }
  27. const request = requestFactory({ timeout: STEP_TIMEOUT })
  28. const getCsrfTokenFor = getCsrfTokenForFactory({ request })
  29. const ctx = {
  30. assertHasStatusCode,
  31. getCsrfTokenFor,
  32. processWithTimeout,
  33. request,
  34. stats,
  35. timeout: STEP_TIMEOUT,
  36. }
  37. const cleanupSteps = []
  38. async function runAndTrack(id, fn) {
  39. let result
  40. try {
  41. result = await fn(ctx)
  42. } catch (e) {
  43. throw new SmokeTestFailure(`${id} failed`, {}, e)
  44. } finally {
  45. completeStep(id)
  46. }
  47. Object.assign(ctx, result)
  48. }
  49. completeStep('init')
  50. let err
  51. try {
  52. for (const step of STEPS) {
  53. if (isAborted()) break
  54. const { name, run, cleanup } = step
  55. if (cleanup) cleanupSteps.unshift({ name, cleanup })
  56. await runAndTrack(`run.${name}`, run)
  57. }
  58. } catch (e) {
  59. err = e
  60. }
  61. const cleanupErrors = []
  62. for (const step of cleanupSteps) {
  63. const { name, cleanup } = step
  64. try {
  65. await runAndTrack(`cleanup.${name}`, cleanup)
  66. } catch (e) {
  67. // keep going with cleanup
  68. cleanupErrors.push(e)
  69. }
  70. }
  71. if (err) throw err
  72. if (cleanupErrors.length) {
  73. if (cleanupErrors.length === 1) throw cleanupErrors[0]
  74. throw new SmokeTestFailure('multiple cleanup steps failed', {
  75. stats,
  76. cleanupErrors,
  77. })
  78. }
  79. }
  80. export default { runSmokeTests, SmokeTestFailure }