pytest-openapi 0.2.3.dev202603041917__tar.gz → 0.2.3.dev202603201619__tar.gz

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.
Files changed (21) hide show
  1. {pytest_openapi-0.2.3.dev202603041917/src/pytest_openapi.egg-info → pytest_openapi-0.2.3.dev202603201619}/PKG-INFO +1 -1
  2. pytest_openapi-0.2.3.dev202603201619/src/pytest_openapi/__init__.py +1 -0
  3. {pytest_openapi-0.2.3.dev202603041917 → pytest_openapi-0.2.3.dev202603201619}/src/pytest_openapi/contract.py +58 -8
  4. {pytest_openapi-0.2.3.dev202603041917 → pytest_openapi-0.2.3.dev202603201619/src/pytest_openapi.egg-info}/PKG-INFO +1 -1
  5. {pytest_openapi-0.2.3.dev202603041917 → pytest_openapi-0.2.3.dev202603201619}/tests/test_integration.py +78 -0
  6. pytest_openapi-0.2.3.dev202603041917/src/pytest_openapi/__init__.py +0 -1
  7. {pytest_openapi-0.2.3.dev202603041917 → pytest_openapi-0.2.3.dev202603201619}/LICENSE +0 -0
  8. {pytest_openapi-0.2.3.dev202603041917 → pytest_openapi-0.2.3.dev202603201619}/README.md +0 -0
  9. {pytest_openapi-0.2.3.dev202603041917 → pytest_openapi-0.2.3.dev202603201619}/pyproject.toml +0 -0
  10. {pytest_openapi-0.2.3.dev202603041917 → pytest_openapi-0.2.3.dev202603201619}/setup.cfg +0 -0
  11. {pytest_openapi-0.2.3.dev202603041917 → pytest_openapi-0.2.3.dev202603201619}/src/pytest_openapi/case_generator.py +0 -0
  12. {pytest_openapi-0.2.3.dev202603041917 → pytest_openapi-0.2.3.dev202603201619}/src/pytest_openapi/openapi.py +0 -0
  13. {pytest_openapi-0.2.3.dev202603041917 → pytest_openapi-0.2.3.dev202603201619}/src/pytest_openapi/plugin.py +0 -0
  14. {pytest_openapi-0.2.3.dev202603041917 → pytest_openapi-0.2.3.dev202603201619}/src/pytest_openapi.egg-info/SOURCES.txt +0 -0
  15. {pytest_openapi-0.2.3.dev202603041917 → pytest_openapi-0.2.3.dev202603201619}/src/pytest_openapi.egg-info/dependency_links.txt +0 -0
  16. {pytest_openapi-0.2.3.dev202603041917 → pytest_openapi-0.2.3.dev202603201619}/src/pytest_openapi.egg-info/entry_points.txt +0 -0
  17. {pytest_openapi-0.2.3.dev202603041917 → pytest_openapi-0.2.3.dev202603201619}/src/pytest_openapi.egg-info/requires.txt +0 -0
  18. {pytest_openapi-0.2.3.dev202603041917 → pytest_openapi-0.2.3.dev202603201619}/src/pytest_openapi.egg-info/top_level.txt +0 -0
  19. {pytest_openapi-0.2.3.dev202603041917 → pytest_openapi-0.2.3.dev202603201619}/tests/test_output_formats.py +0 -0
  20. {pytest_openapi-0.2.3.dev202603041917 → pytest_openapi-0.2.3.dev202603201619}/tests/test_plugin_behavior.py +0 -0
  21. {pytest_openapi-0.2.3.dev202603041917 → pytest_openapi-0.2.3.dev202603201619}/tests/test_unit.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pytest-openapi
3
- Version: 0.2.3.dev202603041917
3
+ Version: 0.2.3.dev202603201619
4
4
  Summary: `pytest --openapi` - an opinionated, lightweight black-box contract tester against a live API using its OpenAPI specification as the source of truth
5
5
  Author-email: Sinan Ozel <coding@sinan.slmail.me>
6
6
  License: MIT License
@@ -0,0 +1 @@
1
+ __version__ = "0.2.3.dev202603201619"
@@ -11,6 +11,56 @@ from .case_generator import generate_test_cases_for_schema
11
11
  test_reports = []
12
12
 
