mirror of
https://github.com/dtzp555-max/ocp.git
synced 2026-07-21 21:15:09 +00:00
fix(doctor): handle unparseable version + empty health body
Three issues raised by code-quality reviewer on b65201b:
1. semverCompare returned 0 for unparseable input, causing fromSupported=true
and kind=noop for an install with unreadable package.json. Now treats
unparseable currentVersion as fresh_install candidate.
2. mockHealth: { status: 200, body: null } routed to fix_oauth (because
health.body?.auth?.ok was undefined → falsy). 200 with empty body is
server-broken, not OAuth-broken; now routes to fix_service.
3. Removed unused KIND_ENUM declaration (dead code).
Two regression tests added.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+9
-5
@@ -17,7 +17,6 @@ import { homedir } from "node:os";
|
|||||||
import { execSync } from "node:child_process";
|
import { execSync } from "node:child_process";
|
||||||
|
|
||||||
const SCHEMA_VERSION = "1";
|
const SCHEMA_VERSION = "1";
|
||||||
const KIND_ENUM = ["noop", "update", "upgrade", "fresh_install", "fix_oauth", "fix_service"];
|
|
||||||
|
|
||||||
function semverParts(v) {
|
function semverParts(v) {
|
||||||
const m = String(v).replace(/^v/, "").match(/^(\d+)\.(\d+)\.(\d+)/);
|
const m = String(v).replace(/^v/, "").match(/^(\d+)\.(\d+)\.(\d+)/);
|
||||||
@@ -53,7 +52,7 @@ export async function runDoctor(opts = {}) {
|
|||||||
push("current_version", "PASS", `current=${currentVersion}`);
|
push("current_version", "PASS", `current=${currentVersion}`);
|
||||||
|
|
||||||
// --- from-version supported? ---
|
// --- from-version supported? ---
|
||||||
const fromSupported = semverCompare(currentVersion, "v3.4.0") >= 0;
|
const fromSupported = !!semverParts(currentVersion) && semverCompare(currentVersion, "v3.4.0") >= 0;
|
||||||
push("from_version_supported", fromSupported ? "PASS" : "FAIL",
|
push("from_version_supported", fromSupported ? "PASS" : "FAIL",
|
||||||
fromSupported ? "≥ v3.4.0" : `${currentVersion} < v3.4.0; in-place upgrade not supported`);
|
fromSupported ? "≥ v3.4.0" : `${currentVersion} < v3.4.0; in-place upgrade not supported`);
|
||||||
|
|
||||||
@@ -75,6 +74,9 @@ export async function runDoctor(opts = {}) {
|
|||||||
if (health.error || health.status !== 200) {
|
if (health.error || health.status !== 200) {
|
||||||
healthOk = false;
|
healthOk = false;
|
||||||
push("service_running", "FAIL", `service unreachable: ${health.error || `status ${health.status}`}`);
|
push("service_running", "FAIL", `service unreachable: ${health.error || `status ${health.status}`}`);
|
||||||
|
} else if (!health.body || typeof health.body !== "object") {
|
||||||
|
healthOk = false;
|
||||||
|
push("service_running", "FAIL", "service /health returned 200 but empty/non-JSON body");
|
||||||
} else {
|
} else {
|
||||||
push("service_running", "PASS", "service responding on /health");
|
push("service_running", "PASS", "service responding on /health");
|
||||||
const authOk = health.body?.auth?.ok;
|
const authOk = health.body?.auth?.ok;
|
||||||
@@ -95,11 +97,13 @@ export async function runDoctor(opts = {}) {
|
|||||||
kind = "fix_service";
|
kind = "fix_service";
|
||||||
} else if (!opts.skipNetwork && !oauthOk) {
|
} else if (!opts.skipNetwork && !oauthOk) {
|
||||||
kind = "fix_oauth";
|
kind = "fix_oauth";
|
||||||
} else if (semverCompare(currentVersion, latestVersion) === 0) {
|
|
||||||
kind = "noop";
|
|
||||||
} else {
|
} else {
|
||||||
const cur = semverParts(currentVersion), lat = semverParts(latestVersion);
|
const cur = semverParts(currentVersion), lat = semverParts(latestVersion);
|
||||||
if (cur && lat && cur.major === lat.major && cur.minor === lat.minor) {
|
if (!cur) {
|
||||||
|
kind = "fresh_install";
|
||||||
|
} else if (semverCompare(currentVersion, latestVersion) === 0) {
|
||||||
|
kind = "noop";
|
||||||
|
} else if (lat && cur.major === lat.major && cur.minor === lat.minor) {
|
||||||
kind = "update";
|
kind = "update";
|
||||||
} else {
|
} else {
|
||||||
kind = "upgrade";
|
kind = "upgrade";
|
||||||
|
|||||||
@@ -639,6 +639,22 @@ test("doctor service down → fix_service kind", async () => {
|
|||||||
assert.equal(result.next_action.kind, "fix_service");
|
assert.equal(result.next_action.kind, "fix_service");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("doctor unparseable version → fresh_install", async () => {
|
||||||
|
const result = await runDoctor({ skipNetwork: true, mockVersion: "garbage", mockLatest: "v3.14.0" });
|
||||||
|
assert.equal(result.from_version_supported, false);
|
||||||
|
assert.equal(result.next_action.kind, "fresh_install");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("doctor empty health body → fix_service (not fix_oauth)", async () => {
|
||||||
|
const result = await runDoctor({
|
||||||
|
skipNetwork: false,
|
||||||
|
mockVersion: "v3.10.0",
|
||||||
|
mockLatest: "v3.14.0",
|
||||||
|
mockHealth: { status: 200, body: null }
|
||||||
|
});
|
||||||
|
assert.equal(result.next_action.kind, "fix_service");
|
||||||
|
});
|
||||||
|
|
||||||
// ── Cleanup ──
|
// ── Cleanup ──
|
||||||
closeDb();
|
closeDb();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user