Files
jundot--omlx/tests/test_v1_models_visibility.py
wehub-resource-sync e9a2f726c9
CI / test (3.11) (push) Has been cancelled
CI / test (3.12) (push) Has been cancelled
CI / test (3.13) (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:29:51 +08:00

176 lines
6.0 KiB
Python

# SPDX-License-Identifier: Apache-2.0
"""Tests for /v1/models visibility filtering (per-model hide + global helper hide)."""
from __future__ import annotations
from unittest.mock import patch
from fastapi.testclient import TestClient
from omlx.model_settings import ModelSettings, ModelSettingsManager
from omlx.server import ServerState, app
from omlx.settings import GlobalSettings
class _Pool:
"""Engine pool stub exposing a fixed model list via get_status()."""
def __init__(self, models: list[dict]):
self._models = models
def resolve_model_id(self, model_id_or_alias: str, settings_manager) -> str:
return model_id_or_alias
def get_status(self) -> dict:
return {
"final_ceiling": 0,
"current_model_memory": 0,
"model_count": len(self._models),
"loaded_count": 0,
"models": self._models,
}
def _model(model_id: str, config_model_type: str = "llama", **extra) -> dict:
return {
"id": model_id,
"model_path": f"/models/{model_id}",
"config_model_type": config_model_type,
"source_repo_id": None,
**extra,
}
def _state(models: list[dict], tmp_path, *, hide_helpers: bool = False) -> ServerState:
state = ServerState()
state.engine_pool = _Pool(models)
state.settings_manager = ModelSettingsManager(base_path=tmp_path)
gs = GlobalSettings()
gs.model.hide_helper_models = hide_helpers
state.global_settings = gs
return state
def _list_ids(state) -> list[str]:
with (
patch("omlx.server._server_state", state),
patch("omlx.server.get_max_context_window", return_value=None),
):
client = TestClient(app, raise_server_exceptions=False)
response = client.get("/v1/models")
assert response.status_code == 200
return [m["id"] for m in response.json()["data"]]
def test_lists_all_models_by_default(tmp_path):
state = _state([_model("chat-a"), _model("chat-b")], tmp_path)
assert _list_ids(state) == ["chat-a", "chat-b"]
def test_per_model_hidden_excluded(tmp_path):
state = _state([_model("chat-a"), _model("chat-b")], tmp_path)
state.settings_manager.set_settings("chat-b", ModelSettings(is_hidden=True))
ids = _list_ids(state)
assert "chat-a" in ids
assert "chat-b" not in ids
def test_hidden_source_profile_excluded(tmp_path):
state = _state([_model("chat-a")], tmp_path)
state.settings_manager.set_settings("chat-a", ModelSettings(is_hidden=True))
state.settings_manager.save_profile(
"chat-a",
"fast",
"Fast",
None,
{"temperature": 0.1},
expose_as_model=True,
)
assert _list_ids(state) == []
def test_hidden_ignored_when_helper_toggle_off(tmp_path):
# A drafter is visible while the global toggle is off.
models = [_model("chat-a"), _model("drafter", is_helper=True)]
state = _state(models, tmp_path, hide_helpers=False)
assert "drafter" in _list_ids(state)
def test_global_hide_helper_excludes_intrinsic_flag(tmp_path):
# Discovery flags drafters (config marker / architecture) via is_helper.
models = [_model("chat-a"), _model("drafter", is_helper=True)]
state = _state(models, tmp_path, hide_helpers=True)
ids = _list_ids(state)
assert ids == ["chat-a"]
def test_global_hide_helper_excludes_helper_source_profile(tmp_path):
models = [_model("chat-a"), _model("drafter", is_helper=True)]
state = _state(models, tmp_path, hide_helpers=True)
state.settings_manager.save_profile(
"drafter",
"fast",
"Fast",
None,
{"temperature": 0.1},
expose_as_model=True,
)
assert _list_ids(state) == ["chat-a"]
def test_global_hide_helper_excludes_referenced_draft(tmp_path):
# A plain-LLM draft is a helper only because another model references it.
models = [_model("chat-a"), _model("draft-llm", config_model_type="llama")]
state = _state(models, tmp_path, hide_helpers=True)
state.settings_manager.set_settings(
"chat-a", ModelSettings(dflash_draft_model="/models/draft-llm")
)
ids = _list_ids(state)
assert "chat-a" in ids
assert "draft-llm" not in ids
def test_referenced_parent_stays_visible(tmp_path):
# The referencing chat model itself is never treated as a helper.
models = [_model("chat-a"), _model("draft-llm")]
state = _state(models, tmp_path, hide_helpers=True)
state.settings_manager.set_settings(
"chat-a", ModelSettings(vlm_mtp_draft_model="/models/draft-llm")
)
assert "chat-a" in _list_ids(state)
def test_favorites_listed_first(tmp_path):
models = [_model("chat-a"), _model("chat-b"), _model("chat-c")]
state = _state(models, tmp_path)
state.settings_manager.set_settings("chat-c", ModelSettings(is_favorite=True))
assert _list_ids(state) == ["chat-c", "chat-a", "chat-b"]
def test_favorites_alphabetical_within_groups(tmp_path):
models = [_model("chat-a"), _model("chat-b"), _model("chat-c"), _model("chat-d")]
state = _state(models, tmp_path)
state.settings_manager.set_settings("chat-b", ModelSettings(is_favorite=True))
state.settings_manager.set_settings("chat-d", ModelSettings(is_favorite=True))
assert _list_ids(state) == ["chat-b", "chat-d", "chat-a", "chat-c"]
def test_favorite_alias_listed_first(tmp_path):
# The favorite set must track display ids, since an alias replaces the id.
models = [_model("chat-a"), _model("chat-b")]
state = _state(models, tmp_path)
state.settings_manager.set_settings(
"chat-b", ModelSettings(is_favorite=True, model_alias="zz-alias")
)
assert _list_ids(state) == ["zz-alias", "chat-a"]
def test_hidden_favorite_still_excluded(tmp_path):
# Favorite is ordering-only and never overrides the hidden filter.
models = [_model("chat-a"), _model("chat-b")]
state = _state(models, tmp_path)
state.settings_manager.set_settings(
"chat-b", ModelSettings(is_hidden=True, is_favorite=True)
)
assert _list_ids(state) == ["chat-a"]