Skip to content

Commit 8516939

Browse files
authored
Fix and enhance llama-stack models tests (#968)
* fix: fix and enhance models tests Signed-off-by: Jorge Garcia Oncins <jgarciao@redhat.com> * feat: update model info type and enhance model tests - Changed `embedding_dimension` type from `int` to `float` in `ModelInfo`. - Improved test coverage for model listing and retrieval, ensuring compatibility with OpenAI SDK structure. - Added assertions to validate model attributes and metadata. - Enhanced error handling for non-existent models. Signed-off-by: Jorge Garcia Oncins <jgarciao@redhat.com> Assisted-by: Cursor * fix: addess enhancements proposed by CodeRabbit Signed-off-by: Jorge Garcia Oncins <jgarciao@redhat.com> --------- Signed-off-by: Jorge Garcia Oncins <jgarciao@redhat.com>
1 parent a286e72 commit 8516939

File tree

2 files changed

+159
-42
lines changed

2 files changed

+159
-42
lines changed

tests/llama_stack/constants.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ class ModelInfo(NamedTuple):
2626

2727
model_id: str
2828
embedding_model: Model
29-
embedding_dimension: int
29+
embedding_dimension: float # API returns float (e.g., 768.0) despite being conceptually an integer
3030

3131

3232
LLS_CORE_POD_FILTER: str = "app=llama-stack"
Lines changed: 158 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,21 @@
11
import pytest
2-
2+
import os
33
from tests.llama_stack.constants import LlamaStackProviders
4-
from llama_stack_client import LlamaStackClient
5-
from utilities.constants import MinIo, QWEN_MODEL_NAME
4+
from llama_stack_client import LlamaStackClient, NotFoundError
5+
from llama_stack_client.types import Model
66

77

88
@pytest.mark.parametrize(
9-
"model_namespace, minio_pod, minio_data_connection, llama_stack_server_config",
9+
"unprivileged_model_namespace",
1010
[
1111
pytest.param(
1212
{"name": "test-llamastack-models", "randomize_name": True},
13-
MinIo.PodConfig.QWEN_HAP_BPIV2_MINIO_CONFIG,
14-
{"bucket": "llms"},
15-
{
16-
"vllm_url_fixture": "qwen_isvc_url",
17-
"inference_model": QWEN_MODEL_NAME,
18-
"llama_stack_storage_size": "2Gi",
19-
},
20-
)
13+
),
2114
],
2215
indirect=True,
2316
)
24-
@pytest.mark.rawdeployment
25-
@pytest.mark.smoke
2617
@pytest.mark.llama_stack
27-
@pytest.mark.skip_must_gather
28-
@pytest.mark.usefixtures("minio_pod", "minio_data_connection")
18+
@pytest.mark.smoke
2919
class TestLlamaStackModels:
3020
"""Test class for LlamaStack models API functionality.
3121
@@ -34,44 +24,171 @@ class TestLlamaStackModels:
3424
- https://github.com/openai/openai-python/blob/main/api.md#models
3525
"""
3626

37-
def test_models_list(self, llama_stack_client: LlamaStackClient) -> None:
38-
"""Test the initial state of the LlamaStack server and available models."""
39-
models = llama_stack_client.models.list()
27+
def test_models_list(
28+
self,
29+
unprivileged_llama_stack_client: LlamaStackClient,
30+
) -> None:
31+
"""Test listing all available models.
32+
33+
Verifies that the models.list() method returns a non-empty list
34+
containing at least one LLM and one embedding model, compatible
35+
with OpenAI SDK structure.
36+
"""
37+
models = unprivileged_llama_stack_client.models.list()
4038
assert models is not None, "No models returned from LlamaStackClient"
39+
assert isinstance(models, list), "models.list() should return a list"
40+
assert len(models) > 0, "At least one model should be available"
4141

4242
llm_model = next((model for model in models if model.api_model_type == "llm"), None)
4343
assert llm_model is not None, "No LLM model found in available models"
44-
model_id = llm_model.identifier
45-
assert model_id is not None, "No identifier set in LLM model"
44+
assert isinstance(llm_model, Model), "LLM model should be a Model instance"
45+
assert llm_model.identifier is not None, "No identifier set in LLM model"
46+
assert len(llm_model.identifier) > 0, "LLM model identifier should not be empty"
4647

