schemathesis 3.39.7__py3-none-any.whl → 4.0.0a2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- schemathesis/__init__.py +27 -65
- schemathesis/auths.py +26 -68
- schemathesis/checks.py +130 -60
- schemathesis/cli/__init__.py +5 -2105
- schemathesis/cli/commands/__init__.py +37 -0
- schemathesis/cli/commands/run/__init__.py +662 -0
- schemathesis/cli/commands/run/checks.py +80 -0
- schemathesis/cli/commands/run/context.py +117 -0
- schemathesis/cli/commands/run/events.py +30 -0
- schemathesis/cli/commands/run/executor.py +141 -0
- schemathesis/cli/commands/run/filters.py +202 -0
- schemathesis/cli/commands/run/handlers/__init__.py +46 -0
- schemathesis/cli/commands/run/handlers/base.py +18 -0
- schemathesis/cli/{cassettes.py → commands/run/handlers/cassettes.py} +178 -247
- schemathesis/cli/commands/run/handlers/junitxml.py +54 -0
- schemathesis/cli/commands/run/handlers/output.py +1368 -0
- schemathesis/cli/commands/run/hypothesis.py +105 -0
- schemathesis/cli/commands/run/loaders.py +129 -0
- schemathesis/cli/{callbacks.py → commands/run/validation.py} +59 -175
- schemathesis/cli/constants.py +5 -58
- schemathesis/cli/core.py +17 -0
- schemathesis/cli/ext/fs.py +14 -0
- schemathesis/cli/ext/groups.py +55 -0
- schemathesis/cli/{options.py → ext/options.py} +37 -16
- schemathesis/cli/hooks.py +36 -0
- schemathesis/contrib/__init__.py +1 -3
- schemathesis/contrib/openapi/__init__.py +1 -3
- schemathesis/contrib/openapi/fill_missing_examples.py +3 -7
- schemathesis/core/__init__.py +58 -0
- schemathesis/core/compat.py +25 -0
- schemathesis/core/control.py +2 -0
- schemathesis/core/curl.py +58 -0
- schemathesis/core/deserialization.py +65 -0
- schemathesis/core/errors.py +370 -0
- schemathesis/core/failures.py +315 -0
- schemathesis/core/fs.py +19 -0
- schemathesis/core/loaders.py +104 -0
- schemathesis/core/marks.py +66 -0
- schemathesis/{transports/content_types.py → core/media_types.py} +14 -12
- schemathesis/{internal/output.py → core/output/__init__.py} +1 -0
- schemathesis/core/output/sanitization.py +197 -0
- schemathesis/{throttling.py → core/rate_limit.py} +16 -17
- schemathesis/core/registries.py +31 -0
- schemathesis/core/transforms.py +113 -0
- schemathesis/core/transport.py +108 -0
- schemathesis/core/validation.py +38 -0
- schemathesis/core/version.py +7 -0
- schemathesis/engine/__init__.py +30 -0
- schemathesis/engine/config.py +59 -0
- schemathesis/engine/context.py +119 -0
- schemathesis/engine/control.py +36 -0
- schemathesis/engine/core.py +157 -0
- schemathesis/engine/errors.py +394 -0
- schemathesis/engine/events.py +243 -0
- schemathesis/engine/phases/__init__.py +66 -0
- schemathesis/{runner → engine/phases}/probes.py +49 -68
- schemathesis/engine/phases/stateful/__init__.py +66 -0
- schemathesis/engine/phases/stateful/_executor.py +301 -0
- schemathesis/engine/phases/stateful/context.py +85 -0
- schemathesis/engine/phases/unit/__init__.py +175 -0
- schemathesis/engine/phases/unit/_executor.py +322 -0
- schemathesis/engine/phases/unit/_pool.py +74 -0
- schemathesis/engine/recorder.py +246 -0
- schemathesis/errors.py +31 -0
- schemathesis/experimental/__init__.py +9 -40
- schemathesis/filters.py +7 -95
- schemathesis/generation/__init__.py +3 -3
- schemathesis/generation/case.py +190 -0
- schemathesis/generation/coverage.py +22 -22
- schemathesis/{_patches.py → generation/hypothesis/__init__.py} +15 -6
- schemathesis/generation/hypothesis/builder.py +585 -0
- schemathesis/generation/{_hypothesis.py → hypothesis/examples.py} +2 -11
- schemathesis/generation/hypothesis/given.py +66 -0
- schemathesis/generation/hypothesis/reporting.py +14 -0
- schemathesis/generation/hypothesis/strategies.py +16 -0
- schemathesis/generation/meta.py +115 -0
- schemathesis/generation/modes.py +28 -0
- schemathesis/generation/overrides.py +96 -0
- schemathesis/generation/stateful/__init__.py +20 -0
- schemathesis/{stateful → generation/stateful}/state_machine.py +84 -109
- schemathesis/generation/targets.py +69 -0
- schemathesis/graphql/__init__.py +15 -0
- schemathesis/graphql/checks.py +109 -0
- schemathesis/graphql/loaders.py +131 -0
- schemathesis/hooks.py +17 -62
- schemathesis/openapi/__init__.py +13 -0
- schemathesis/openapi/checks.py +387 -0
- schemathesis/openapi/generation/__init__.py +0 -0
- schemathesis/openapi/generation/filters.py +63 -0
- schemathesis/openapi/loaders.py +178 -0
- schemathesis/pytest/__init__.py +5 -0
- schemathesis/pytest/control_flow.py +7 -0
- schemathesis/pytest/lazy.py +273 -0
- schemathesis/pytest/loaders.py +12 -0
- schemathesis/{extra/pytest_plugin.py → pytest/plugin.py} +94 -107
- schemathesis/python/__init__.py +0 -0
- schemathesis/python/asgi.py +12 -0
- schemathesis/python/wsgi.py +12 -0
- schemathesis/schemas.py +456 -228
- schemathesis/specs/graphql/__init__.py +0 -1
- schemathesis/specs/graphql/_cache.py +1 -2
- schemathesis/specs/graphql/scalars.py +5 -3
- schemathesis/specs/graphql/schemas.py +122 -123
- schemathesis/specs/graphql/validation.py +11 -17
- schemathesis/specs/openapi/__init__.py +6 -1
- schemathesis/specs/openapi/_cache.py +1 -2
- schemathesis/specs/openapi/_hypothesis.py +97 -134
- schemathesis/specs/openapi/checks.py +238 -219
- schemathesis/specs/openapi/converter.py +4 -4
- schemathesis/specs/openapi/definitions.py +1 -1
- schemathesis/specs/openapi/examples.py +22 -20
- schemathesis/specs/openapi/expressions/__init__.py +11 -15
- schemathesis/specs/openapi/expressions/extractors.py +1 -4
- schemathesis/specs/openapi/expressions/nodes.py +33 -32
- schemathesis/specs/openapi/formats.py +3 -2
- schemathesis/specs/openapi/links.py +123 -299
- schemathesis/specs/openapi/media_types.py +10 -12
- schemathesis/specs/openapi/negative/__init__.py +2 -1
- schemathesis/specs/openapi/negative/mutations.py +3 -2
- schemathesis/specs/openapi/parameters.py +8 -6
- schemathesis/specs/openapi/patterns.py +1 -1
- schemathesis/specs/openapi/references.py +11 -51
- schemathesis/specs/openapi/schemas.py +177 -191
- schemathesis/specs/openapi/security.py +1 -1
- schemathesis/specs/openapi/serialization.py +10 -6
- schemathesis/specs/openapi/stateful/__init__.py +97 -91
- schemathesis/transport/__init__.py +104 -0
- schemathesis/transport/asgi.py +26 -0
- schemathesis/transport/prepare.py +99 -0
- schemathesis/transport/requests.py +221 -0
- schemathesis/{_xml.py → transport/serialization.py} +69 -7
- schemathesis/transport/wsgi.py +165 -0
- {schemathesis-3.39.7.dist-info → schemathesis-4.0.0a2.dist-info}/METADATA +18 -14
- schemathesis-4.0.0a2.dist-info/RECORD +151 -0
- {schemathesis-3.39.7.dist-info → schemathesis-4.0.0a2.dist-info}/entry_points.txt +1 -1
- schemathesis/_compat.py +0 -74
- schemathesis/_dependency_versions.py +0 -19
- schemathesis/_hypothesis.py +0 -559
- schemathesis/_override.py +0 -50
- schemathesis/_rate_limiter.py +0 -7
- schemathesis/cli/context.py +0 -75
- schemathesis/cli/debug.py +0 -27
- schemathesis/cli/handlers.py +0 -19
- schemathesis/cli/junitxml.py +0 -124
- schemathesis/cli/output/__init__.py +0 -1
- schemathesis/cli/output/default.py +0 -936
- schemathesis/cli/output/short.py +0 -59
- schemathesis/cli/reporting.py +0 -79
- schemathesis/cli/sanitization.py +0 -26
- schemathesis/code_samples.py +0 -151
- schemathesis/constants.py +0 -56
- schemathesis/contrib/openapi/formats/__init__.py +0 -9
- schemathesis/contrib/openapi/formats/uuid.py +0 -16
- schemathesis/contrib/unique_data.py +0 -41
- schemathesis/exceptions.py +0 -571
- schemathesis/extra/_aiohttp.py +0 -28
- schemathesis/extra/_flask.py +0 -13
- schemathesis/extra/_server.py +0 -18
- schemathesis/failures.py +0 -277
- schemathesis/fixups/__init__.py +0 -37
- schemathesis/fixups/fast_api.py +0 -41
- schemathesis/fixups/utf8_bom.py +0 -28
- schemathesis/generation/_methods.py +0 -44
- schemathesis/graphql.py +0 -3
- schemathesis/internal/__init__.py +0 -7
- schemathesis/internal/checks.py +0 -84
- schemathesis/internal/copy.py +0 -32
- schemathesis/internal/datetime.py +0 -5
- schemathesis/internal/deprecation.py +0 -38
- schemathesis/internal/diff.py +0 -15
- schemathesis/internal/extensions.py +0 -27
- schemathesis/internal/jsonschema.py +0 -36
- schemathesis/internal/transformation.py +0 -26
- schemathesis/internal/validation.py +0 -34
- schemathesis/lazy.py +0 -474
- schemathesis/loaders.py +0 -122
- schemathesis/models.py +0 -1341
- schemathesis/parameters.py +0 -90
- schemathesis/runner/__init__.py +0 -605
- schemathesis/runner/events.py +0 -389
- schemathesis/runner/impl/__init__.py +0 -3
- schemathesis/runner/impl/context.py +0 -104
- schemathesis/runner/impl/core.py +0 -1246
- schemathesis/runner/impl/solo.py +0 -80
- schemathesis/runner/impl/threadpool.py +0 -391
- schemathesis/runner/serialization.py +0 -544
- schemathesis/sanitization.py +0 -252
- schemathesis/serializers.py +0 -328
- schemathesis/service/__init__.py +0 -18
- schemathesis/service/auth.py +0 -11
- schemathesis/service/ci.py +0 -202
- schemathesis/service/client.py +0 -133
- schemathesis/service/constants.py +0 -38
- schemathesis/service/events.py +0 -61
- schemathesis/service/extensions.py +0 -224
- schemathesis/service/hosts.py +0 -111
- schemathesis/service/metadata.py +0 -71
- schemathesis/service/models.py +0 -258
- schemathesis/service/report.py +0 -255
- schemathesis/service/serialization.py +0 -173
- schemathesis/service/usage.py +0 -66
- schemathesis/specs/graphql/loaders.py +0 -364
- schemathesis/specs/openapi/expressions/context.py +0 -16
- schemathesis/specs/openapi/loaders.py +0 -708
- schemathesis/specs/openapi/stateful/statistic.py +0 -198
- schemathesis/specs/openapi/stateful/types.py +0 -14
- schemathesis/specs/openapi/validation.py +0 -26
- schemathesis/stateful/__init__.py +0 -147
- schemathesis/stateful/config.py +0 -97
- schemathesis/stateful/context.py +0 -135
- schemathesis/stateful/events.py +0 -274
- schemathesis/stateful/runner.py +0 -309
- schemathesis/stateful/sink.py +0 -68
- schemathesis/stateful/statistic.py +0 -22
- schemathesis/stateful/validation.py +0 -100
- schemathesis/targets.py +0 -77
- schemathesis/transports/__init__.py +0 -359
- schemathesis/transports/asgi.py +0 -7
- schemathesis/transports/auth.py +0 -38
- schemathesis/transports/headers.py +0 -36
- schemathesis/transports/responses.py +0 -57
- schemathesis/types.py +0 -44
- schemathesis/utils.py +0 -164
- schemathesis-3.39.7.dist-info/RECORD +0 -160
- /schemathesis/{extra → cli/ext}/__init__.py +0 -0
- /schemathesis/{_lazy_import.py → core/lazy_import.py} +0 -0
- /schemathesis/{internal → core}/result.py +0 -0
- {schemathesis-3.39.7.dist-info → schemathesis-4.0.0a2.dist-info}/WHEEL +0 -0
- {schemathesis-3.39.7.dist-info → schemathesis-4.0.0a2.dist-info}/licenses/LICENSE +0 -0
schemathesis/runner/events.py
DELETED
@@ -1,389 +0,0 @@
|
|
1
|
-
from __future__ import annotations
|
2
|
-
|
3
|
-
import enum
|
4
|
-
import threading
|
5
|
-
import time
|
6
|
-
from dataclasses import asdict, dataclass, field
|
7
|
-
from typing import TYPE_CHECKING, Any
|
8
|
-
|
9
|
-
from ..exceptions import RuntimeErrorType, SchemaError, SchemaErrorType, format_exception
|
10
|
-
from ..internal.datetime import current_datetime
|
11
|
-
from ..internal.result import Err, Ok, Result
|
12
|
-
from .serialization import SerializedError, SerializedTestResult
|
13
|
-
|
14
|
-
if TYPE_CHECKING:
|
15
|
-
from ..generation import DataGenerationMethod
|
16
|
-
from ..models import APIOperation, Status, TestResult, TestResultSet
|
17
|
-
from ..schemas import BaseSchema, Specification
|
18
|
-
from ..service.models import AnalysisResult
|
19
|
-
from ..stateful import events
|
20
|
-
from . import probes
|
21
|
-
|
22
|
-
|
23
|
-
@dataclass
|
24
|
-
class ExecutionEvent:
|
25
|
-
"""Generic execution event."""
|
26
|
-
|
27
|
-
# Whether this event is expected to be the last one in the event stream
|
28
|
-
is_terminal = False
|
29
|
-
|
30
|
-
def asdict(self, **kwargs: Any) -> dict[str, Any]:
|
31
|
-
data = asdict(self, **kwargs)
|
32
|
-
# An internal tag for simpler type identification
|
33
|
-
data["event_type"] = self.__class__.__name__
|
34
|
-
return data
|
35
|
-
|
36
|
-
|
37
|
-
@dataclass
|
38
|
-
class Initialized(ExecutionEvent):
|
39
|
-
"""Runner is initialized, settings are prepared, requests session is ready."""
|
40
|
-
|
41
|
-
schema: dict[str, Any]
|
42
|
-
specification: Specification
|
43
|
-
# Total number of operations in the schema
|
44
|
-
operations_count: int | None
|
45
|
-
# Total number of links in the schema
|
46
|
-
links_count: int | None
|
47
|
-
# The place, where the API schema is located
|
48
|
-
location: str | None
|
49
|
-
seed: int | None
|
50
|
-
# The base URL against which the tests are running
|
51
|
-
base_url: str
|
52
|
-
# The base path part of every operation
|
53
|
-
base_path: str
|
54
|
-
# API schema specification name
|
55
|
-
specification_name: str
|
56
|
-
# Monotonic clock value when the test run started. Used to properly calculate run duration, since this clock
|
57
|
-
# can't go backwards.
|
58
|
-
start_time: float = field(default_factory=time.monotonic)
|
59
|
-
# Datetime of the test run start
|
60
|
-
started_at: str = field(default_factory=current_datetime)
|
61
|
-
thread_id: int = field(default_factory=threading.get_ident)
|
62
|
-
|
63
|
-
@classmethod
|
64
|
-
def from_schema(
|
65
|
-
cls,
|
66
|
-
*,
|
67
|
-
schema: BaseSchema,
|
68
|
-
count_operations: bool = True,
|
69
|
-
count_links: bool = True,
|
70
|
-
start_time: float | None = None,
|
71
|
-
started_at: str | None = None,
|
72
|
-
seed: int | None,
|
73
|
-
) -> Initialized:
|
74
|
-
"""Computes all needed data from a schema instance."""
|
75
|
-
return cls(
|
76
|
-
schema=schema.raw_schema,
|
77
|
-
specification=schema.specification,
|
78
|
-
operations_count=schema.operations_count if count_operations else None,
|
79
|
-
links_count=schema.links_count if count_links else None,
|
80
|
-
location=schema.location,
|
81
|
-
base_url=schema.get_base_url(),
|
82
|
-
base_path=schema.base_path,
|
83
|
-
start_time=start_time or time.monotonic(),
|
84
|
-
started_at=started_at or current_datetime(),
|
85
|
-
specification_name=schema.verbose_name,
|
86
|
-
seed=seed,
|
87
|
-
)
|
88
|
-
|
89
|
-
|
90
|
-
@dataclass
|
91
|
-
class BeforeProbing(ExecutionEvent):
|
92
|
-
pass
|
93
|
-
|
94
|
-
|
95
|
-
@dataclass
|
96
|
-
class AfterProbing(ExecutionEvent):
|
97
|
-
probes: list[probes.ProbeRun] | None
|
98
|
-
|
99
|
-
def asdict(self, **kwargs: Any) -> dict[str, Any]:
|
100
|
-
probes = self.probes or []
|
101
|
-
return {"probes": [probe.serialize() for probe in probes], "events_type": self.__class__.__name__}
|
102
|
-
|
103
|
-
|
104
|
-
@dataclass
|
105
|
-
class BeforeAnalysis(ExecutionEvent):
|
106
|
-
pass
|
107
|
-
|
108
|
-
|
109
|
-
@dataclass
|
110
|
-
class AfterAnalysis(ExecutionEvent):
|
111
|
-
analysis: Result[AnalysisResult, Exception] | None
|
112
|
-
|
113
|
-
def _serialize(self) -> dict[str, Any]:
|
114
|
-
from ..service.models import AnalysisSuccess
|
115
|
-
|
116
|
-
data = {}
|
117
|
-
if isinstance(self.analysis, Ok):
|
118
|
-
result = self.analysis.ok()
|
119
|
-
if isinstance(result, AnalysisSuccess):
|
120
|
-
data["analysis_id"] = result.id
|
121
|
-
else:
|
122
|
-
data["error"] = result.message
|
123
|
-
elif isinstance(self.analysis, Err):
|
124
|
-
data["error"] = format_exception(self.analysis.err())
|
125
|
-
return data
|
126
|
-
|
127
|
-
def asdict(self, **kwargs: Any) -> dict[str, Any]:
|
128
|
-
data = self._serialize()
|
129
|
-
data["event_type"] = self.__class__.__name__
|
130
|
-
return data
|
131
|
-
|
132
|
-
|
133
|
-
class CurrentOperationMixin:
|
134
|
-
method: str
|
135
|
-
path: str
|
136
|
-
|
137
|
-
@property
|
138
|
-
def current_operation(self) -> str:
|
139
|
-
return f"{self.method} {self.path}"
|
140
|
-
|
141
|
-
|
142
|
-
@dataclass
|
143
|
-
class BeforeExecution(CurrentOperationMixin, ExecutionEvent):
|
144
|
-
"""Happens before each tested API operation.
|
145
|
-
|
146
|
-
It happens before a single hypothesis test, that may contain many examples inside.
|
147
|
-
"""
|
148
|
-
|
149
|
-
# HTTP method
|
150
|
-
method: str
|
151
|
-
# Full path, including the base path
|
152
|
-
path: str
|
153
|
-
# Specification-specific operation name
|
154
|
-
verbose_name: str
|
155
|
-
# Path without the base path
|
156
|
-
relative_path: str
|
157
|
-
# The current level of recursion during stateful testing
|
158
|
-
recursion_level: int
|
159
|
-
# The way data will be generated
|
160
|
-
data_generation_method: list[DataGenerationMethod]
|
161
|
-
# A unique ID which connects events that happen during testing of the same API operation
|
162
|
-
# It may be useful when multiple threads are involved where incoming events are not ordered
|
163
|
-
correlation_id: str
|
164
|
-
thread_id: int = field(default_factory=threading.get_ident)
|
165
|
-
|
166
|
-
@classmethod
|
167
|
-
def from_operation(
|
168
|
-
cls,
|
169
|
-
operation: APIOperation,
|
170
|
-
recursion_level: int,
|
171
|
-
data_generation_method: list[DataGenerationMethod],
|
172
|
-
correlation_id: str,
|
173
|
-
) -> BeforeExecution:
|
174
|
-
return cls(
|
175
|
-
method=operation.method.upper(),
|
176
|
-
path=operation.full_path,
|
177
|
-
verbose_name=operation.verbose_name,
|
178
|
-
relative_path=operation.path,
|
179
|
-
recursion_level=recursion_level,
|
180
|
-
data_generation_method=data_generation_method,
|
181
|
-
correlation_id=correlation_id,
|
182
|
-
)
|
183
|
-
|
184
|
-
|
185
|
-
@dataclass
|
186
|
-
class AfterExecution(CurrentOperationMixin, ExecutionEvent):
|
187
|
-
"""Happens after each tested API operation."""
|
188
|
-
|
189
|
-
method: str
|
190
|
-
path: str
|
191
|
-
relative_path: str
|
192
|
-
# Specification-specific operation name
|
193
|
-
verbose_name: str
|
194
|
-
|
195
|
-
# APIOperation test status - success / failure / error
|
196
|
-
status: Status
|
197
|
-
# The way data was generated
|
198
|
-
data_generation_method: list[DataGenerationMethod]
|
199
|
-
result: SerializedTestResult
|
200
|
-
# Test running time
|
201
|
-
elapsed_time: float
|
202
|
-
correlation_id: str
|
203
|
-
thread_id: int = field(default_factory=threading.get_ident)
|
204
|
-
# Captured hypothesis stdout
|
205
|
-
hypothesis_output: list[str] = field(default_factory=list)
|
206
|
-
|
207
|
-
@classmethod
|
208
|
-
def from_result(
|
209
|
-
cls,
|
210
|
-
result: TestResult,
|
211
|
-
status: Status,
|
212
|
-
elapsed_time: float,
|
213
|
-
hypothesis_output: list[str],
|
214
|
-
operation: APIOperation,
|
215
|
-
data_generation_method: list[DataGenerationMethod],
|
216
|
-
correlation_id: str,
|
217
|
-
) -> AfterExecution:
|
218
|
-
return cls(
|
219
|
-
method=operation.method.upper(),
|
220
|
-
path=operation.full_path,
|
221
|
-
relative_path=operation.path,
|
222
|
-
verbose_name=operation.verbose_name,
|
223
|
-
result=SerializedTestResult.from_test_result(result),
|
224
|
-
status=status,
|
225
|
-
elapsed_time=elapsed_time,
|
226
|
-
hypothesis_output=hypothesis_output,
|
227
|
-
data_generation_method=data_generation_method,
|
228
|
-
correlation_id=correlation_id,
|
229
|
-
)
|
230
|
-
|
231
|
-
|
232
|
-
@dataclass
|
233
|
-
class Interrupted(ExecutionEvent):
|
234
|
-
"""If execution was interrupted by Ctrl-C, or a received SIGTERM."""
|
235
|
-
|
236
|
-
thread_id: int = field(default_factory=threading.get_ident)
|
237
|
-
|
238
|
-
|
239
|
-
@enum.unique
|
240
|
-
class InternalErrorType(str, enum.Enum):
|
241
|
-
SCHEMA = "schema"
|
242
|
-
OTHER = "other"
|
243
|
-
|
244
|
-
|
245
|
-
DEFAULT_INTERNAL_ERROR_MESSAGE = "An internal error occurred during the test run"
|
246
|
-
|
247
|
-
|
248
|
-
@dataclass
|
249
|
-
class InternalError(ExecutionEvent):
|
250
|
-
"""An error that happened inside the runner."""
|
251
|
-
|
252
|
-
is_terminal = True
|
253
|
-
|
254
|
-
# Main error info
|
255
|
-
type: InternalErrorType
|
256
|
-
subtype: SchemaErrorType | None
|
257
|
-
title: str
|
258
|
-
message: str
|
259
|
-
extras: list[str]
|
260
|
-
|
261
|
-
# Exception info
|
262
|
-
exception_type: str
|
263
|
-
exception: str
|
264
|
-
exception_with_traceback: str
|
265
|
-
# Auxiliary data
|
266
|
-
thread_id: int = field(default_factory=threading.get_ident)
|
267
|
-
|
268
|
-
@classmethod
|
269
|
-
def from_schema_error(cls, error: SchemaError) -> InternalError:
|
270
|
-
return cls.with_exception(
|
271
|
-
error,
|
272
|
-
type_=InternalErrorType.SCHEMA,
|
273
|
-
subtype=error.type,
|
274
|
-
title="Schema Loading Error",
|
275
|
-
message=error.message,
|
276
|
-
extras=error.extras,
|
277
|
-
)
|
278
|
-
|
279
|
-
@classmethod
|
280
|
-
def from_exc(cls, exc: Exception) -> InternalError:
|
281
|
-
return cls.with_exception(
|
282
|
-
exc,
|
283
|
-
type_=InternalErrorType.OTHER,
|
284
|
-
subtype=None,
|
285
|
-
title="Test Execution Error",
|
286
|
-
message=DEFAULT_INTERNAL_ERROR_MESSAGE,
|
287
|
-
extras=[],
|
288
|
-
)
|
289
|
-
|
290
|
-
@classmethod
|
291
|
-
def with_exception(
|
292
|
-
cls,
|
293
|
-
exc: Exception,
|
294
|
-
type_: InternalErrorType,
|
295
|
-
subtype: SchemaErrorType | None,
|
296
|
-
title: str,
|
297
|
-
message: str,
|
298
|
-
extras: list[str],
|
299
|
-
) -> InternalError:
|
300
|
-
exception_type = f"{exc.__class__.__module__}.{exc.__class__.__qualname__}"
|
301
|
-
exception = format_exception(exc)
|
302
|
-
exception_with_traceback = format_exception(exc, include_traceback=True)
|
303
|
-
return cls(
|
304
|
-
type=type_,
|
305
|
-
subtype=subtype,
|
306
|
-
title=title,
|
307
|
-
message=message,
|
308
|
-
extras=extras,
|
309
|
-
exception_type=exception_type,
|
310
|
-
exception=exception,
|
311
|
-
exception_with_traceback=exception_with_traceback,
|
312
|
-
)
|
313
|
-
|
314
|
-
|
315
|
-
@dataclass
|
316
|
-
class StatefulEvent(ExecutionEvent):
|
317
|
-
"""Represents an event originating from the state machine runner."""
|
318
|
-
|
319
|
-
data: events.StatefulEvent
|
320
|
-
|
321
|
-
__slots__ = ("data",)
|
322
|
-
|
323
|
-
def asdict(self, **kwargs: Any) -> dict[str, Any]:
|
324
|
-
return {"data": self.data.asdict(**kwargs), "event_type": self.__class__.__name__}
|
325
|
-
|
326
|
-
|
327
|
-
@dataclass
|
328
|
-
class AfterStatefulExecution(ExecutionEvent):
|
329
|
-
"""Happens after the stateful test run."""
|
330
|
-
|
331
|
-
status: Status
|
332
|
-
result: SerializedTestResult
|
333
|
-
elapsed_time: float
|
334
|
-
data_generation_method: list[DataGenerationMethod]
|
335
|
-
thread_id: int = field(default_factory=threading.get_ident)
|
336
|
-
|
337
|
-
|
338
|
-
@dataclass
|
339
|
-
class Finished(ExecutionEvent):
|
340
|
-
"""The final event of the run.
|
341
|
-
|
342
|
-
No more events after this point.
|
343
|
-
"""
|
344
|
-
|
345
|
-
is_terminal = True
|
346
|
-
|
347
|
-
passed_count: int
|
348
|
-
skipped_count: int
|
349
|
-
failed_count: int
|
350
|
-
errored_count: int
|
351
|
-
|
352
|
-
has_failures: bool
|
353
|
-
has_errors: bool
|
354
|
-
has_logs: bool
|
355
|
-
is_empty: bool
|
356
|
-
generic_errors: list[SerializedError]
|
357
|
-
warnings: list[str]
|
358
|
-
|
359
|
-
total: dict[str, dict[str | Status, int]]
|
360
|
-
|
361
|
-
# Total test run execution time
|
362
|
-
running_time: float
|
363
|
-
thread_id: int = field(default_factory=threading.get_ident)
|
364
|
-
|
365
|
-
@classmethod
|
366
|
-
def from_results(cls, results: TestResultSet, running_time: float) -> Finished:
|
367
|
-
return cls(
|
368
|
-
passed_count=results.passed_count,
|
369
|
-
skipped_count=results.skipped_count,
|
370
|
-
failed_count=results.failed_count,
|
371
|
-
errored_count=results.errored_count,
|
372
|
-
has_failures=results.has_failures,
|
373
|
-
has_errors=results.has_errors,
|
374
|
-
has_logs=results.has_logs,
|
375
|
-
is_empty=results.is_empty,
|
376
|
-
total=results.total,
|
377
|
-
generic_errors=[
|
378
|
-
SerializedError.with_exception(
|
379
|
-
type_=RuntimeErrorType.SCHEMA_GENERIC,
|
380
|
-
exception=error,
|
381
|
-
title=error.full_path,
|
382
|
-
message=error.message,
|
383
|
-
extras=[],
|
384
|
-
)
|
385
|
-
for error in results.generic_errors
|
386
|
-
],
|
387
|
-
warnings=results.warnings,
|
388
|
-
running_time=running_time,
|
389
|
-
)
|
@@ -1,104 +0,0 @@
|
|
1
|
-
from __future__ import annotations
|
2
|
-
|
3
|
-
from dataclasses import dataclass
|
4
|
-
from typing import TYPE_CHECKING, Any
|
5
|
-
|
6
|
-
from ...constants import NOT_SET
|
7
|
-
from ...internal.checks import CheckConfig
|
8
|
-
from ...models import TestResult, TestResultSet
|
9
|
-
|
10
|
-
if TYPE_CHECKING:
|
11
|
-
import threading
|
12
|
-
|
13
|
-
from ..._override import CaseOverride
|
14
|
-
from ...exceptions import OperationSchemaError
|
15
|
-
from ...models import Case
|
16
|
-
from ...types import NotSet, RawAuth
|
17
|
-
|
18
|
-
|
19
|
-
@dataclass
|
20
|
-
class RunnerContext:
|
21
|
-
"""Holds context shared for a test run."""
|
22
|
-
|
23
|
-
data: TestResultSet
|
24
|
-
auth: RawAuth | None
|
25
|
-
seed: int | None
|
26
|
-
stop_event: threading.Event
|
27
|
-
unique_data: bool
|
28
|
-
outcome_cache: dict[int, BaseException | None]
|
29
|
-
checks_config: CheckConfig
|
30
|
-
override: CaseOverride | None
|
31
|
-
no_failfast: bool
|
32
|
-
|
33
|
-
__slots__ = (
|
34
|
-
"data",
|
35
|
-
"auth",
|
36
|
-
"seed",
|
37
|
-
"stop_event",
|
38
|
-
"unique_data",
|
39
|
-
"outcome_cache",
|
40
|
-
"checks_config",
|
41
|
-
"override",
|
42
|
-
"no_failfast",
|
43
|
-
)
|
44
|
-
|
45
|
-
def __init__(
|
46
|
-
self,
|
47
|
-
*,
|
48
|
-
seed: int | None,
|
49
|
-
auth: RawAuth | None,
|
50
|
-
stop_event: threading.Event,
|
51
|
-
unique_data: bool,
|
52
|
-
checks_config: CheckConfig,
|
53
|
-
override: CaseOverride | None,
|
54
|
-
no_failfast: bool,
|
55
|
-
) -> None:
|
56
|
-
self.data = TestResultSet(seed=seed)
|
57
|
-
self.auth = auth
|
58
|
-
self.seed = seed
|
59
|
-
self.stop_event = stop_event
|
60
|
-
self.outcome_cache = {}
|
61
|
-
self.unique_data = unique_data
|
62
|
-
self.checks_config = checks_config
|
63
|
-
self.override = override
|
64
|
-
self.no_failfast = no_failfast
|
65
|
-
|
66
|
-
def _repr_pretty_(self, *args: Any, **kwargs: Any) -> None: ...
|
67
|
-
|
68
|
-
@property
|
69
|
-
def is_stopped(self) -> bool:
|
70
|
-
return self.stop_event.is_set()
|
71
|
-
|
72
|
-
@property
|
73
|
-
def has_all_not_found(self) -> bool:
|
74
|
-
"""Check if all responses are 404."""
|
75
|
-
has_not_found = False
|
76
|
-
for entry in self.data.results:
|
77
|
-
for check in entry.checks:
|
78
|
-
if check.response is not None:
|
79
|
-
if check.response.status_code == 404:
|
80
|
-
has_not_found = True
|
81
|
-
else:
|
82
|
-
# There are non-404 responses, no reason to check any other response
|
83
|
-
return False
|
84
|
-
# Only happens if all responses are 404, or there are no responses at all.
|
85
|
-
# In the first case, it returns True, for the latter - False
|
86
|
-
return has_not_found
|
87
|
-
|
88
|
-
def add_result(self, result: TestResult) -> None:
|
89
|
-
self.data.append(result)
|
90
|
-
|
91
|
-
def add_generic_error(self, error: OperationSchemaError) -> None:
|
92
|
-
self.data.generic_errors.append(error)
|
93
|
-
|
94
|
-
def add_warning(self, message: str) -> None:
|
95
|
-
self.data.add_warning(message)
|
96
|
-
|
97
|
-
def cache_outcome(self, case: Case, outcome: BaseException | None) -> None:
|
98
|
-
self.outcome_cache[hash(case)] = outcome
|
99
|
-
|
100
|
-
def get_cached_outcome(self, case: Case) -> BaseException | None | NotSet:
|
101
|
-
return self.outcome_cache.get(hash(case), NOT_SET)
|
102
|
-
|
103
|
-
|
104
|
-
ALL_NOT_FOUND_WARNING_MESSAGE = "All API responses have a 404 status code. Did you specify the proper API location?"
|