runner.mjs 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. import * as process from 'node:process'
  2. import waitOn from 'wait-on'
  3. import { spawn } from 'node:child_process'
  4. export default function getRunner () {
  5. const type = process.env.OLIVETIN_TEST_RUNNER
  6. console.log('OLIVETIN_TEST_RUNNER env value is: ', type)
  7. switch (type) {
  8. case 'local':
  9. return new OliveTinTestRunnerStartLocalProcess()
  10. case 'vm':
  11. return new OliveTinTestRunnerVm()
  12. case 'container':
  13. return new OliveTinTestRunnerEnv()
  14. default:
  15. return new OliveTinTestRunnerStartLocalProcess()
  16. }
  17. }
  18. class OliveTinTestRunner {
  19. BASE_URL = 'http://nohost:1337/';
  20. pageGeneration = 0
  21. baseUrl() {
  22. return this.BASE_URL
  23. }
  24. metricsUrl() {
  25. return new URL('metrics', this.baseUrl());
  26. }
  27. }
  28. class OliveTinTestRunnerStartLocalProcess extends OliveTinTestRunner {
  29. async start (cfg) {
  30. if (this.ot != null && this.ot.exitCode == null) {
  31. await this.stop()
  32. }
  33. this.pageGeneration += 1
  34. let stdout = ""
  35. let stderr = ""
  36. console.log(" OliveTin starting local process...")
  37. this.ot = spawn('./../service/OliveTin', ['-configdir', 'tests/' + cfg + '/'], {
  38. env: process.env
  39. })
  40. let logStdout = false
  41. if (process.env.CI === 'true') {
  42. logStdout = true;
  43. } else {
  44. logStdout = process.env.OLIVETIN_TEST_RUNNER_LOG_STDOUT === '1'
  45. }
  46. this.ot.stdout.on('data', (data) => {
  47. stdout += data
  48. if (logStdout) {
  49. console.log(`stdout: ${data}`)
  50. }
  51. })
  52. this.ot.stderr.on('data', (data) => {
  53. stderr += data
  54. if (logStdout) {
  55. console.log(`stderr: ${data}`)
  56. }
  57. })
  58. this.ot.on('close', (code) => {
  59. if (code != null) {
  60. console.log(`OliveTin local process exited with code ${code}`)
  61. console.log(stdout)
  62. console.log(stderr)
  63. console.log(this.ot.exitCode)
  64. }
  65. })
  66. if (this.ot.exitCode == null) {
  67. this.BASE_URL = 'http://localhost:1337/'
  68. console.log(" OliveTin waiting for local process to start...")
  69. await waitOn({
  70. resources: [this.BASE_URL]
  71. })
  72. console.log(" OliveTin local process started and webUI accessible")
  73. } else {
  74. console.log(" OliveTin local process start FAILED!")
  75. console.log(stdout)
  76. console.log(stderr)
  77. console.log(this.ot.exitCode)
  78. }
  79. }
  80. async stop () {
  81. if (this.ot == null) {
  82. return
  83. }
  84. if (this.ot.exitCode != null) {
  85. console.log(' OliveTin local process tried stop(), but it already exited with code', this.ot.exitCode)
  86. } else {
  87. const stopTimeoutMs = 5000
  88. const closed = new Promise((resolve) => {
  89. this.ot.once('close', resolve)
  90. })
  91. this.ot.kill('SIGTERM')
  92. const didStopGracefully = await Promise.race([
  93. closed.then(() => true),
  94. new Promise((resolve) => setTimeout(() => resolve(false), stopTimeoutMs))
  95. ])
  96. if (!didStopGracefully) {
  97. console.log(' OliveTin local process did not exit after SIGTERM, sending SIGKILL')
  98. if (this.ot.exitCode == null) {
  99. this.ot.kill('SIGKILL')
  100. }
  101. await Promise.race([
  102. closed,
  103. new Promise((resolve) => setTimeout(resolve, stopTimeoutMs))
  104. ])
  105. }
  106. console.log(' OliveTin local process killed')
  107. }
  108. this.ot = null
  109. if (process.env.CI === 'true') {
  110. // GitHub runners seem to need a bit more time to clean up
  111. await new Promise((res) => setTimeout(res, 3000))
  112. } else {
  113. await new Promise((res) => setTimeout(res, 50))
  114. }
  115. }
  116. }
  117. class OliveTinTestRunnerEnv extends OliveTinTestRunner {
  118. constructor () {
  119. super()
  120. const IP = process.env.IP
  121. const PORT = process.env.PORT
  122. this.BASE_URL = 'http://' + IP + ':' + PORT + '/'
  123. console.log('Runner ENV endpoint: ' + this.BASE_URL)
  124. }
  125. async start () {
  126. await waitOn({
  127. resources: [this.BASE_URL]
  128. })
  129. }
  130. async stop () {
  131. }
  132. }
  133. class OliveTinTestRunnerVm extends OliveTinTestRunnerEnv {
  134. constructor() {
  135. super()
  136. }
  137. async start (cfg) {
  138. console.log("vagrant changing config")
  139. spawn('vagrant', ['ssh', '-c', '"ln -sf /etc/OliveTin/ /opt/OliveTin-configs/' + cfg + '/config.yaml"'])
  140. spawn('vagrant', ['ssh', '-c', '"systemctl restart OliveTin"'])
  141. return null
  142. }
  143. }