4748
embedding_model = next((model for model in models if model.api_model_type == "embedding"), None)
4849
assert embedding_model is not None, "No embedding model found in available models"
49-
embedding_model_id = embedding_model.identifier
50-
assert embedding_model_id is not None, "No embedding model returned from LlamaStackClient"
50+
assert isinstance(embedding_model, Model), "Embedding model should be a Model instance"
51+
assert embedding_model.identifier is not None, "No identifier set in embedding model"
52+
assert len(embedding_model.identifier) > 0, "Embedding model identifier should not be empty"
5153
assert "embedding_dimension" in embedding_model.metadata, "embedding_dimension not found in model metadata"
5254
embedding_dimension = embedding_model.metadata["embedding_dimension"]
5355
assert embedding_dimension is not None, "No embedding_dimension set in embedding model"
56+
# API returns dimension as float (e.g., 768.0) though conceptually an integer
57+
assert isinstance(embedding_dimension, float), "embedding_dimension should be a float"
58+
assert embedding_dimension > 0, "embedding_dimension should be positive"
59+
assert embedding_dimension.is_integer(), "embedding_dimension should be a whole number"
60+
61+
def test_models_list_structure(
62+
self,
63+
unprivileged_llama_stack_client: LlamaStackClient,
64+
) -> None:
65+
"""Test that model list response structure matches OpenAI SDK compatibility.
66+
67+
Verifies that each model in the list has the required fields expected
68+
by OpenAI-compatible clients.
69+
"""
70+
models = unprivileged_llama_stack_client.models.list()
71+
assert models is not None, "No models returned from LlamaStackClient"
72+
73+
for model in models:
74+
assert hasattr(model, "identifier"), "Model should have identifier attribute"
75+
assert hasattr(model, "api_model_type"), "Model should have api_model_type attribute"
76+
assert model.identifier is not None, f"Model {model} should have a non-None identifier"
77+
assert model.api_model_type in ["llm", "embedding"], (
78+
f"Model {model.identifier} should have api_model_type 'llm' or 'embedding', "
79+
f"got '{model.api_model_type}'"
80+
)
81+
assert hasattr(model, "metadata"), "Model should have metadata attribute"
82+
assert isinstance(model.metadata, dict), "Model metadata should be a dictionary"
83+
84+
def test_models_retrieve_existing(
85+
self,
86+
unprivileged_llama_stack_client: LlamaStackClient,
87+
) -> None:
88+
"""Test retrieving an existing model by ID.
89+
90+
Verifies that models.retrieve() returns the correct model when given
91+
a valid model identifier from the list.
92+
"""
93+
models = unprivileged_llama_stack_client.models.list()
94+
assert len(models) > 0, "At least one model should be available"
95+
96+
test_model = models[0]
97+
retrieved_model = unprivileged_llama_stack_client.models.retrieve(model_id=test_model.identifier)
5498

