-
Notifications
You must be signed in to change notification settings - Fork 3.3k
Expand file tree
/
Copy pathtest_exceptions.py
More file actions
224 lines (179 loc) · 7.54 KB
/
test_exceptions.py
File metadata and controls
224 lines (179 loc) · 7.54 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
"""Tests for MCP exception classes."""
import pickle
import pytest
from mcp.shared.exceptions import MCPError, UrlElicitationRequiredError
from mcp.types import URL_ELICITATION_REQUIRED, ElicitRequestURLParams, ErrorData
def test_url_elicitation_required_error_create_with_single_elicitation() -> None:
"""Test creating error with a single elicitation."""
elicitation = ElicitRequestURLParams(
mode="url",
message="Auth required",
url="https://example.com/auth",
elicitation_id="test-123",
)
error = UrlElicitationRequiredError([elicitation])
assert error.error.code == URL_ELICITATION_REQUIRED
assert error.error.message == "URL elicitation required"
assert len(error.elicitations) == 1
assert error.elicitations[0].elicitation_id == "test-123"
def test_url_elicitation_required_error_create_with_multiple_elicitations() -> None:
"""Test creating error with multiple elicitations uses plural message."""
elicitations = [
ElicitRequestURLParams(
mode="url",
message="Auth 1",
url="https://example.com/auth1",
elicitation_id="test-1",
),
ElicitRequestURLParams(
mode="url",
message="Auth 2",
url="https://example.com/auth2",
elicitation_id="test-2",
),
]
error = UrlElicitationRequiredError(elicitations)
assert error.error.message == "URL elicitations required" # Plural
assert len(error.elicitations) == 2
def test_url_elicitation_required_error_custom_message() -> None:
"""Test creating error with a custom message."""
elicitation = ElicitRequestURLParams(
mode="url",
message="Auth required",
url="https://example.com/auth",
elicitation_id="test-123",
)
error = UrlElicitationRequiredError([elicitation], message="Custom message")
assert error.error.message == "Custom message"
def test_url_elicitation_required_error_from_error_data() -> None:
"""Test reconstructing error from ErrorData."""
error_data = ErrorData(
code=URL_ELICITATION_REQUIRED,
message="URL elicitation required",
data={
"elicitations": [
{
"mode": "url",
"message": "Auth required",
"url": "https://example.com/auth",
"elicitationId": "test-123",
}
]
},
)
error = UrlElicitationRequiredError.from_error(error_data)
assert len(error.elicitations) == 1
assert error.elicitations[0].elicitation_id == "test-123"
assert error.elicitations[0].url == "https://example.com/auth"
def test_url_elicitation_required_error_from_error_data_wrong_code() -> None:
"""Test that from_error raises ValueError for wrong error code."""
error_data = ErrorData(
code=-32600, # Wrong code
message="Some other error",
data={},
)
with pytest.raises(ValueError, match="Expected error code"):
UrlElicitationRequiredError.from_error(error_data)
def test_url_elicitation_required_error_serialization_roundtrip() -> None:
"""Test that error can be serialized and reconstructed."""
original = UrlElicitationRequiredError(
[
ElicitRequestURLParams(
mode="url",
message="Auth required",
url="https://example.com/auth",
elicitation_id="test-123",
)
]
)
# Simulate serialization over wire
error_data = original.error
# Reconstruct
reconstructed = UrlElicitationRequiredError.from_error(error_data)
assert reconstructed.elicitations[0].elicitation_id == original.elicitations[0].elicitation_id
assert reconstructed.elicitations[0].url == original.elicitations[0].url
assert reconstructed.elicitations[0].message == original.elicitations[0].message
def test_url_elicitation_required_error_data_contains_elicitations() -> None:
"""Test that error data contains properly serialized elicitations."""
elicitation = ElicitRequestURLParams(
mode="url",
message="Please authenticate",
url="https://example.com/oauth",
elicitation_id="oauth-flow-1",
)
error = UrlElicitationRequiredError([elicitation])
assert error.error.data is not None
assert "elicitations" in error.error.data
elicit_data = error.error.data["elicitations"][0]
assert elicit_data["mode"] == "url"
assert elicit_data["message"] == "Please authenticate"
assert elicit_data["url"] == "https://example.com/oauth"
assert elicit_data["elicitationId"] == "oauth-flow-1"
def test_url_elicitation_required_error_inherits_from_mcp_error() -> None:
"""Test that UrlElicitationRequiredError inherits from MCPError."""
elicitation = ElicitRequestURLParams(
mode="url",
message="Auth required",
url="https://example.com/auth",
elicitation_id="test-123",
)
error = UrlElicitationRequiredError([elicitation])
assert isinstance(error, MCPError)
assert isinstance(error, Exception)
def test_url_elicitation_required_error_exception_message() -> None:
"""Test that exception message is set correctly."""
elicitation = ElicitRequestURLParams(
mode="url",
message="Auth required",
url="https://example.com/auth",
elicitation_id="test-123",
)
error = UrlElicitationRequiredError([elicitation])
# The exception's string representation should match the message
assert str(error) == "URL elicitation required"
def test_mcp_error_pickle_roundtrip() -> None:
"""Test that MCPError survives a pickle round-trip."""
original = MCPError(code=-32600, message="Invalid request", data={"detail": "bad"})
restored = pickle.loads(pickle.dumps(original))
assert type(restored) is MCPError
assert restored.error.code == original.error.code
assert restored.error.message == original.error.message
assert restored.error.data == original.error.data
def test_url_elicitation_required_error_pickle_roundtrip() -> None:
"""Test that UrlElicitationRequiredError survives a pickle round-trip."""
elicitations = [
ElicitRequestURLParams(
mode="url",
message="Auth required",
url="https://example.com/auth",
elicitation_id="test-123",
),
]
original = UrlElicitationRequiredError(elicitations, message="Please authenticate")
restored = pickle.loads(pickle.dumps(original))
assert type(restored) is UrlElicitationRequiredError
assert restored.error.code == URL_ELICITATION_REQUIRED
assert restored.error.message == "Please authenticate"
assert len(restored.elicitations) == 1
assert restored.elicitations[0].elicitation_id == "test-123"
assert restored.elicitations[0].url == "https://example.com/auth"
def test_url_elicitation_required_error_pickle_default_message() -> None:
"""Test pickle round-trip preserves the auto-generated default message."""
elicitations = [
ElicitRequestURLParams(
mode="url",
message="Auth",
url="https://example.com/auth",
elicitation_id="e1",
),
ElicitRequestURLParams(
mode="url",
message="Auth2",
url="https://example.com/auth2",
elicitation_id="e2",
),
]
original = UrlElicitationRequiredError(elicitations)
restored = pickle.loads(pickle.dumps(original))
assert restored.error.message == "URL elicitations required"
assert len(restored.elicitations) == 2