dashboardSupervisor.test.ts 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. import { describe, expect, it } from 'vitest'
  2. import {
  3. DashboardSupervisor,
  4. DEFAULT_DASHBOARD_USERNAME,
  5. } from '../../src/server/dashboardSupervisor.js'
  6. function supervisor(overrides: {
  7. values?: Record<string, string>
  8. running?: boolean
  9. runningHost?: '127.0.0.1' | '0.0.0.0'
  10. allowLan?: boolean
  11. } = {}) {
  12. const values = { ...overrides.values }
  13. let running = overrides.running ?? false
  14. let runningHost = overrides.runningHost ?? '127.0.0.1'
  15. const lanProbeHost = '192.168.1.20'
  16. const calls: string[][] = []
  17. const launches: string[][] = []
  18. const instance = new DashboardSupervisor({
  19. allowLan: overrides.allowLan ?? false,
  20. lanProbeHost,
  21. run(args) {
  22. calls.push([...args])
  23. if (args[0] === 'config' && args[1] === 'get') return values[args[2]] ?? ''
  24. if (args[0] === 'config' && args[1] === 'set') {
  25. values[args[2]] = args[3]
  26. return ''
  27. }
  28. if (args[0] === 'dashboard' && args[1] === '--stop') {
  29. running = false
  30. return ''
  31. }
  32. return ''
  33. },
  34. launch(args) {
  35. launches.push([...args])
  36. running = true
  37. runningHost = args[2] as typeof runningHost
  38. },
  39. probe: async (host) => running && (
  40. host === '127.0.0.1'
  41. || (host === lanProbeHost && runningHost === '0.0.0.0')
  42. ),
  43. log: () => undefined,
  44. })
  45. return { instance, calls, launches, values }
  46. }
  47. describe('DashboardSupervisor', () => {
  48. it('configures the requested default credentials and starts an unavailable dashboard', async () => {
  49. const value = supervisor()
  50. await value.instance.checkNow()
  51. expect(value.values['dashboard.basic_auth.username']).toBe(DEFAULT_DASHBOARD_USERNAME)
  52. expect(value.values['dashboard.basic_auth.password_hash']).toMatch(/^scrypt\$16384\$8\$1\$/)
  53. expect(value.values['dashboard.basic_auth.secret']).toMatch(/.{32,}/)
  54. expect(value.launches).toEqual([['dashboard', '--host', '127.0.0.1', '--no-open']])
  55. })
  56. it('does not overwrite configured dashboard credentials', async () => {
  57. const value = supervisor({
  58. running: true,
  59. values: {
  60. 'dashboard.basic_auth.username': 'operator',
  61. 'dashboard.basic_auth.password_hash': 'scrypt$existing',
  62. 'dashboard.basic_auth.secret': 'configured-secret',
  63. },
  64. })
  65. await value.instance.checkNow()
  66. expect(value.calls.filter((args) => args[1] === 'set')).toEqual([])
  67. expect(value.launches).toEqual([])
  68. })
  69. it('restarts a running dashboard after filling missing authentication and uses LAN binding when enabled', async () => {
  70. const value = supervisor({ running: true, allowLan: true })
  71. await value.instance.checkNow()
  72. expect(value.calls).toContainEqual(['dashboard', '--stop'])
  73. expect(value.launches).toEqual([['dashboard', '--host', '0.0.0.0', '--no-open']])
  74. })
  75. it('moves an authenticated loopback dashboard onto the LAN when managed installation requires it', async () => {
  76. const value = supervisor({
  77. running: true,
  78. runningHost: '127.0.0.1',
  79. allowLan: true,
  80. values: {
  81. 'dashboard.basic_auth.username': 'operator',
  82. 'dashboard.basic_auth.password_hash': 'scrypt$existing',
  83. 'dashboard.basic_auth.secret': 'configured-secret',
  84. },
  85. })
  86. await value.instance.checkNow()
  87. expect(value.calls).toContainEqual(['dashboard', '--stop'])
  88. expect(value.launches).toEqual([['dashboard', '--host', '0.0.0.0', '--no-open']])
  89. })
  90. it('moves an authenticated LAN dashboard back to loopback when unmanaged LAN is requested', async () => {
  91. const value = supervisor({
  92. running: true,
  93. runningHost: '0.0.0.0',
  94. allowLan: false,
  95. values: {
  96. 'dashboard.basic_auth.username': 'operator',
  97. 'dashboard.basic_auth.password_hash': 'scrypt$existing',
  98. 'dashboard.basic_auth.secret': 'configured-secret',
  99. },
  100. })
  101. await value.instance.checkNow()
  102. expect(value.calls).toContainEqual(['dashboard', '--stop'])
  103. expect(value.launches).toEqual([['dashboard', '--host', '127.0.0.1', '--no-open']])
  104. })
  105. it('explicitly restarts a healthy dashboard and waits for 9119 to return', async () => {
  106. const value = supervisor({
  107. running: true,
  108. values: {
  109. 'dashboard.basic_auth.username': 'operator',
  110. 'dashboard.basic_auth.password_hash': 'scrypt$existing',
  111. 'dashboard.basic_auth.secret': 'configured-secret',
  112. },
  113. })
  114. await value.instance.restart()
  115. expect(value.calls).toContainEqual(['dashboard', '--stop'])
  116. expect(value.launches).toEqual([['dashboard', '--host', '127.0.0.1', '--no-open']])
  117. })
  118. })