test(xceadmin): add env-var override for live E2E binary discovery
_live_e2e_common.py's CONTROLLER_CANDIDATES/XCEADMIN_CANDIDATES only ever
resolved to the three default profile-dir names (xce.build, build.release,
build.dbg), with no way to point the live E2E suite at a binary built to a
custom/explicit build dir. Adds XCE_CONTROLLER_BIN/XCEADMIN_BIN env-var
overrides via a new resolve_binary_candidates() helper -- when set, the
override becomes the sole candidate; otherwise the existing three-name
fallback list is unchanged. Mirrors the ${XCE_CONTROLLER_BIN:-default}
convention already used by clean_failover_preservation.sh/run-ha-soak.sh.
Skip messages in both live E2E test files now mention the override.
TDD: 4 new unit tests in test_live_e2e_common.py (no override, empty
override, override-becomes-sole-candidate, and an end-to-end reload proving
the real module constants respect their env vars). Full xceadmin suite
(288 tests) confirmed unaffected: 287 pass, 1 pre-existing unrelated
failure (a stale redirect-gap assertion, unrelated to this change).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AgYRU3zDTqNGV5Jk8aiKLg
This commit is contained in:
parent
7880ab4280
commit
3891bd909a
4 changed files with 133 additions and 16 deletions
|
|
@ -27,6 +27,7 @@ it -- the same mechanism that already lets every test file here import
|
|||
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import re
|
||||
import socket
|
||||
import time
|
||||
|
|
@ -36,19 +37,45 @@ SRC_DIR = Path(__file__).resolve().parents[2]
|
|||
REPO_CONFIGS_DIR = SRC_DIR / "configs"
|
||||
DEPLOY_HA_SH = SRC_DIR / "tools" / "deploy-ha.sh"
|
||||
|
||||
|
||||
def resolve_binary_candidates(env_var: str, defaults: list[Path]) -> list[Path]:
|
||||
"""If ``env_var`` is set to a non-empty value, it becomes the SOLE
|
||||
candidate -- lets a caller point discovery at a binary built to a
|
||||
custom/explicit build dir (``xce-build.sh``'s "legacy explicit
|
||||
build_dir" override), which none of the fixed default profile-dir names
|
||||
below can ever match. Otherwise falls back to ``defaults`` unchanged.
|
||||
|
||||
Mirrors the ``${XCE_CONTROLLER_BIN:-default}``-style env-var-override
|
||||
convention already used by ``clean_failover_preservation.sh``/
|
||||
``run-ha-soak.sh`` elsewhere in this repo, rather than a Python-only
|
||||
ad hoc mechanism.
|
||||
"""
|
||||
override = os.environ.get(env_var)
|
||||
if override:
|
||||
return [Path(override)]
|
||||
return defaults
|
||||
|
||||
|
||||
# Mirrors deploy-ha.sh's own xceadmin/controller discovery order
|
||||
# (src/tools/deploy-ha.sh) -- xce.build (asan, the default profile) first,
|
||||
# then release, then debug.
|
||||
CONTROLLER_CANDIDATES = [
|
||||
SRC_DIR / "xce.build" / "controller" / "xce_controller",
|
||||
SRC_DIR / "build.release" / "controller" / "xce_controller",
|
||||
SRC_DIR / "build.dbg" / "controller" / "xce_controller",
|
||||
]
|
||||
XCEADMIN_CANDIDATES = [
|
||||
SRC_DIR / "xce.build" / "xceadmin" / ".venv" / "bin" / "xceadmin",
|
||||
SRC_DIR / "build.release" / "xceadmin" / ".venv" / "bin" / "xceadmin",
|
||||
SRC_DIR / "build.dbg" / "xceadmin" / ".venv" / "bin" / "xceadmin",
|
||||
]
|
||||
# then release, then debug. XCE_CONTROLLER_BIN/XCEADMIN_BIN override this
|
||||
# entirely when set (e.g. a build to a custom/explicit build dir).
|
||||
CONTROLLER_CANDIDATES = resolve_binary_candidates(
|
||||
"XCE_CONTROLLER_BIN",
|
||||
[
|
||||
SRC_DIR / "xce.build" / "controller" / "xce_controller",
|
||||
SRC_DIR / "build.release" / "controller" / "xce_controller",
|
||||
SRC_DIR / "build.dbg" / "controller" / "xce_controller",
|
||||
],
|
||||
)
|
||||
XCEADMIN_CANDIDATES = resolve_binary_candidates(
|
||||
"XCEADMIN_BIN",
|
||||
[
|
||||
SRC_DIR / "xce.build" / "xceadmin" / ".venv" / "bin" / "xceadmin",
|
||||
SRC_DIR / "build.release" / "xceadmin" / ".venv" / "bin" / "xceadmin",
|
||||
SRC_DIR / "build.dbg" / "xceadmin" / ".venv" / "bin" / "xceadmin",
|
||||
],
|
||||
)
|
||||
|
||||
READY_TIMEOUT_S = 20.0
|
||||
VERSION_TAG_RE = re.compile(r"versionTag=(\d+)\s+ackedCount=(\d+)")
|
||||
|
|
|
|||
|
|
@ -296,7 +296,8 @@ def live_ha_cluster(tmp_path: Path):
|
|||
if controller_bin is None:
|
||||
pytest.skip(
|
||||
"no xce_controller binary found under xce.build/build.release/"
|
||||
"build.dbg -- run xce-build.sh controller [profile] first to "
|
||||
"build.dbg -- run xce-build.sh controller [profile] first, or "
|
||||
"set XCE_CONTROLLER_BIN to a custom build's binary, to "
|
||||
"exercise this live E2E test"
|
||||
)
|
||||
if shutil.which("openssl") is None:
|
||||
|
|
@ -433,7 +434,11 @@ def test_live_config_push_against_primary_reaches_success_path(
|
|||
"""
|
||||
xceadmin_bin = find_first_executable(XCEADMIN_CANDIDATES)
|
||||
if xceadmin_bin is None:
|
||||
pytest.skip("no xceadmin binary found under xce.build/build.release/build.dbg")
|
||||
pytest.skip(
|
||||
"no xceadmin binary found under xce.build/build.release/"
|
||||
"build.dbg -- set XCEADMIN_BIN to a custom build's binary "
|
||||
"if using a non-default build dir"
|
||||
)
|
||||
|
||||
cluster_bin = _build_cluster_bin(xceadmin_bin, tmp_path)
|
||||
|
||||
|
|
@ -519,7 +524,11 @@ def test_live_config_push_against_standby_returns_standby_rejection_not_redirect
|
|||
"""
|
||||
xceadmin_bin = find_first_executable(XCEADMIN_CANDIDATES)
|
||||
if xceadmin_bin is None:
|
||||
pytest.skip("no xceadmin binary found under xce.build/build.release/build.dbg")
|
||||
pytest.skip(
|
||||
"no xceadmin binary found under xce.build/build.release/"
|
||||
"build.dbg -- set XCEADMIN_BIN to a custom build's binary "
|
||||
"if using a non-default build dir"
|
||||
)
|
||||
|
||||
cluster_bin = _build_cluster_bin(xceadmin_bin, tmp_path)
|
||||
|
||||
|
|
|
|||
|
|
@ -93,7 +93,8 @@ def live_controller(tmp_path: Path):
|
|||
if controller_bin is None:
|
||||
pytest.skip(
|
||||
"no xce_controller binary found under xce.build/build.release/"
|
||||
"build.dbg -- run xce-build.sh controller [profile] first to "
|
||||
"build.dbg -- run xce-build.sh controller [profile] first, or "
|
||||
"set XCE_CONTROLLER_BIN to a custom build's binary, to "
|
||||
"exercise this live E2E test"
|
||||
)
|
||||
if shutil.which("openssl") is None:
|
||||
|
|
@ -154,7 +155,11 @@ def test_live_config_push_against_real_single_node_controller(live_controller, t
|
|||
controller_addr, log_file = live_controller
|
||||
xceadmin_bin = _find_first_executable(_XCEADMIN_CANDIDATES)
|
||||
if xceadmin_bin is None:
|
||||
pytest.skip("no xceadmin binary found under xce.build/build.release/build.dbg")
|
||||
pytest.skip(
|
||||
"no xceadmin binary found under xce.build/build.release/"
|
||||
"build.dbg -- set XCEADMIN_BIN to a custom build's binary "
|
||||
"if using a non-default build dir"
|
||||
)
|
||||
|
||||
cluster_bin = tmp_path / "cluster.bin"
|
||||
build_result = subprocess.run(
|
||||
|
|
|
|||
76
src/xceadmin/tests/test_live_e2e_common.py
Normal file
76
src/xceadmin/tests/test_live_e2e_common.py
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
"""Unit tests for ``_live_e2e_common``'s binary-discovery env-var override.
|
||||
|
||||
``CONTROLLER_CANDIDATES``/``XCEADMIN_CANDIDATES`` previously only ever
|
||||
resolved to the three default profile-dir names (``xce.build``,
|
||||
``build.release``, ``build.dbg``) -- no way to point the live E2E suite at
|
||||
a binary built to a custom/explicit build dir (``xce-build.sh``'s
|
||||
"legacy explicit build_dir" override) without editing this module directly.
|
||||
This adds ``XCE_CONTROLLER_BIN``/``XCEADMIN_BIN`` env-var overrides,
|
||||
consistent with the ``${XCE_CONTROLLER_BIN:-default}``-style pattern
|
||||
already used by ``clean_failover_preservation.sh``/``run-ha-soak.sh``.
|
||||
|
||||
Tests the pure resolution helper directly (not the frozen module-level
|
||||
``CONTROLLER_CANDIDATES``/``XCEADMIN_CANDIDATES`` constants, which are
|
||||
computed once at import time from whatever the environment happened to be
|
||||
-- re-importing the module under a patched environment is fragile/awkward
|
||||
under pytest's module caching, so the override LOGIC is factored into a
|
||||
directly-testable function instead).
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
from _live_e2e_common import resolve_binary_candidates
|
||||
|
||||
|
||||
def test_no_env_override_returns_default_candidates_unchanged(monkeypatch):
|
||||
monkeypatch.delenv("XCE_SOME_TEST_BIN", raising=False)
|
||||
defaults = [Path("/a/xce.build/x"), Path("/a/build.release/x")]
|
||||
|
||||
result = resolve_binary_candidates("XCE_SOME_TEST_BIN", defaults)
|
||||
|
||||
assert result == defaults
|
||||
|
||||
|
||||
def test_empty_env_override_falls_back_to_default_candidates(monkeypatch):
|
||||
monkeypatch.setenv("XCE_SOME_TEST_BIN", "")
|
||||
defaults = [Path("/a/xce.build/x")]
|
||||
|
||||
result = resolve_binary_candidates("XCE_SOME_TEST_BIN", defaults)
|
||||
|
||||
assert result == defaults
|
||||
|
||||
|
||||
def test_env_override_becomes_sole_candidate(monkeypatch, tmp_path):
|
||||
custom_bin = tmp_path / "my-custom-build" / "controller" / "xce_controller"
|
||||
monkeypatch.setenv("XCE_SOME_TEST_BIN", str(custom_bin))
|
||||
defaults = [Path("/a/xce.build/x"), Path("/a/build.dbg/x")]
|
||||
|
||||
result = resolve_binary_candidates("XCE_SOME_TEST_BIN", defaults)
|
||||
|
||||
assert result == [custom_bin]
|
||||
|
||||
|
||||
def test_controller_and_xceadmin_candidates_respect_their_own_env_vars(monkeypatch, tmp_path):
|
||||
"""End-to-end through the real module constants' construction: reload
|
||||
the module with each override env var set and confirm the exported
|
||||
candidate lists reduce to the single overridden path, proving the
|
||||
actual production wiring (not just the helper in isolation) is correct.
|
||||
"""
|
||||
import importlib
|
||||
|
||||
import _live_e2e_common as mod
|
||||
|
||||
custom_controller = tmp_path / "custom" / "xce_controller"
|
||||
custom_xceadmin = tmp_path / "custom" / "xceadmin"
|
||||
monkeypatch.setenv("XCE_CONTROLLER_BIN", str(custom_controller))
|
||||
monkeypatch.setenv("XCEADMIN_BIN", str(custom_xceadmin))
|
||||
try:
|
||||
importlib.reload(mod)
|
||||
assert mod.CONTROLLER_CANDIDATES == [custom_controller]
|
||||
assert mod.XCEADMIN_CANDIDATES == [custom_xceadmin]
|
||||
finally:
|
||||
monkeypatch.delenv("XCE_CONTROLLER_BIN", raising=False)
|
||||
monkeypatch.delenv("XCEADMIN_BIN", raising=False)
|
||||
importlib.reload(mod) # restore default candidates for any test after this one
|
||||
Loading…
Add table
Add a link
Reference in a new issue