13
13
 
14
+ def collect_streaming_response(response):
15
+ """Collect and parse streaming response content into a structured
16
+ form.
17
+
18
+ Reads the buffered response text and parses SSE or NDJSON chunks.
19
+
20
+ Args:
21
+ response: requests.Response object with a streaming content-type
22
+
23
+ Returns:
24
+ list or str: List of parsed chunks for SSE/NDJSON, raw text otherwise
25
+ """
26
+ content_type = response.headers.get("Content-Type", "").lower()
27
+ text = response.text
28
+
29
+ if "text/event-stream" in content_type:
30
+ chunks = []
31
+ for line in text.splitlines():
32
+ line = line.strip()
33
+ if line.startswith("data:"):
34
+ data = line[5:].strip()
35
+ if not data:
36
+ continue
37
+ if data == "[DONE]":
38
+ chunks.append("[DONE]")
39
+ else:
40
+ try:
41
+ chunks.append(json.loads(data))
42
+ except (json.JSONDecodeError, ValueError):
43
+ chunks.append(data)
44
+ return chunks if chunks else text
45
+
46
+ if (
47
+ "application/x-ndjson" in content_type
48
+ or "application/stream+json" in content_type
49
+ ):
50
+ chunks = []
51
+ for line in text.splitlines():
52
+ line = line.strip()
53
+ if not line:
54
+ continue
55
+ try:
56
+ chunks.append(json.loads(line))
57
+ except (json.JSONDecodeError, ValueError):
58
+ chunks.append(line)
59
+ return chunks if chunks else text
60
+
61
+ return text
62
+
63
+
14
64
  def make_request(method, url, json=None, timeout=10):
