Skip to content

Commit 8b739c6

Browse files
committed
feat: add exhaustive SDK test suite
1 parent 15eb16b commit 8b739c6

53 files changed

Lines changed: 9692 additions & 25 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.genignore

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,7 @@ examples/*
44
src/mistralai/extra/*
55
pylintrc
66
scripts/prepare_readme.py
7-
tests/test_azure_integration.py
8-
tests/test_azure_v2_parity.py
9-
tests/test_gcp_integration.py
10-
tests/test_gcp_v2_parity.py
7+
scripts/run_all_tests.sh
118
tests/test_prepare_readme.py
9+
tests/unit/**
10+
tests/test_integration.py

.github/workflows/test_custom_code.yaml

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,5 +32,47 @@ jobs:
3232
- name: Run the 'src/mistralai/extra' package unit tests
3333
run: uv run python3.12 -m unittest discover -s src/mistralai/extra/tests -t src
3434

35-
- name: Run pytest for repository tests
36-
run: uv run pytest tests/
35+
- name: Run unit tests
36+
run: |
37+
uv run pytest tests/unit/ -v --tb=short -x
38+
uv run pytest packages/azure/tests/unit/ -v --tb=short -x
39+
uv run pytest packages/gcp/tests/unit/ -v --tb=short -x
40+
41+
- name: Run parity tests
42+
run: |
43+
uv run pytest packages/azure/tests/test_azure_v2_parity.py -v
44+
uv run pytest packages/gcp/tests/test_gcp_v2_parity.py -v
45+
46+
- name: Set up Go
47+
uses: actions/setup-go@v5
48+
with:
49+
go-version: '1.21'
50+
51+
- name: Start Speakeasy mock server
52+
run: |
53+
cd tests/mockserver
54+
go run . -address :18080 &
55+
sleep 3
56+
curl -sf http://localhost:18080/_mockserver/health || echo "Mock server health check failed"
57+
58+
- name: Run Speakeasy contract tests
59+
run: uv run pytest tests/ --ignore=tests/unit/ -m "not integration"
60+
61+
- name: Run main SDK integration tests
62+
if: ${{ secrets.MISTRAL_API_KEY != '' }}
63+
env:
64+
MISTRAL_API_KEY: ${{ secrets.MISTRAL_API_KEY }}
65+
run: uv run pytest tests/test_integration.py -v
66+
67+
- name: Run Azure integration tests
68+
if: ${{ secrets.AZURE_API_KEY != '' }}
69+
env:
70+
AZURE_API_KEY: ${{ secrets.AZURE_API_KEY }}
71+
AZURE_ENDPOINT: ${{ secrets.AZURE_ENDPOINT }}
72+
run: uv run pytest packages/azure/tests/test_azure_integration.py -v
73+
74+
- name: Run GCP integration tests
75+
if: ${{ secrets.GCP_PROJECT_ID != '' }}
76+
env:
77+
GCP_PROJECT_ID: ${{ secrets.GCP_PROJECT_ID }}
78+
run: uv run pytest packages/gcp/tests/test_gcp_integration.py -v

packages/azure/.genignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,6 @@ src/mistralai/azure/client/_hooks/registration.py
44
README.md
55
USAGE.md
66
docs/sdks/**/README.md
7+
tests/unit/**
8+
tests/test_azure_integration.py
9+
tests/test_azure_v2_parity.py

packages/azure/.speakeasy/tests.arazzo.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ workflows:
3939
contentType: application/json
4040
payload:
4141
document:
42-
document_url: httcan you ps://upset-labourer.net/
42+
document_url: https://upset-labourer.net/
4343
type: document_url
4444
model: CX-9
4545
successCriteria:

packages/azure/pyproject.toml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ dev = [
1919
"pytest>=8.2.2,<9",
2020
"pytest-asyncio>=0.23.7,<0.24",
2121
"pytest-xdist>=3.5.0,<4",
22+
"respx>=0.22.0,<0.23",
2223
]
2324

2425
[tool.setuptools.package-data]
@@ -46,6 +47,14 @@ build-backend = "hatchling.build"
4647

4748
[tool.pytest.ini_options]
4849
pythonpath = ["src"]
50+
asyncio_mode = "auto"
51+
markers = [
52+
"integration: marks tests requiring real API credentials",
53+
]
54+
filterwarnings = [
55+
"ignore:coroutine 'AsyncClient.aclose' was never awaited:RuntimeWarning",
56+
"ignore:Pydantic serializer warnings:UserWarning",
57+
]
4958

5059
[tool.mypy]
5160
disable_error_code = "misc"

tests/test_azure_integration.py renamed to packages/azure/tests/test_azure_integration.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
2. Tailscale connected via gw-0 exit node
1010
1111
Usage:
12-
AZURE_API_KEY=xxx pytest tests/test_azure_integration.py -v
12+
AZURE_API_KEY=xxx pytest packages/azure/tests/test_azure_integration.py -v
1313
1414
Environment variables:
1515
AZURE_API_KEY: API key (required)
@@ -42,10 +42,10 @@
4242

4343
SKIP_REASON = "AZURE_API_KEY env var required"
4444

45-
pytestmark = pytest.mark.skipif(
46-
not AZURE_API_KEY,
47-
reason=SKIP_REASON
48-
)
45+
pytestmark = [
46+
pytest.mark.skipif(not AZURE_API_KEY, reason=SKIP_REASON),
47+
pytest.mark.integration,
48+
]
4949

5050
# Shared tool definition for tool-call tests
5151
WEATHER_TOOL = {
@@ -64,7 +64,7 @@
6464

6565
@pytest.fixture
6666
def azure_client():
67-
"""Create an Azure client with api_version parameter."""
67+
"""Create an Azure client for integration tests."""
6868
from mistralai.azure.client import MistralAzure
6969
assert AZURE_API_KEY is not None, "AZURE_API_KEY must be set"
7070
return MistralAzure(
File renamed without changes.

packages/azure/tests/unit/__init__.py

Whitespace-only changes.
Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
"""Tests for MistralAzure constructor and api-version injection."""
2+
3+
import warnings
4+
5+
import httpx
6+
import pytest
7+
8+
from mistralai.azure.client.sdk import MistralAzure
9+
10+
11+
# -------------------------------------------------------------------------
12+
# 1. Default API version
13+
# -------------------------------------------------------------------------
14+
15+
16+
class TestDefaultApiVersion:
17+
def test_default_api_version(self):
18+
client = MistralAzure(
19+
api_key="test-key",
20+
server_url="https://test.azure.api",
21+
)
22+
23+
# The default api_version should be "2024-05-01-preview"
24+
# It should be injected into the httpx client's params
25+
params = client.sdk_configuration.client.params
26+
assert "api-version" in dict(params)
27+
assert dict(params)["api-version"] == "2024-05-01-preview"
28+
29+
30+
# -------------------------------------------------------------------------
31+
# 2. Custom API version
32+
# -------------------------------------------------------------------------
33+
34+
35+
class TestCustomApiVersion:
36+
def test_custom_api_version(self):
37+
client = MistralAzure(
38+
api_key="test-key",
39+
server_url="https://test.azure.api",
40+
api_version="2025-01-01",
41+
)
42+
43+
params = client.sdk_configuration.client.params
44+
assert dict(params)["api-version"] == "2025-01-01"
45+
46+
47+
# -------------------------------------------------------------------------
48+
# 3. API version in query params
49+
# -------------------------------------------------------------------------
50+
51+
52+
class TestApiVersionInQueryParams:
53+
def test_api_version_in_query_params(self):
54+
client = MistralAzure(
55+
api_key="test-key",
56+
server_url="https://test.azure.api",
57+
)
58+
59+
# Both sync and async clients should have the param
60+
sync_params = dict(client.sdk_configuration.client.params)
61+
assert sync_params["api-version"] == "2024-05-01-preview"
62+
63+
async_params = dict(client.sdk_configuration.async_client.params)
64+
assert async_params["api-version"] == "2024-05-01-preview"
65+
66+
67+
# -------------------------------------------------------------------------
68+
# 4. Context manager works
69+
# -------------------------------------------------------------------------
70+
71+
72+
class TestContextManager:
73+
def test_context_manager(self):
74+
with MistralAzure(
75+
api_key="test-key",
76+
server_url="https://test.azure.api",
77+
) as m:
78+
assert isinstance(m, MistralAzure)
79+
assert m.sdk_configuration.client is not None
80+
81+
82+
# -------------------------------------------------------------------------
83+
# 5. dir() includes sub SDKs
84+
# -------------------------------------------------------------------------
85+
86+
87+
class TestDirIncludesSubSdks:
88+
def test_dir_includes_sub_sdks(self):
89+
client = MistralAzure(
90+
api_key="test-key",
91+
server_url="https://test.azure.api",
92+
)
93+
94+
d = dir(client)
95+
assert "chat" in d
96+
assert "ocr" in d
97+
98+
99+
# -------------------------------------------------------------------------
100+
# 6. Warning when custom client + non-default api_version
101+
# -------------------------------------------------------------------------
102+
103+
104+
class TestApiVersionWarningWithCustomClient:
105+
def test_api_version_warning_with_custom_client(self):
106+
custom_client = httpx.Client()
107+
try:
108+
with warnings.catch_warnings(record=True) as w:
109+
warnings.simplefilter("always")
110+
client = MistralAzure(
111+
api_key="test-key",
112+
server_url="https://test.azure.api",
113+
client=custom_client,
114+
api_version="2025-01-01",
115+
)
116+
assert len(w) >= 1
117+
assert "api_version is ignored" in str(w[0].message)
118+
finally:
119+
custom_client.close()
120+
121+
122+
# -------------------------------------------------------------------------
123+
# 7. Chat complete via respx verifies api-version in request
124+
# -------------------------------------------------------------------------
125+
126+
127+
class TestChatCompleteViaRespx:
128+
def test_chat_complete_sends_api_version(self):
129+
"""Azure chat.complete() sends api-version query parameter."""
130+
import respx
131+
132+
client = MistralAzure(
133+
api_key="test-key",
134+
server_url="https://test.azure.api",
135+
)
136+
137+
chat_response = {
138+
"id": "test-001",
139+
"object": "chat.completion",
140+
"model": "mistral-small-latest",
141+
"created": 1700000000,
142+
"choices": [
143+
{
144+
"index": 0,
145+
"message": {"role": "assistant", "content": "Hello."},
146+
"finish_reason": "stop",
147+
}
148+
],
149+
"usage": {
150+
"prompt_tokens": 10,
151+
"completion_tokens": 5,
152+
"total_tokens": 15,
153+
},
154+
}
155+
156+
with respx.mock(base_url="https://test.azure.api") as router:
157+
# Azure SDK strips /v1/ prefix from paths
158+
route = router.post("/chat/completions").mock(
159+
return_value=httpx.Response(200, json=chat_response)
160+
)
161+
result = client.chat.complete(
162+
model="mistral-small-latest",
163+
messages=[{"role": "user", "content": "Hi"}],
164+
)
165+
166+
assert result is not None
167+
assert result.id == "test-001"
168+
# Verify api-version was in the query params
169+
assert route.called
170+
request = route.calls.last.request
171+
assert "api-version" in str(request.url)

packages/gcp/.genignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,8 @@ src/mistralai/gcp/client/_hooks/registration.py
44
README.md
55
USAGE.md
66
docs/sdks/**/README.md
7+
tests/unit/**
8+
tests/test_gcp_integration.py
9+
tests/test_gcp_v2_parity.py
710
tests/test_chat.py
811
tests/test_fim.py

0 commit comments

Comments
 (0)