diff --git a/src/openultrasast/plane/reconciler.py b/src/openultrasast/plane/reconciler.py index 377392d..aeaad4b 100644 --- a/src/openultrasast/plane/reconciler.py +++ b/src/openultrasast/plane/reconciler.py @@ -469,8 +469,10 @@ def _pods_ready(namespace: str, context: str) -> tuple[bool, str]: ok, out = _sh("kubectl", "--context", context, "-n", namespace, "get", "pods", "--no-headers") if not ok or not out: return False, out or "no pods" - rows = [line.split() for line in out.splitlines()] - bad = [r[0] for r in rows if len(r) > 2 and r[2] not in ("Completed", "Succeeded") and r[1].split("/")[0] != r[1].split("/")[-1]] + rows = [r for r in (line.split() for line in out.splitlines()) if len(r) > 2 and re.fullmatch(r"\d+/\d+", r[1])] + if not rows: # "No resources found" is not a ready namespace + return False, f"no pods in {namespace}" + bad = [r[0] for r in rows if r[2] not in ("Completed", "Succeeded") and r[1].split("/")[0] != r[1].split("/")[1]] return not bad, f"not ready: {', '.join(bad)}" if bad else f"{len(rows)} pods ready" diff --git a/tests/test_plane_reconciler.py b/tests/test_plane_reconciler.py index 9ee7321..a1b3dfb 100644 --- a/tests/test_plane_reconciler.py +++ b/tests/test_plane_reconciler.py @@ -483,3 +483,16 @@ def test_elapsed_polling_is_paced(fake: Fake, tmp_path: Path, monkeypatch: pytes started = time.monotonic() assert reconciler.run(write_run(tmp_path, "paced", PAIR.replace("{serialize}", "")), ax=str(fake.ax)) == "done" assert time.monotonic() - started >= 0.4, "three polls of x plus one of y at 0.1s each" + + +def test_doctor_treats_an_empty_namespace_as_not_ready(monkeypatch: pytest.MonkeyPatch) -> None: + """kubectl's "No resources found" must not read as one ready pod (a plausible-zero instrument failure).""" + from openultrasast.plane import reconciler + + monkeypatch.setattr(reconciler, "_sh", lambda *a: (True, "No resources found in ax-system namespace.")) + ok, text = reconciler._pods_ready("ax-system", "kind-ousast") + assert not ok and "no pods" in text + monkeypatch.setattr(reconciler, "_sh", lambda *a: (True, "a-1 1/1 Running 0 1m\nb-2 0/1 Completed 0 1m")) + assert reconciler._pods_ready("ns", "ctx") == (True, "2 pods ready") + monkeypatch.setattr(reconciler, "_sh", lambda *a: (True, "a-1 0/1 Running 0 1m")) + assert reconciler._pods_ready("ns", "ctx")[0] is False