test(setup): add ZAI endpoint picker tests, move base-URL tests to MiniMax

Z.AI now uses a curses picker instead of plain text input for base URL,
so the existing TestBaseUrlValidation tests (which used zai as their test
subject) are migrated to MiniMax, which still uses the text input path.

Add TestZaiEndpointPicker covering:
- Selecting each official endpoint (Global, China, Coding Plan Global,
  Coding Plan China) saves the correct base URL to config
- Custom proxy URL entry (valid + invalid rejection)
- Cancel keeps the existing base URL
- Current endpoint is the default choice in the picker
- Non-standard URL defaults to the Custom proxy option
This commit is contained in:
kshitijk4poor 2026-06-25 11:35:36 +05:30 committed by kshitij
parent f3372d3407
commit d0df264213

View file

@ -319,31 +319,37 @@ class TestProviderPersistsAfterModelSave:
class TestBaseUrlValidation:
"""Reject non-URL values in the base URL prompt (e.g. shell commands)."""
"""Reject non-URL values in the base URL prompt (e.g. shell commands).
Uses MiniMax instead of Z.AI because Z.AI now uses a curses-based
endpoint picker (_select_zai_endpoint) rather than the plain text
input() prompt. Z.AI picker behavior is covered in
TestZaiEndpointPicker below.
"""
def test_invalid_base_url_rejected(self, config_home, monkeypatch, capsys):
"""Typing a non-URL string should not be saved as the base URL."""
from hermes_cli.auth import PROVIDER_REGISTRY
pconfig = PROVIDER_REGISTRY.get("zai")
pconfig = PROVIDER_REGISTRY.get("minimax")
if not pconfig:
pytest.skip("zai not in PROVIDER_REGISTRY")
pytest.skip("minimax not in PROVIDER_REGISTRY")
monkeypatch.setenv("GLM_API_KEY", "test-key")
monkeypatch.setenv("MINIMAX_API_KEY", "test-key")
from hermes_cli.main import _model_flow_api_key_provider
from hermes_cli.config import load_config, get_env_value
# User types a shell command instead of a URL at the base URL prompt
with patch("hermes_cli.auth._prompt_model_selection", return_value="glm-5"), \
with patch("hermes_cli.auth._prompt_model_selection", return_value="MiniMax-M2"), \
patch("hermes_cli.auth.deactivate_provider"), \
patch("builtins.input", return_value="nano ~/.hermes/.env"):
_model_flow_api_key_provider(load_config(), "zai", "old-model")
_model_flow_api_key_provider(load_config(), "minimax", "old-model")
# The garbage value should NOT have been saved
saved = get_env_value("GLM_BASE_URL") or ""
saved = get_env_value("MINIMAX_BASE_URL") or ""
assert not saved or saved.startswith(("http://", "https://")), \
f"Non-URL value was saved as GLM_BASE_URL: {saved}"
f"Non-URL value was saved as MINIMAX_BASE_URL: {saved}"
captured = capsys.readouterr()
assert "Invalid URL" in captured.out
@ -351,42 +357,199 @@ class TestBaseUrlValidation:
"""A proper URL should be saved normally."""
from hermes_cli.auth import PROVIDER_REGISTRY
pconfig = PROVIDER_REGISTRY.get("zai")
pconfig = PROVIDER_REGISTRY.get("minimax")
if not pconfig:
pytest.skip("zai not in PROVIDER_REGISTRY")
pytest.skip("minimax not in PROVIDER_REGISTRY")
monkeypatch.setenv("GLM_API_KEY", "test-key")
monkeypatch.setenv("MINIMAX_API_KEY", "test-key")
from hermes_cli.main import _model_flow_api_key_provider
from hermes_cli.config import load_config, get_env_value
with patch("hermes_cli.auth._prompt_model_selection", return_value="glm-5"), \
with patch("hermes_cli.auth._prompt_model_selection", return_value="MiniMax-M2"), \
patch("hermes_cli.auth.deactivate_provider"), \
patch("builtins.input", return_value="https://custom.z.ai/api/paas/v4"):
_model_flow_api_key_provider(load_config(), "zai", "old-model")
patch("builtins.input", return_value="https://custom.minimax.example/v1"):
_model_flow_api_key_provider(load_config(), "minimax", "old-model")
saved = get_env_value("GLM_BASE_URL") or ""
assert saved == "https://custom.z.ai/api/paas/v4"
saved = get_env_value("MINIMAX_BASE_URL") or ""
assert saved == "https://custom.minimax.example/v1"
def test_empty_base_url_keeps_default(self, config_home, monkeypatch):
"""Pressing Enter (empty) should not change the base URL."""
from hermes_cli.auth import PROVIDER_REGISTRY
pconfig = PROVIDER_REGISTRY.get("zai")
pconfig = PROVIDER_REGISTRY.get("minimax")
if not pconfig:
pytest.skip("zai not in PROVIDER_REGISTRY")
pytest.skip("minimax not in PROVIDER_REGISTRY")
monkeypatch.setenv("GLM_API_KEY", "test-key")
monkeypatch.delenv("GLM_BASE_URL", raising=False)
monkeypatch.setenv("MINIMAX_API_KEY", "test-key")
monkeypatch.delenv("MINIMAX_BASE_URL", raising=False)
from hermes_cli.main import _model_flow_api_key_provider
from hermes_cli.config import load_config, get_env_value
with patch("hermes_cli.auth._prompt_model_selection", return_value="glm-5"), \
with patch("hermes_cli.auth._prompt_model_selection", return_value="MiniMax-M2"), \
patch("hermes_cli.auth.deactivate_provider"), \
patch("builtins.input", return_value=""):
_model_flow_api_key_provider(load_config(), "minimax", "old-model")
saved = get_env_value("MINIMAX_BASE_URL") or ""
assert saved == "", "Empty input should not save a base URL"
class TestZaiEndpointPicker:
"""Z.AI setup should present a curses picker for endpoint selection."""
def test_select_global_endpoint(self, config_home, monkeypatch):
"""Selecting Global should save the direct API base URL."""
from hermes_cli.auth import ZAI_ENDPOINTS
from hermes_cli.main import _model_flow_api_key_provider
from hermes_cli.config import load_config
global_url = ZAI_ENDPOINTS[0][1] # "https://api.z.ai/api/paas/v4"
monkeypatch.setenv("GLM_API_KEY", "test-key")
with patch("hermes_cli.main._prompt_provider_choice", return_value=0), \
patch("hermes_cli.auth._prompt_model_selection", return_value="glm-5"), \
patch("hermes_cli.auth.deactivate_provider"), \
patch("builtins.input", return_value=""):
_model_flow_api_key_provider(load_config(), "zai", "old-model")
saved = get_env_value("GLM_BASE_URL") or ""
assert saved == "", "Empty input should not save a base URL"
model = load_config()["model"]
assert model["base_url"] == global_url
def test_select_coding_plan_global_endpoint(self, config_home, monkeypatch):
"""Selecting Coding Plan Global should save the coding base URL."""
from hermes_cli.auth import ZAI_ENDPOINTS
from hermes_cli.main import _model_flow_api_key_provider
from hermes_cli.config import load_config
coding_url = ZAI_ENDPOINTS[2][1] # coding-global
monkeypatch.setenv("GLM_API_KEY", "test-key")
# Index 2 = Coding Plan Global in ZAI_ENDPOINTS
with patch("hermes_cli.main._prompt_provider_choice", return_value=2), \
patch("hermes_cli.auth._prompt_model_selection", return_value="glm-5.2"), \
patch("hermes_cli.auth.deactivate_provider"), \
patch("builtins.input", return_value=""):
_model_flow_api_key_provider(load_config(), "zai", "old-model")
model = load_config()["model"]
assert model["base_url"] == coding_url
def test_select_china_endpoint(self, config_home, monkeypatch):
"""Selecting China should save the bigmodel.cn base URL."""
from hermes_cli.auth import ZAI_ENDPOINTS
from hermes_cli.main import _model_flow_api_key_provider
from hermes_cli.config import load_config
cn_url = ZAI_ENDPOINTS[1][1] # "https://open.bigmodel.cn/api/paas/v4"
monkeypatch.setenv("GLM_API_KEY", "test-key")
with patch("hermes_cli.main._prompt_provider_choice", return_value=1), \
patch("hermes_cli.auth._prompt_model_selection", return_value="glm-5"), \
patch("hermes_cli.auth.deactivate_provider"), \
patch("builtins.input", return_value=""):
_model_flow_api_key_provider(load_config(), "zai", "old-model")
model = load_config()["model"]
assert model["base_url"] == cn_url
def test_select_custom_proxy_url(self, config_home, monkeypatch):
"""Selecting Custom proxy should prompt for a URL and save it."""
from hermes_cli.main import _model_flow_api_key_provider
from hermes_cli.config import load_config, get_env_value
monkeypatch.setenv("GLM_API_KEY", "test-key")
# Last option index = custom proxy
with patch("hermes_cli.main._prompt_provider_choice", return_value=4), \
patch("hermes_cli.auth._prompt_model_selection", return_value="glm-5"), \
patch("hermes_cli.auth.deactivate_provider"), \
patch("builtins.input", return_value="https://proxy.example.com/glm/v4"):
_model_flow_api_key_provider(load_config(), "zai", "old-model")
saved = get_env_value("GLM_BASE_URL") or ""
assert saved == "https://proxy.example.com/glm/v4"
def test_custom_proxy_rejects_invalid_url(self, config_home, monkeypatch, capsys):
"""Custom proxy must start with http:// or https://."""
from hermes_cli.main import _model_flow_api_key_provider
from hermes_cli.config import load_config
monkeypatch.setenv("GLM_API_KEY", "test-key")
monkeypatch.delenv("GLM_BASE_URL", raising=False)
with patch("hermes_cli.main._prompt_provider_choice", return_value=4), \
patch("hermes_cli.auth._prompt_model_selection", return_value="glm-5"), \
patch("hermes_cli.auth.deactivate_provider"), \
patch("builtins.input", return_value="not-a-url"):
_model_flow_api_key_provider(load_config(), "zai", "old-model")
# The invalid URL should not have been saved as base_url
model = load_config()["model"]
assert model["base_url"] != "not-a-url"
captured = capsys.readouterr()
assert "Invalid URL" in captured.out
def test_cancel_keeps_existing_base_url(self, config_home, monkeypatch):
"""Cancelling the picker should not change the base URL."""
from hermes_cli.main import _model_flow_api_key_provider
from hermes_cli.config import load_config, get_env_value
monkeypatch.setenv("GLM_API_KEY", "test-key")
monkeypatch.setenv("GLM_BASE_URL", "https://existing.example/v4")
# _prompt_provider_choice returns None on cancel
with patch("hermes_cli.main._prompt_provider_choice", return_value=None), \
patch("hermes_cli.auth._prompt_model_selection", return_value="glm-5"), \
patch("hermes_cli.auth.deactivate_provider"), \
patch("builtins.input", return_value=""):
_model_flow_api_key_provider(load_config(), "zai", "old-model")
# env var is preserved (not overwritten on cancel)
saved = get_env_value("GLM_BASE_URL") or ""
assert saved == "https://existing.example/v4"
def test_current_endpoint_is_default_choice(self, config_home, monkeypatch):
"""When a known endpoint is already active, it should be the default."""
from hermes_cli.auth import ZAI_ENDPOINTS
from hermes_cli.model_setup_flows import _select_zai_endpoint
coding_url = ZAI_ENDPOINTS[2][1] # coding-global
captured = {}
def fake_choice(choices, *, default=0, title=""):
captured["default"] = default
captured["choices"] = choices
return default
with patch("hermes_cli.main._prompt_provider_choice", side_effect=fake_choice):
result = _select_zai_endpoint(coding_url)
# Default should point at index 2 (coding-global)
assert captured["default"] == 2
assert result == coding_url
def test_custom_url_active_defaults_to_custom_option(self, config_home, monkeypatch):
"""When a non-standard URL is active, Custom proxy should be default."""
from hermes_cli.auth import ZAI_ENDPOINTS
from hermes_cli.model_setup_flows import _select_zai_endpoint
custom_url = "https://my-proxy.example.com/v4"
# 4 official endpoints → custom is index 4
expected_default = len(ZAI_ENDPOINTS)
captured = {}
def fake_choice(choices, *, default=0, title=""):
captured["default"] = default
return default
with patch("hermes_cli.main._prompt_provider_choice", side_effect=fake_choice), \
patch("builtins.input", return_value=""):
_select_zai_endpoint(custom_url)
assert captured["default"] == expected_default