0
# Exception Handling
1
2
Comprehensive exception hierarchy for detailed error reporting and debugging, covering schema validation, key mismatches, protocol errors, and configuration issues.
3
4
## Capabilities
5
6
### Base Exception Class
7
8
Root exception class for all Tavern-specific errors with contextual information about test execution.
9
10
```python { .api }
11
class TavernException(Exception):
12
"""
13
Base exception class for all Tavern errors.
14
15
Attributes:
16
- stage: Optional dictionary containing current test stage information
17
- test_block_config: Optional test configuration object
18
- is_final: Boolean indicating if this is a final error (default: False)
19
"""
20
21
stage: Optional[dict]
22
test_block_config: Optional["TestConfig"]
23
is_final: bool = False
24
25
def __init__(self, message: str, **kwargs):
26
super().__init__(message)
27
self.stage = kwargs.get('stage')
28
self.test_block_config = kwargs.get('test_block_config')
29
self.is_final = kwargs.get('is_final', False)
30
```
31
32
## Validation Exceptions
33
34
### Schema Validation Errors
35
36
Exceptions related to schema validation and test specification format issues.
37
38
```python { .api }
39
class BadSchemaError(TavernException):
40
"""
41
Raised when test schema is invalid or malformed.
42
43
Common causes:
44
- Invalid YAML structure
45
- Missing required fields
46
- Incorrect data types in test specification
47
- Malformed validation functions
48
"""
49
50
class TestFailError(TavernException):
51
"""
52
Raised when a test fails validation or execution.
53
54
Common causes:
55
- Response validation failures
56
- Assertion errors
57
- Test execution timeouts
58
- Protocol-specific failures
59
"""
60
```
61
62
### Key Matching Errors
63
64
Exceptions for response validation and key matching issues.
65
66
```python { .api }
67
class KeyMismatchError(TavernException):
68
"""
69
Raised when response keys don't match expected values.
70
71
Common causes:
72
- JSON response structure differs from expected
73
- Missing keys in response
74
- Type mismatches in response values
75
"""
76
77
class UnexpectedKeysError(TavernException):
78
"""
79
Raised when request specification contains unexpected keys.
80
81
Common causes:
82
- Typos in request specification
83
- Using unsupported request parameters
84
- Plugin-specific parameter errors
85
"""
86
87
class MissingKeysError(TavernException):
88
"""
89
Raised when required keys are missing from request specification.
90
91
Common causes:
92
- Incomplete request specifications
93
- Missing required parameters for protocol
94
- Configuration errors
95
"""
96
```
97
98
### Template and Variable Errors
99
100
Exceptions related to variable templating and string formatting.
101
102
```python { .api }
103
class MissingFormatError(TavernException):
104
"""
105
Raised when template variable is not found during string formatting.
106
107
Common causes:
108
- Reference to undefined variable in template
109
- Typos in variable names
110
- Variable not saved from previous stage
111
- Missing global configuration variables
112
"""
113
```
114
115
## Protocol-Specific Exceptions
116
117
### HTTP/REST Exceptions
118
119
Exceptions specific to HTTP/REST API testing.
120
121
```python { .api }
122
class RestRequestException(TavernException):
123
"""
124
Raised when HTTP request execution fails.
125
126
Common causes:
127
- Network connectivity issues
128
- Invalid URLs
129
- HTTP client configuration errors
130
- Request timeout
131
- SSL/TLS certificate issues
132
"""
133
```
134
135
### MQTT Exceptions
136
137
Exceptions specific to MQTT protocol testing.
138
139
```python { .api }
140
class MQTTError(TavernException):
141
"""
142
Raised when MQTT operations fail.
143
144
Common causes:
145
- MQTT broker connection failures
146
- Subscription timeout
147
- Message publication errors
148
- Topic permission issues
149
- QoS level conflicts
150
"""
151
```
152
153
### gRPC Exceptions
154
155
Exceptions specific to gRPC protocol testing.
156
157
```python { .api }
158
class GRPCRequestException(TavernException):
159
"""
160
Raised when gRPC request execution fails.
161
162
Common causes:
163
- gRPC service unavailable
164
- Method not found
165
- Protocol buffer serialization errors
166
- Authentication failures
167
- Deadline exceeded
168
"""
169
```
170
171
## System and Configuration Exceptions
172
173
### Plugin and Loading Errors
174
175
Exceptions related to plugin loading and system configuration.
176
177
```python { .api }
178
class PluginLoadError(TavernException):
179
"""
180
Raised when plugin loading fails.
181
182
Common causes:
183
- Plugin not found
184
- Plugin import errors
185
- Incompatible plugin version
186
- Missing plugin dependencies
187
- Entry point configuration errors
188
"""
189
190
class InvalidSettingsError(TavernException):
191
"""
192
Raised when configuration is invalid or incorrectly formatted.
193
194
Common causes:
195
- Invalid global configuration file
196
- Malformed YAML configuration
197
- Missing configuration files
198
- Type errors in configuration values
199
- File permission issues
200
"""
201
```
202
203
### Validation Function Errors
204
205
Exceptions from response validation functions.
206
207
```python { .api }
208
class JMESError(TavernException):
209
"""
210
Raised when JMESPath query execution fails.
211
212
Common causes:
213
- Invalid JMESPath syntax
214
- JMESPath query returns None
215
- Type errors in query result
216
- Expected value mismatch
217
"""
218
219
class RegexAccessError(TavernException):
220
"""
221
Raised when regex validation fails.
222
223
Common causes:
224
- Regex pattern doesn't match content
225
- Invalid regex expression
226
- JMESPath extraction failure before regex
227
- Content type mismatch
228
"""
229
230
class UnexpectedExceptionError(TavernException):
231
"""
232
Raised when exception validation fails.
233
234
Common causes:
235
- Response doesn't match expected exception format
236
- Status code mismatch
237
- Exception description doesn't match
238
- Exception title/error field mismatch
239
"""
240
```
241
242
## Exception Usage Examples
243
244
### Basic Exception Handling
245
246
```python
247
from tavern.core import run
248
from tavern._core.exceptions import (
249
TavernException,
250
TestFailError,
251
BadSchemaError,
252
InvalidSettingsError
253
)
254
255
try:
256
exit_code = run("test_api.tavern.yaml")
257
except InvalidSettingsError as e:
258
print(f"Configuration error: {e}")
259
print(f"Stage: {e.stage}")
260
except BadSchemaError as e:
261
print(f"Schema validation error: {e}")
262
except TestFailError as e:
263
print(f"Test execution failed: {e}")
264
except TavernException as e:
265
print(f"Tavern error: {e}")
266
if e.test_block_config:
267
print(f"Test config: {e.test_block_config}")
268
```
269
270
### Validation Function Error Handling
271
272
```python
273
from tavern.helpers import validate_jwt, validate_regex
274
from tavern._core.exceptions import JMESError, RegexAccessError
275
276
try:
277
# JWT validation
278
jwt_data = validate_jwt(response, "access_token", verify_signature=False)
279
except Exception as e:
280
print(f"JWT validation failed: {e}")
281
282
try:
283
# Regex validation
284
regex_result = validate_regex(response, r"ID: (\d+)")
285
except RegexAccessError as e:
286
print(f"Regex matching failed: {e}")
287
288
try:
289
# JMESPath validation
290
from tavern.helpers import check_jmespath_match
291
result = check_jmespath_match(data, "users[0].id")
292
except JMESError as e:
293
print(f"JMESPath query failed: {e}")
294
```
295
296
### Plugin Development Error Handling
297
298
```python
299
from tavern.request import BaseRequest
300
from tavern._core.exceptions import TavernException
301
302
class CustomRequest(BaseRequest):
303
def run(self):
304
try:
305
return self.session.execute_request(self.rspec)
306
except ConnectionError as e:
307
raise TavernException(
308
f"Custom protocol connection failed: {e}",
309
stage=self.rspec,
310
test_block_config=self.test_block_config
311
)
312
except TimeoutError as e:
313
raise TavernException(
314
f"Custom protocol timeout: {e}",
315
stage=self.rspec,
316
test_block_config=self.test_block_config,
317
is_final=True # Mark as final error
318
)
319
```
320
321
### Exception Context in YAML Tests
322
323
```yaml
324
# Validation functions can raise exceptions that provide context
325
test_name: Error handling example
326
327
stages:
328
- name: Test with potential validation errors
329
request:
330
url: https://api.example.com/data
331
method: GET
332
response:
333
status_code: 200
334
validate:
335
# This might raise JMESError if path not found
336
- function: tavern.helpers:check_jmespath_match
337
extra_kwargs:
338
query: "data.nonexistent_field"
339
expected: "some_value"
340
341
# This might raise RegexAccessError if pattern doesn't match
342
- function: tavern.helpers:validate_regex
343
extra_kwargs:
344
expression: "Order #([0-9]+)"
345
header: "X-Order-ID"
346
```
347
348
### Custom Exception Classes
349
350
```python
351
# Custom exceptions for specific use cases
352
class APIRateLimitError(TavernException):
353
"""Raised when API rate limit is exceeded."""
354
pass
355
356
class AuthenticationError(TavernException):
357
"""Raised when authentication fails."""
358
pass
359
360
class DataValidationError(TavernException):
361
"""Raised when response data validation fails."""
362
pass
363
364
# Usage in custom validation functions
365
def validate_api_response(response, expected_data):
366
if response.status_code == 429:
367
raise APIRateLimitError("API rate limit exceeded")
368
369
if response.status_code == 401:
370
raise AuthenticationError("Authentication failed")
371
372
if not validate_response_data(response.json(), expected_data):
373
raise DataValidationError(
374
"Response data validation failed",
375
stage={'response': response.json()},
376
is_final=True
377
)
378
```
379
380
## Error Context and Debugging
381
382
### Accessing Exception Context
383
384
```python
385
def handle_tavern_exception(e: TavernException):
386
"""Extract useful debugging information from Tavern exceptions."""
387
388
print(f"Error: {e}")
389
390
if e.stage:
391
print(f"Failed stage: {e.stage}")
392
393
if e.test_block_config:
394
print(f"Test variables: {e.test_block_config.variables}")
395
print(f"Test name: {e.test_block_config.test_name}")
396
397
if e.is_final:
398
print("This is a final error - test execution should stop")
399
```
400
401
### Exception Hierarchy for Debugging
402
403
```python
404
# Exception hierarchy allows for specific error handling
405
try:
406
run_tavern_tests()
407
except KeyMismatchError as e:
408
# Handle response validation specifically
409
log_response_mismatch(e)
410
except BadSchemaError as e:
411
# Handle schema issues specifically
412
fix_test_schema(e)
413
except MQTTError as e:
414
# Handle MQTT-specific issues
415
check_mqtt_broker(e)
416
except TavernException as e:
417
# Handle any other Tavern errors
418
log_general_error(e)
419
except Exception as e:
420
# Handle non-Tavern errors
421
log_unexpected_error(e)
422
```
423
424
## Types
425
426
```python { .api }
427
from typing import Optional
428
429
TestConfig = "tavern._core.pytest.config.TestConfig"
430
```