55-
def test_models_register(self, llama_stack_client: LlamaStackClient) -> None:
56-
"""Test model registration functionality."""
57-
response = llama_stack_client.models.register(
58-
provider_id=LlamaStackProviders.Inference.VLLM_INFERENCE, model_type="llm", model_id=QWEN_MODEL_NAME
99+
assert retrieved_model is not None, f"Model {test_model.identifier} should be retrievable"
100+
assert isinstance(retrieved_model, Model), "Retrieved model should be a Model instance"
101+
assert retrieved_model.identifier == test_model.identifier, (
102+
f"Retrieved model identifier '{retrieved_model.identifier}' "
103+
f"should match requested '{test_model.identifier}'"
59104
)
60-
assert response
105+
assert retrieved_model.api_model_type == test_model.api_model_type, (
106+
f"Retrieved model type '{retrieved_model.api_model_type}' "
107+
f"should match original '{test_model.api_model_type}'"
108+
)
109+
110+
def test_models_retrieve_nonexistent(
111+
self,
112+
unprivileged_llama_stack_client: LlamaStackClient,
113+
) -> None:
114+
"""Test retrieving a non-existent model raises NotFoundError.
115+
116+
Verifies that models.retrieve() raises NotFoundError when given
117+
an invalid model identifier, matching OpenAI SDK behavior.
118+
"""
119+
nonexistent_model_id = "nonexistent-provider/nonexistent-model"
61120

62-
def test_model_list(self, llama_stack_client: LlamaStackClient) -> None:
63-
"""Test listing available models and verify their properties."""
64-
models = llama_stack_client.models.list()
121+
with pytest.raises(NotFoundError):
122+
unprivileged_llama_stack_client.models.retrieve(model_id=nonexistent_model_id)
65123

66-
# Find the registered LLM by identifier suffix
67-
expected_id_suffix = f"/{QWEN_MODEL_NAME}"
68-
target = next(
69-
(model for model in models if model.model_type == "llm" and model.identifier.endswith(expected_id_suffix)),
70-
None,
124+
def test_models_register(
125+
self,
126+
unprivileged_llama_stack_client: LlamaStackClient,
127+
) -> None:
128+
"""Test registering a new model.
129+
130+
Verifies that models.register() successfully registers a new model
131+
and it appears in the models list.
132+
"""
133+
inference_model = os.getenv("LLS_CORE_INFERENCE_MODEL")
134+
assert inference_model, "LLS_CORE_INFERENCE_MODEL environment variable must be set"
135+
test_model_id = f"{inference_model}-test-register"
136+
137+
response = unprivileged_llama_stack_client.models.register(
138+
model_id=test_model_id,
139+
model_type="llm",
140+
provider_id=LlamaStackProviders.Inference.VLLM_INFERENCE,
71141
)
72-
assert target is not None, (
73-
f"LLM {QWEN_MODEL_NAME} not found in models: {[model.identifier for model in models]}"
142+
assert response is not None, "Model registration should return a response"
143+
144+
registered_model_id = f"{LlamaStackProviders.Inference.VLLM_INFERENCE.value}/{test_model_id}"
145+
try:
146+
models = unprivileged_llama_stack_client.models.list()
147+
registered_model_ids = [model.identifier for model in models]
148+
assert registered_model_id in registered_model_ids, (
149+
f"Registered model {registered_model_id} should appear in models list"
150+
)
151+
finally:
152+
unprivileged_llama_stack_client.models.unregister(model_id=registered_model_id)
153+
154+
def test_models_register_retrieve_unregister(
155+
self,
156+
unprivileged_llama_stack_client: LlamaStackClient,
157+
) -> None:
158+
"""Test complete model lifecycle: register, retrieve, and unregister.
159+
160+
Verifies the full workflow of registering a model, retrieving it,
161+
verifying its properties, and then unregistering it.
162+
"""
163+
inference_model = os.getenv("LLS_CORE_INFERENCE_MODEL")
164+
assert inference_model, "LLS_CORE_INFERENCE_MODEL environment variable must be set"
165+
test_model_id = f"{inference_model}-test-lifecycle"
166+
167+
response = unprivileged_llama_stack_client.models.register(
168+
model_id=test_model_id,
169+
model_type="llm",
170+
provider_id=LlamaStackProviders.Inference.VLLM_INFERENCE,
74171
)
75-
assert target.identifier.endswith(expected_id_suffix)
76-
assert target.model_type == "llm"
77-
assert target.provider_id == LlamaStackProviders.Inference.VLLM_INFERENCE.value
172+
assert response is not None, "Model registration should return a response"
173+
174+
registered_model_id = f"{LlamaStackProviders.Inference.VLLM_INFERENCE.value}/{test_model_id}"
175+
try:
176+
registered_model = unprivileged_llama_stack_client.models.retrieve(model_id=registered_model_id)
177+
assert registered_model is not None, f"LLM {registered_model_id} not found using models.retrieve"
178+
assert isinstance(registered_model, Model), "Retrieved model should be a Model instance"
179+
expected_id_suffix = f"/{test_model_id}"
180+
assert registered_model.identifier.endswith(expected_id_suffix), (
181+
f"Model identifier '{registered_model.identifier}' should end with '{expected_id_suffix}'"
182+
)
183+
assert registered_model.api_model_type == "llm", (
184+
f"Registered model should have api_model_type 'llm', got '{registered_model.api_model_type}'"
185+
)
186+
assert registered_model.provider_id == LlamaStackProviders.Inference.VLLM_INFERENCE.value, (
187+
f"Registered model provider_id should be '{LlamaStackProviders.Inference.VLLM_INFERENCE.value}', "
188+
f"got '{registered_model.provider_id}'"
189+
)
190+
finally:
191+
unprivileged_llama_stack_client.models.unregister(model_id=registered_model_id)
192+
193+
with pytest.raises(NotFoundError):
194+
unprivileged_llama_stack_client.models.retrieve(model_id=registered_model_id)

0 commit comments

Comments
 (0)