|
8 | 8 | from opentelemetry.sdk.trace.export.in_memory_span_exporter import InMemorySpanExporter |
9 | 9 | from opentelemetry.trace import set_tracer_provider |
10 | 10 |
|
11 | | -from slm_server.app import DETAIL_SEM_TIMEOUT, app, get_llm |
| 11 | +from slm_server.app import DETAIL_SEM_TIMEOUT, app, get_llm, get_settings |
| 12 | +from slm_server.config import Settings |
12 | 13 |
|
13 | 14 | # Create a mock Llama instance |
14 | 15 | mock_llama = MagicMock() |
@@ -266,11 +267,10 @@ def test_metrics_endpoint_integration(): |
266 | 267 | assert "python_info" in content |
267 | 268 | assert "process_virtual_memory_bytes" in content |
268 | 269 |
|
269 | | - # Verify custom SLM metrics are present (even if empty) |
270 | | - assert "slm_completion_duration_seconds" in content |
271 | | - assert "slm_tokens_total" in content |
272 | | - assert "slm_completion_tokens_per_second" in content |
273 | | - assert "slm_first_token_delay_ms" in content |
| 270 | + # NOTE: SLM-specific metrics (slm_completion_duration_seconds, slm_tokens_total, |
| 271 | + # etc.) are only registered when tracing is fully configured with endpoint and |
| 272 | + # credentials. In the test environment tracing is not configured, so these |
| 273 | + # metrics are not expected here. They are tested via test_trace.py. |
274 | 274 |
|
275 | 275 |
|
276 | 276 | def test_streaming_call_with_tracing_integration(): |
@@ -733,3 +733,66 @@ def test_request_validation_and_defaults(): |
733 | 733 | assert call_args[1]["stream"] is False # Default value |
734 | 734 |
|
735 | 735 |
|
| 736 | +def test_list_models_structure(): |
| 737 | + """GET /api/v1/models returns OpenAI-compatible list with one model.""" |
| 738 | + response = client.get("/api/v1/models") |
| 739 | + assert response.status_code == 200 |
| 740 | + data = response.json() |
| 741 | + assert data["object"] == "list" |
| 742 | + assert isinstance(data["data"], list) |
| 743 | + assert len(data["data"]) == 1 |
| 744 | + model = data["data"][0] |
| 745 | + assert model["object"] == "model" |
| 746 | + assert "id" in model and isinstance(model["id"], str) |
| 747 | + assert "created" in model and isinstance(model["created"], int) |
| 748 | + assert model["owned_by"] == "second-state" |
| 749 | + |
| 750 | + |
| 751 | +def test_list_models_with_overridden_settings(): |
| 752 | + """GET /api/v1/models uses model_path and model_owner from settings.""" |
| 753 | + settings = Settings( |
| 754 | + model_path="/tmp/SomeModel.gguf", |
| 755 | + model_owner="custom-org", |
| 756 | + ) |
| 757 | + |
| 758 | + def override_settings(): |
| 759 | + return settings |
| 760 | + |
| 761 | + app.dependency_overrides[get_settings] = override_settings |
| 762 | + try: |
| 763 | + response = client.get("/api/v1/models") |
| 764 | + assert response.status_code == 200 |
| 765 | + data = response.json() |
| 766 | + assert data["object"] == "list" |
| 767 | + assert len(data["data"]) == 1 |
| 768 | + model = data["data"][0] |
| 769 | + assert model["id"] == "SomeModel" |
| 770 | + assert model["object"] == "model" |
| 771 | + assert model["owned_by"] == "custom-org" |
| 772 | + assert model["created"] == 0 # file does not exist |
| 773 | + finally: |
| 774 | + app.dependency_overrides.pop(get_settings, None) |
| 775 | + |
| 776 | + |
| 777 | +def test_list_models_created_from_existing_file(tmp_path): |
| 778 | + """GET /api/v1/models returns file mtime as created when model file exists.""" |
| 779 | + model_file = tmp_path / "RealModel.gguf" |
| 780 | + model_file.write_bytes(b"\x00") |
| 781 | + |
| 782 | + settings = Settings(model_path=str(model_file)) |
| 783 | + |
| 784 | + def override_settings(): |
| 785 | + return settings |
| 786 | + |
| 787 | + app.dependency_overrides[get_settings] = override_settings |
| 788 | + try: |
| 789 | + response = client.get("/api/v1/models") |
| 790 | + assert response.status_code == 200 |
| 791 | + model = response.json()["data"][0] |
| 792 | + assert model["id"] == "RealModel" |
| 793 | + assert model["created"] > 0 |
| 794 | + assert model["created"] == int(model_file.stat().st_mtime) |
| 795 | + finally: |
| 796 | + app.dependency_overrides.pop(get_settings, None) |
| 797 | + |
| 798 | + |
0 commit comments