15
65
  """Wrapper for HTTP requests that logs all requests and responses
16
66
  for reporting.
@@ -1066,7 +1116,7 @@ def test_post_endpoint(
1066
1116
  expected_status,
1067
1117
  expected_response,
1068
1118
  response.status_code,
1069
- f"[Streaming response: {content_type}]",
1119
+ collect_streaming_response(response),
1070
1120
  True,
1071
1121
  None,
1072
1122
  test_origin,
@@ -1085,7 +1135,7 @@ def test_post_endpoint(
1085
1135
  expected_status,
1086
1136
  expected_response,
1087
1137
  response.status_code,
1088
- f"[Streaming response: {content_type}]",
1138
+ collect_streaming_response(response),
1089
1139
  False,
1090
1140
  error_msg,
1091
1141
  test_origin,
@@ -1116,7 +1166,7 @@ def test_post_endpoint(
1116
1166
  expected_status,
1117
1167
  expected_response,
1118
1168
  response.status_code,
1119
- f"[Streaming response: {content_type}]",
1169
+ collect_streaming_response(response),
1120
1170
  True,
1121
1171
  None,
1122
1172
  test_origin,
@@ -1135,7 +1185,7 @@ def test_post_endpoint(
1135
1185
  expected_status,
1136
1186
  expected_response,
1137
1187
  response.status_code,
1138
- f"[Streaming response: {content_type}]",
1188
+ collect_streaming_response(response),
1139
1189
  False,
1140
1190
  error_msg,
1141
1191
  test_origin,
@@ -2200,7 +2250,7 @@ def test_post_endpoint_single(
2200
2250
  expected_status,
2201
2251
  expected_response,
2202
2252
  response.status_code,
2203
- f"[Streaming response: {content_type}]",
2253
+ collect_streaming_response(response),
2204
2254
  True,
2205
2255
  None,
2206
2256
  test_origin,
@@ -2219,7 +2269,7 @@ def test_post_endpoint_single(
2219
2269
  expected_status,
2220
2270
  expected_response,
2221
2271
  response.status_code,
2222
- f"[Streaming response: {content_type}]",
2272
+ collect_streaming_response(response),
2223
2273
  False,
2224
2274
  error_msg,
2225
2275
  test_origin,
@@ -2249,7 +2299,7 @@ def test_post_endpoint_single(
2249
2299
  expected_status,
2250
2300
  expected_response,
2251
2301
  response.status_code,
2252
- f"[Streaming response: {content_type}]",
2302
+ collect_streaming_response(response),
2253
2303
  True,
2254
2304
  None,
2255
2305
  test_origin,
@@ -2268,7 +2318,7 @@ def test_post_endpoint_single(
2268
2318
  expected_status,
2269
2319
  expected_response,
2270
2320
  response.status_code,
2271
- f"[Streaming response: {content_type}]",
2321
+ collect_streaming_response(response),
2272
2322
  False,
2273
2323
  error_msg,
2274
2324
  test_origin,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pytest-openapi
3
- Version: 0.2.3.dev202603041917
3
+ Version: 0.2.3.dev202603201619
4
4
  Summary: `pytest --openapi` - an opinionated, lightweight black-box contract tester against a live API using its OpenAPI specification as the source of truth
5
5
  Author-email: Sinan Ozel <coding@sinan.slmail.me>
6
6
  License: MIT License
@@ -1253,6 +1253,84 @@ def test_streaming_api_all_endpoints_tested():
1253
1253
  ), f"Expected all tests to pass with no failures, got: {output}"
1254
1254
 
1255
1255
 
1256
+ @pytest.mark.depends(on=["test_openapi_flag_is_recognized"])
1257
+ def test_streaming_vvv_shows_sse_content_not_placeholder():
1258
+ """Test that -vvv mode shows collected SSE content, not a placeholder."""
1259
+ print(
1260
+ "\n🔍 Testing -vvv shows SSE content instead of placeholder...",
1261
+ flush=True,
1262
+ )
1263
+ time.sleep(0.5)
1264
+
1265
+ result = subprocess.run(
1266
+ [
1267
+ "pytest",
1268
+ "--openapi=http://mock-server-streaming-api:8000",
1269
+ "-k",
1270
+ "stream/sse",
1271
+ "-vvv",
1272
+ ],
1273
+ capture_output=True,
1274
+ text=True,
1275
+ cwd="/app",
1276
+ )
1277
+
1278
+ output = result.stdout + result.stderr
1279
+
1280
+ assert (
1281
+ result.returncode == 0
1282
+ ), f"Expected SSE streaming tests to pass, got: {output}"
1283
+
1284
+ # Should NOT show the opaque placeholder string
1285
+ assert (
1286
+ "[Streaming response:" not in output
1287
+ ), f"Expected no placeholder, but got: {output}"
1288
+
1289
+ # Should show actual collected chunk content
1290
+ assert (
1291
+ "Chunk" in output
1292
+ ), f"Expected actual streaming content ('Chunk') in -vvv output, got: {output}"
1293
+
1294
+
1295
+ @pytest.mark.depends(on=["test_openapi_flag_is_recognized"])
1296
+ def test_streaming_vvv_shows_ndjson_content_not_placeholder():
1297
+ """Test that -vvv mode shows collected NDJSON content, not a placeholder."""
1298
+ print(
1299
+ "\n🔍 Testing -vvv shows NDJSON content instead of placeholder...",
1300
+ flush=True,
1301
+ )
1302
+ time.sleep(0.5)
1303
+
1304
+ result = subprocess.run(
1305
+ [
1306
+ "pytest",
1307
+ "--openapi=http://mock-server-streaming-api:8000",
1308
+ "-k",
1309
+ "stream/ndjson",
1310
+ "-vvv",
1311
+ ],
1312
+ capture_output=True,
1313
+ text=True,
1314
+ cwd="/app",
1315
+ )
1316
+
1317
+ output = result.stdout + result.stderr
1318
+
1319
+ assert (
1320
+ result.returncode == 0
1321
+ ), f"Expected NDJSON streaming tests to pass, got: {output}"
1322
+
1323
+ # Should NOT show the opaque placeholder string
1324
+ assert (
1325
+ "[Streaming response:" not in output
1326
+ ), f"Expected no placeholder, but got: {output}"
1327
+
1328
+ # Should show actual collected chunk content
1329
+ assert (
1330
+ "Chunk" in output
1331
+ ), f"Expected actual streaming content ('Chunk') in -vvv output, got: {output}"
1332
+
1333
+
1256
1334
  @pytest.mark.depends(on=["test_openapi_flag_is_recognized"])
1257
1335
  def test_post_no_request_body_passes():
1258
1336
  """Test that POST endpoints with no request body are tested and pass."""
@@ -1 +0,0 @@
1
- __version__ = "0.2.3.dev202603041917"