SafeExec.test.js 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. import { beforeEach, chai, describe, expect, it, vi } from 'vitest'
  2. const should = chai.should()
  3. const modulePath = '../../../app/js/SafeExec.js'
  4. describe('SafeExec', function () {
  5. let settings, options, safeExec
  6. beforeEach(async function () {
  7. settings = { enableConversions: true }
  8. options = { timeout: 10 * 1000, killSignal: 'SIGTERM' }
  9. vi.doMock('@overleaf/settings', () => ({
  10. default: settings,
  11. }))
  12. safeExec = (await import(modulePath)).default
  13. })
  14. describe('safeExec', function () {
  15. it('should execute a valid command', async function () {
  16. await new Promise(resolve => {
  17. safeExec(['/bin/echo', 'hello'], options, (err, stdout, stderr) => {
  18. stdout.should.equal('hello\n')
  19. stderr.should.equal('')
  20. should.not.exist(err)
  21. resolve()
  22. })
  23. })
  24. })
  25. it('should error when conversions are disabled', async function () {
  26. await new Promise(resolve => {
  27. settings.enableConversions = false
  28. safeExec(['/bin/echo', 'hello'], options, err => {
  29. expect(err).to.exist
  30. resolve()
  31. })
  32. })
  33. })
  34. it('should execute a command with non-zero exit status', async function () {
  35. await new Promise(resolve => {
  36. safeExec(['/usr/bin/env', 'false'], options, err => {
  37. expect(err).to.exist
  38. expect(err.name).to.equal('FailedCommandError')
  39. expect(err.code).to.equal(1)
  40. expect(err.stdout).to.equal('')
  41. expect(err.stderr).to.equal('')
  42. resolve()
  43. })
  44. })
  45. })
  46. it('should handle an invalid command', async function () {
  47. await new Promise(resolve => {
  48. safeExec(['/bin/foobar'], options, err => {
  49. err.code.should.equal('ENOENT')
  50. resolve()
  51. })
  52. })
  53. })
  54. it('should handle a command that runs too long', async function () {
  55. await new Promise(resolve => {
  56. safeExec(
  57. ['/bin/sleep', '10'],
  58. { timeout: 500, killSignal: 'SIGTERM' },
  59. err => {
  60. expect(err).to.exist
  61. expect(err.name).to.equal('FailedCommandError')
  62. expect(err.code).to.equal('SIGTERM')
  63. resolve()
  64. }
  65. )
  66. })
  67. })
  68. })
  69. describe('as a promise', function () {
  70. beforeEach(function () {
  71. safeExec = safeExec.promises
  72. })
  73. it('should execute a valid command', async function () {
  74. const { stdout, stderr } = await safeExec(['/bin/echo', 'hello'], options)
  75. stdout.should.equal('hello\n')
  76. stderr.should.equal('')
  77. })
  78. it('should throw a ConversionsDisabledError when appropriate', async function () {
  79. settings.enableConversions = false
  80. try {
  81. await safeExec(['/bin/echo', 'hello'], options)
  82. } catch (err) {
  83. expect(err.name).to.equal('ConversionsDisabledError')
  84. return
  85. }
  86. expect('method did not throw an error').not.to.exist
  87. })
  88. it('should throw a FailedCommandError when appropriate', async function () {
  89. try {
  90. await safeExec(['/usr/bin/env', 'false'], options)
  91. } catch (err) {
  92. expect(err.name).to.equal('FailedCommandError')
  93. expect(err.code).to.equal(1)
  94. return
  95. }
  96. expect('method did not throw an error').not.to.exist
  97. })
  98. })
  99. })