5export const runCodeservHealthcheck = async ({hostname, password}: {hostname: string, password?: string}) => { 6 const suiteName = 'healthcheck' 7 console.log(chalkCyan(`[${suiteName}] ${hostname}`)) 11 test('httpsResponds', async () => { 12 const url = `https://${hostname}/` 13 const maxAttempts = 5, delaySec = 10 14 let lastErr: string = 'unknown' 15 for (let i = 0; i < maxAttempts; i++) { 17 const resp = await fetch(url, {signal: AbortSignal.timeout(10000)}) 18 // 401 is fine here - means server is up, just needs auth 19 if (resp.ok || resp.status === 401) return {passed: true, msg: `HTTP ${resp.status}`} 20 lastErr = `HTTP ${resp.status} ${resp.statusText}` 24 if (i < maxAttempts - 1) await sleep(delaySec * 1000) 26 return {passed: false, msg: `fetch failed after ${maxAttempts} attempts: ${lastErr ?? 'unknown'}`} 29 test('authRequired', async () => { 30 if (!password) return {passed: true, msg: 'skipped (no password configured)'} 31 const url = `https://${hostname}/` 33 const resp = await fetch(url, {signal: AbortSignal.timeout(10000)}) 34 if (resp.status === 401) return {passed: true, msg: 'returns 401 without auth'} 35 return {passed: false, msg: `expected 401, got ${resp.status}`} 37 return {passed: false, msg: err.message} 41 test('authWorks', async () => { 42 if (!password) return {passed: true, msg: 'skipped (no password configured)'} 43 const url = `https://${hostname}/` 44 const auth = Buffer.from(`opencode:${password}`).toString('base64') 45 const maxAttempts = 3, delaySec = 5, timeoutMs = 30000 46 let lastErr: string = 'unknown' 47 for (let i = 0; i < maxAttempts; i++) { 49 const resp = await fetch(url, {headers: {Authorization: `Basic ${auth}`}, signal: AbortSignal.timeout(timeoutMs)}) 50 if (resp.ok) return {passed: true, msg: `HTTP ${resp.status} with auth`} 51 lastErr = `auth failed: HTTP ${resp.status}` 55 if (i < maxAttempts - 1) await sleep(delaySec * 1000) 57 return {passed: false, msg: lastErr ?? 'unknown error'}