sefrone-api-e2e 1.2.2__tar.gz → 1.2.4__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.
- {sefrone_api_e2e-1.2.2 → sefrone_api_e2e-1.2.4}/PKG-INFO +1 -1
- {sefrone_api_e2e-1.2.2 → sefrone_api_e2e-1.2.4}/sefrone_api_e2e/runner_rest_api.py +66 -5
- {sefrone_api_e2e-1.2.2 → sefrone_api_e2e-1.2.4}/sefrone_api_e2e.egg-info/PKG-INFO +1 -1
- {sefrone_api_e2e-1.2.2 → sefrone_api_e2e-1.2.4}/setup.py +1 -1
- {sefrone_api_e2e-1.2.2 → sefrone_api_e2e-1.2.4}/README.md +0 -0
- {sefrone_api_e2e-1.2.2 → sefrone_api_e2e-1.2.4}/sefrone_api_e2e/__init__.py +0 -0
- {sefrone_api_e2e-1.2.2 → sefrone_api_e2e-1.2.4}/sefrone_api_e2e/api_e2e_manager.py +0 -0
- {sefrone_api_e2e-1.2.2 → sefrone_api_e2e-1.2.4}/sefrone_api_e2e/e2e/Scenarios/Auth/0_check_features.yaml +0 -0
- {sefrone_api_e2e-1.2.2 → sefrone_api_e2e-1.2.4}/sefrone_api_e2e/e2e/Scenarios/Auth/1_normal_auth_flow.yaml +0 -0
- {sefrone_api_e2e-1.2.2 → sefrone_api_e2e-1.2.4}/sefrone_api_e2e/e2e/Scenarios/Auth/2_account_endpoints.yaml +0 -0
- {sefrone_api_e2e-1.2.2 → sefrone_api_e2e-1.2.4}/sefrone_api_e2e/e2e/Scenarios/Auth/3_admin_account_endpoints.yaml +0 -0
- {sefrone_api_e2e-1.2.2 → sefrone_api_e2e-1.2.4}/sefrone_api_e2e/e2e/Scenarios/Auth/4_workspace_endpoints.yaml +0 -0
- {sefrone_api_e2e-1.2.2 → sefrone_api_e2e-1.2.4}/sefrone_api_e2e/e2e/Scenarios/Auth/5_apikey_endpoints.yaml +0 -0
- {sefrone_api_e2e-1.2.2 → sefrone_api_e2e-1.2.4}/sefrone_api_e2e/e2e/Scenarios/Auth/6_project_endpoints.yaml +0 -0
- {sefrone_api_e2e-1.2.2 → sefrone_api_e2e-1.2.4}/sefrone_api_e2e/e2e/Scenarios/Auth/7_email_2fa_flow.yaml +0 -0
- {sefrone_api_e2e-1.2.2 → sefrone_api_e2e-1.2.4}/sefrone_api_e2e/e2e_scenarios_manager.py +0 -0
- {sefrone_api_e2e-1.2.2 → sefrone_api_e2e-1.2.4}/sefrone_api_e2e/env_patch.py +0 -0
- {sefrone_api_e2e-1.2.2 → sefrone_api_e2e-1.2.4}/sefrone_api_e2e/json_mock_server.py +0 -0
- {sefrone_api_e2e-1.2.2 → sefrone_api_e2e-1.2.4}/sefrone_api_e2e/runner_assets.py +0 -0
- {sefrone_api_e2e-1.2.2 → sefrone_api_e2e-1.2.4}/sefrone_api_e2e/runner_email_mock.py +0 -0
- {sefrone_api_e2e-1.2.2 → sefrone_api_e2e-1.2.4}/sefrone_api_e2e/runner_satim_mock.py +0 -0
- {sefrone_api_e2e-1.2.2 → sefrone_api_e2e-1.2.4}/sefrone_api_e2e/runner_webhook_mock.py +0 -0
- {sefrone_api_e2e-1.2.2 → sefrone_api_e2e-1.2.4}/sefrone_api_e2e/step_runner.py +0 -0
- {sefrone_api_e2e-1.2.2 → sefrone_api_e2e-1.2.4}/sefrone_api_e2e.egg-info/SOURCES.txt +0 -0
- {sefrone_api_e2e-1.2.2 → sefrone_api_e2e-1.2.4}/sefrone_api_e2e.egg-info/dependency_links.txt +0 -0
- {sefrone_api_e2e-1.2.2 → sefrone_api_e2e-1.2.4}/sefrone_api_e2e.egg-info/requires.txt +0 -0
- {sefrone_api_e2e-1.2.2 → sefrone_api_e2e-1.2.4}/sefrone_api_e2e.egg-info/top_level.txt +0 -0
- {sefrone_api_e2e-1.2.2 → sefrone_api_e2e-1.2.4}/setup.cfg +0 -0
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import hashlib
|
|
2
2
|
import os
|
|
3
|
+
import random
|
|
3
4
|
import secrets
|
|
4
5
|
import time
|
|
5
6
|
from typing import Any
|
|
@@ -66,20 +67,63 @@ class RestApiRunner(StepRunner):
|
|
|
66
67
|
def _handle_randomize(self, step: dict, ctx: RunContext) -> StepResult:
|
|
67
68
|
spec = step["randomize"]
|
|
68
69
|
if isinstance(spec, dict):
|
|
69
|
-
for key,
|
|
70
|
-
|
|
71
|
-
length = 8
|
|
72
|
-
ctx.store_value(key, self._random_string(length))
|
|
70
|
+
for key, value in spec.items():
|
|
71
|
+
ctx.store_value(key, self._generate_random_value(value))
|
|
73
72
|
elif isinstance(spec, list):
|
|
74
73
|
for key in spec:
|
|
75
74
|
ctx.store_value(key, self._random_string(8))
|
|
76
75
|
return StepResult.passed()
|
|
77
76
|
|
|
77
|
+
def _generate_random_value(self, spec) -> str:
|
|
78
|
+
"""
|
|
79
|
+
Generate a random value from a spec:
|
|
80
|
+
|
|
81
|
+
- ``int`` (e.g. ``8``) → random hex string of that length (backward-compat)
|
|
82
|
+
- ``{type: string, length: N}`` → random hex string of length N
|
|
83
|
+
- ``{type: string, length: N, chars: digits}`` → digits-only string of length N
|
|
84
|
+
- ``{type: string, length: N, chars: hex}`` → hex string of length N (default)
|
|
85
|
+
- ``{type: number, min: N, max: M}`` → random integer in [min, max] (inclusive)
|
|
86
|
+
- ``{type: float, min: N, max: M}`` → random float in [min, max]
|
|
87
|
+
"""
|
|
88
|
+
if isinstance(spec, int):
|
|
89
|
+
length = spec if spec > 0 else 8
|
|
90
|
+
return self._random_string(length)
|
|
91
|
+
|
|
92
|
+
if isinstance(spec, dict):
|
|
93
|
+
kind = str(spec.get("type", "string")).lower()
|
|
94
|
+
|
|
95
|
+
if kind == "string":
|
|
96
|
+
length = int(spec.get("length", 8))
|
|
97
|
+
if length <= 0:
|
|
98
|
+
length = 8
|
|
99
|
+
chars = str(spec.get("chars", "hex")).lower()
|
|
100
|
+
if chars == "digits":
|
|
101
|
+
return self._random_digits(length)
|
|
102
|
+
return self._random_string(length)
|
|
103
|
+
|
|
104
|
+
if kind == "number":
|
|
105
|
+
min_val = int(spec.get("min", 0))
|
|
106
|
+
max_val = int(spec.get("max", 9999))
|
|
107
|
+
return str(random.randint(min_val, max_val))
|
|
108
|
+
|
|
109
|
+
if kind == "float":
|
|
110
|
+
min_val = float(spec.get("min", 0.0))
|
|
111
|
+
max_val = float(spec.get("max", 1.0))
|
|
112
|
+
precision = int(spec.get("precision", 2))
|
|
113
|
+
return str(round(random.uniform(min_val, max_val), precision))
|
|
114
|
+
|
|
115
|
+
# fallback
|
|
116
|
+
return self._random_string(8)
|
|
117
|
+
|
|
78
118
|
@staticmethod
|
|
79
119
|
def _random_string(length: int = 8) -> str:
|
|
80
120
|
n_bytes = (length + 1) // 2
|
|
81
121
|
return secrets.token_hex(n_bytes)[:length]
|
|
82
122
|
|
|
123
|
+
@staticmethod
|
|
124
|
+
def _random_digits(length: int = 8) -> str:
|
|
125
|
+
return "".join(str(random.randint(0, 9)) for _ in range(length))
|
|
126
|
+
|
|
83
127
|
# ------------------------------------------------------------------ #
|
|
84
128
|
# HTTP
|
|
85
129
|
# ------------------------------------------------------------------ #
|
|
@@ -178,7 +222,7 @@ class RestApiRunner(StepRunner):
|
|
|
178
222
|
resp = ctx.session.request(**request_kwargs)
|
|
179
223
|
print(f" -> {method} {url} -> {resp.status_code}")
|
|
180
224
|
|
|
181
|
-
if ctx.is_verbose:
|
|
225
|
+
if ctx.is_verbose and "application/json" in resp.headers.get("Content-Type", ""):
|
|
182
226
|
print(f"Response text: {resp.text}")
|
|
183
227
|
|
|
184
228
|
# --- Status assertion ---
|
|
@@ -220,6 +264,23 @@ class RestApiRunner(StepRunner):
|
|
|
220
264
|
except Exception:
|
|
221
265
|
raise AssertionError(f"Response is not valid JSON: {resp.text}")
|
|
222
266
|
|
|
267
|
+
# --- Content-Type assertion ---
|
|
268
|
+
expected_content_type = expect.get("content_type")
|
|
269
|
+
if expected_content_type:
|
|
270
|
+
actual_ct = resp.headers.get("Content-Type", "")
|
|
271
|
+
if expected_content_type not in actual_ct:
|
|
272
|
+
raise AssertionError(
|
|
273
|
+
f"Expected Content-Type to include '{expected_content_type}', got '{actual_ct}'"
|
|
274
|
+
)
|
|
275
|
+
|
|
276
|
+
# --- Save file to disk ---
|
|
277
|
+
if "save_file" in step:
|
|
278
|
+
file_path = ctx.substitute_stored(str(step["save_file"]))
|
|
279
|
+
os.makedirs(os.path.dirname(file_path) if os.path.dirname(file_path) else ".", exist_ok=True)
|
|
280
|
+
with open(file_path, "wb") as f:
|
|
281
|
+
f.write(resp.content)
|
|
282
|
+
print(f" Saved response file -> {file_path}")
|
|
283
|
+
|
|
223
284
|
# --- File SHA256 check ---
|
|
224
285
|
if "file_sha256_matches" in expect:
|
|
225
286
|
local_path = ctx.substitute_stored(expect["file_sha256_matches"])
|
|
@@ -5,7 +5,7 @@ with open("README.md", "r", encoding="utf-8") as fh:
|
|
|
5
5
|
|
|
6
6
|
setup(
|
|
7
7
|
name="sefrone_api_e2e",
|
|
8
|
-
version="1.2.
|
|
8
|
+
version="1.2.4",
|
|
9
9
|
author="Sefrone",
|
|
10
10
|
author_email="contact@sefrone.com",
|
|
11
11
|
description="A Python package to provide e2e testing helpers for sefrone API projects",
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sefrone_api_e2e-1.2.2 → sefrone_api_e2e-1.2.4}/sefrone_api_e2e.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|