runner.mjs 4.2 KB

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