ntf-sample-plugin 0.1.8__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.
- ntf_sample_plugin-0.1.8/PKG-INFO +66 -0
- ntf_sample_plugin-0.1.8/README.md +58 -0
- ntf_sample_plugin-0.1.8/ntf_sample_plugin/__init__.py +3 -0
- ntf_sample_plugin-0.1.8/ntf_sample_plugin/assertions.py +43 -0
- ntf_sample_plugin-0.1.8/ntf_sample_plugin/functions.py +28 -0
- ntf_sample_plugin-0.1.8/ntf_sample_plugin/renderer.py +22 -0
- ntf_sample_plugin-0.1.8/ntf_sample_plugin/reporter.py +20 -0
- ntf_sample_plugin-0.1.8/ntf_sample_plugin/transport.py +14 -0
- ntf_sample_plugin-0.1.8/ntf_sample_plugin.egg-info/PKG-INFO +66 -0
- ntf_sample_plugin-0.1.8/ntf_sample_plugin.egg-info/SOURCES.txt +16 -0
- ntf_sample_plugin-0.1.8/ntf_sample_plugin.egg-info/dependency_links.txt +1 -0
- ntf_sample_plugin-0.1.8/ntf_sample_plugin.egg-info/entry_points.txt +14 -0
- ntf_sample_plugin-0.1.8/ntf_sample_plugin.egg-info/requires.txt +2 -0
- ntf_sample_plugin-0.1.8/ntf_sample_plugin.egg-info/top_level.txt +1 -0
- ntf_sample_plugin-0.1.8/pyproject.toml +3 -0
- ntf_sample_plugin-0.1.8/setup.cfg +34 -0
- ntf_sample_plugin-0.1.8/setup.py +4 -0
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: ntf_sample_plugin
|
|
3
|
+
Version: 0.1.8
|
|
4
|
+
Summary: Sample plugin pack for PytestOps (ntf)
|
|
5
|
+
Description-Content-Type: text/markdown
|
|
6
|
+
Requires-Dist: PytestOps-framework>=0.1.0
|
|
7
|
+
Requires-Dist: jsonpath>=0.82.2
|
|
8
|
+
|
|
9
|
+
# ntf-sample-plugin
|
|
10
|
+
|
|
11
|
+
Sample plugin pack for PytestOps (`ntf`). It demonstrates all plugin entry-points:
|
|
12
|
+
|
|
13
|
+
- `ntf.assertions` (custom assertion)
|
|
14
|
+
- `ntf.functions` (custom renderer functions)
|
|
15
|
+
- `ntf.reporters` (custom report output)
|
|
16
|
+
- `ntf.transports` (custom transport factory)
|
|
17
|
+
- `ntf.renderers` (custom renderer)
|
|
18
|
+
|
|
19
|
+
## Install (local)
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
cd plugins/ntf_sample_plugin
|
|
23
|
+
python -m pip install -e .
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Usage
|
|
27
|
+
|
|
28
|
+
### Custom assertion: `startswith`
|
|
29
|
+
|
|
30
|
+
```yaml
|
|
31
|
+
validate:
|
|
32
|
+
- startswith: {"body.message": "ok"}
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### Custom functions
|
|
36
|
+
|
|
37
|
+
```yaml
|
|
38
|
+
request:
|
|
39
|
+
json:
|
|
40
|
+
ts: "${now_iso()}"
|
|
41
|
+
rid: "${rand_int(1000,9999)}"
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### Custom reporter
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
ntf run-yaml --config configs/default.yaml --cases tests/data --reporter print
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Optionally write JSON report with:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
set NTF_SAMPLE_REPORT=report/sample-plugin.json
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### Custom transport
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
ntf run-yaml --config configs/default.yaml --cases tests/data --transport requests_no_session
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### Custom renderer
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
ntf run-yaml --config configs/default.yaml --cases tests/data --renderer upper
|
|
66
|
+
```
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# ntf-sample-plugin
|
|
2
|
+
|
|
3
|
+
Sample plugin pack for PytestOps (`ntf`). It demonstrates all plugin entry-points:
|
|
4
|
+
|
|
5
|
+
- `ntf.assertions` (custom assertion)
|
|
6
|
+
- `ntf.functions` (custom renderer functions)
|
|
7
|
+
- `ntf.reporters` (custom report output)
|
|
8
|
+
- `ntf.transports` (custom transport factory)
|
|
9
|
+
- `ntf.renderers` (custom renderer)
|
|
10
|
+
|
|
11
|
+
## Install (local)
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
cd plugins/ntf_sample_plugin
|
|
15
|
+
python -m pip install -e .
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Usage
|
|
19
|
+
|
|
20
|
+
### Custom assertion: `startswith`
|
|
21
|
+
|
|
22
|
+
```yaml
|
|
23
|
+
validate:
|
|
24
|
+
- startswith: {"body.message": "ok"}
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
### Custom functions
|
|
28
|
+
|
|
29
|
+
```yaml
|
|
30
|
+
request:
|
|
31
|
+
json:
|
|
32
|
+
ts: "${now_iso()}"
|
|
33
|
+
rid: "${rand_int(1000,9999)}"
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### Custom reporter
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
ntf run-yaml --config configs/default.yaml --cases tests/data --reporter print
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Optionally write JSON report with:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
set NTF_SAMPLE_REPORT=report/sample-plugin.json
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### Custom transport
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
ntf run-yaml --config configs/default.yaml --cases tests/data --transport requests_no_session
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### Custom renderer
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
ntf run-yaml --config configs/default.yaml --cases tests/data --renderer upper
|
|
58
|
+
```
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
import jsonpath
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def _resolve_actual(actual_json: Any, status_code: int, locator: str) -> tuple[bool, Any]:
|
|
9
|
+
if locator == "status_code":
|
|
10
|
+
return True, status_code
|
|
11
|
+
|
|
12
|
+
if locator.startswith("$"):
|
|
13
|
+
values = jsonpath.jsonpath(actual_json, locator)
|
|
14
|
+
if not values:
|
|
15
|
+
return False, None
|
|
16
|
+
return True, values[0]
|
|
17
|
+
|
|
18
|
+
if isinstance(actual_json, dict) and locator in actual_json:
|
|
19
|
+
return True, actual_json.get(locator)
|
|
20
|
+
|
|
21
|
+
values = jsonpath.jsonpath(actual_json, f"$..{locator}")
|
|
22
|
+
if not values:
|
|
23
|
+
return False, None
|
|
24
|
+
return True, values[0]
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def assert_startswith(payload: Any, actual_json: Any, status_code: int) -> None:
|
|
28
|
+
if not isinstance(payload, dict) or len(payload) != 1:
|
|
29
|
+
raise AssertionError("startswith payload must be a dict with one locator")
|
|
30
|
+
|
|
31
|
+
locator, expected_prefix = next(iter(payload.items()))
|
|
32
|
+
found, actual = _resolve_actual(actual_json, status_code, str(locator))
|
|
33
|
+
if not found:
|
|
34
|
+
raise AssertionError(f"startswith locator not found: {locator}")
|
|
35
|
+
|
|
36
|
+
if not str(actual).startswith(str(expected_prefix)):
|
|
37
|
+
raise AssertionError(
|
|
38
|
+
"startswith failed: locator={locator} expected_prefix={expected!r} actual={actual!r}".format(
|
|
39
|
+
locator=locator,
|
|
40
|
+
expected=expected_prefix,
|
|
41
|
+
actual=actual,
|
|
42
|
+
)
|
|
43
|
+
)
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import datetime
|
|
4
|
+
import random
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def now_iso() -> str:
|
|
8
|
+
return datetime.datetime.now().isoformat()
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def rand_int(a: str = "0", b: str = "100") -> int:
|
|
12
|
+
try:
|
|
13
|
+
lo = int(a)
|
|
14
|
+
except Exception:
|
|
15
|
+
lo = 0
|
|
16
|
+
try:
|
|
17
|
+
hi = int(b)
|
|
18
|
+
except Exception:
|
|
19
|
+
hi = 100
|
|
20
|
+
if lo > hi:
|
|
21
|
+
lo, hi = hi, lo
|
|
22
|
+
return random.randint(lo, hi)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
FUNCTIONS = {
|
|
26
|
+
"now_iso": now_iso,
|
|
27
|
+
"rand_int": rand_int,
|
|
28
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
from ntf.renderer import RenderContext, Renderer
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class UpperRenderer:
|
|
9
|
+
def __init__(self, ctx: RenderContext, functions: Any | None = None) -> None:
|
|
10
|
+
self._inner = Renderer(ctx, functions=functions)
|
|
11
|
+
|
|
12
|
+
def render(self, data: Any) -> Any:
|
|
13
|
+
return self._upper(self._inner.render(data))
|
|
14
|
+
|
|
15
|
+
def _upper(self, data: Any) -> Any:
|
|
16
|
+
if isinstance(data, str):
|
|
17
|
+
return data.upper()
|
|
18
|
+
if isinstance(data, list):
|
|
19
|
+
return [self._upper(i) for i in data]
|
|
20
|
+
if isinstance(data, dict):
|
|
21
|
+
return {k: self._upper(v) for k, v in data.items()}
|
|
22
|
+
return data
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
import os
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from typing import Any
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def print_report(summary: dict[str, Any], failures: list[dict[str, Any]]) -> None:
|
|
10
|
+
print("[ntf-sample-plugin] summary:", summary)
|
|
11
|
+
if failures:
|
|
12
|
+
print("[ntf-sample-plugin] failures:", len(failures))
|
|
13
|
+
|
|
14
|
+
out_path = os.getenv("NTF_SAMPLE_REPORT")
|
|
15
|
+
if not out_path:
|
|
16
|
+
return
|
|
17
|
+
p = Path(out_path)
|
|
18
|
+
p.parent.mkdir(parents=True, exist_ok=True)
|
|
19
|
+
payload = {"summary": summary, "failures": failures}
|
|
20
|
+
p.write_text(json.dumps(payload, ensure_ascii=False, indent=2), encoding="utf-8")
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
from ntf.http import RequestsTransport
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def requests_no_session(cfg: Any) -> RequestsTransport:
|
|
9
|
+
return RequestsTransport(
|
|
10
|
+
proxy=cfg.http_proxy,
|
|
11
|
+
verify=cfg.http_verify,
|
|
12
|
+
cert=cfg.http_cert,
|
|
13
|
+
session_persist=False,
|
|
14
|
+
)
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: ntf-sample-plugin
|
|
3
|
+
Version: 0.1.8
|
|
4
|
+
Summary: Sample plugin pack for PytestOps (ntf)
|
|
5
|
+
Description-Content-Type: text/markdown
|
|
6
|
+
Requires-Dist: PytestOps-framework>=0.1.0
|
|
7
|
+
Requires-Dist: jsonpath>=0.82.2
|
|
8
|
+
|
|
9
|
+
# ntf-sample-plugin
|
|
10
|
+
|
|
11
|
+
Sample plugin pack for PytestOps (`ntf`). It demonstrates all plugin entry-points:
|
|
12
|
+
|
|
13
|
+
- `ntf.assertions` (custom assertion)
|
|
14
|
+
- `ntf.functions` (custom renderer functions)
|
|
15
|
+
- `ntf.reporters` (custom report output)
|
|
16
|
+
- `ntf.transports` (custom transport factory)
|
|
17
|
+
- `ntf.renderers` (custom renderer)
|
|
18
|
+
|
|
19
|
+
## Install (local)
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
cd plugins/ntf_sample_plugin
|
|
23
|
+
python -m pip install -e .
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Usage
|
|
27
|
+
|
|
28
|
+
### Custom assertion: `startswith`
|
|
29
|
+
|
|
30
|
+
```yaml
|
|
31
|
+
validate:
|
|
32
|
+
- startswith: {"body.message": "ok"}
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### Custom functions
|
|
36
|
+
|
|
37
|
+
```yaml
|
|
38
|
+
request:
|
|
39
|
+
json:
|
|
40
|
+
ts: "${now_iso()}"
|
|
41
|
+
rid: "${rand_int(1000,9999)}"
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### Custom reporter
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
ntf run-yaml --config configs/default.yaml --cases tests/data --reporter print
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Optionally write JSON report with:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
set NTF_SAMPLE_REPORT=report/sample-plugin.json
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### Custom transport
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
ntf run-yaml --config configs/default.yaml --cases tests/data --transport requests_no_session
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### Custom renderer
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
ntf run-yaml --config configs/default.yaml --cases tests/data --renderer upper
|
|
66
|
+
```
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
README.md
|
|
2
|
+
pyproject.toml
|
|
3
|
+
setup.cfg
|
|
4
|
+
setup.py
|
|
5
|
+
ntf_sample_plugin/__init__.py
|
|
6
|
+
ntf_sample_plugin/assertions.py
|
|
7
|
+
ntf_sample_plugin/functions.py
|
|
8
|
+
ntf_sample_plugin/renderer.py
|
|
9
|
+
ntf_sample_plugin/reporter.py
|
|
10
|
+
ntf_sample_plugin/transport.py
|
|
11
|
+
ntf_sample_plugin.egg-info/PKG-INFO
|
|
12
|
+
ntf_sample_plugin.egg-info/SOURCES.txt
|
|
13
|
+
ntf_sample_plugin.egg-info/dependency_links.txt
|
|
14
|
+
ntf_sample_plugin.egg-info/entry_points.txt
|
|
15
|
+
ntf_sample_plugin.egg-info/requires.txt
|
|
16
|
+
ntf_sample_plugin.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
[ntf.assertions]
|
|
2
|
+
startswith = ntf_sample_plugin.assertions:assert_startswith
|
|
3
|
+
|
|
4
|
+
[ntf.functions]
|
|
5
|
+
functions = ntf_sample_plugin.functions:FUNCTIONS
|
|
6
|
+
|
|
7
|
+
[ntf.renderers]
|
|
8
|
+
upper = ntf_sample_plugin.renderer:UpperRenderer
|
|
9
|
+
|
|
10
|
+
[ntf.reporters]
|
|
11
|
+
print = ntf_sample_plugin.reporter:print_report
|
|
12
|
+
|
|
13
|
+
[ntf.transports]
|
|
14
|
+
requests_no_session = ntf_sample_plugin.transport:requests_no_session
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
ntf_sample_plugin
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
[metadata]
|
|
2
|
+
name = ntf_sample_plugin
|
|
3
|
+
version = 0.1.8
|
|
4
|
+
description = Sample plugin pack for PytestOps (ntf)
|
|
5
|
+
long_description = file: README.md
|
|
6
|
+
long_description_content_type = text/markdown
|
|
7
|
+
requires_python = >=3.12
|
|
8
|
+
|
|
9
|
+
[options]
|
|
10
|
+
packages = find:
|
|
11
|
+
install_requires =
|
|
12
|
+
PytestOps-framework>=0.1.0
|
|
13
|
+
jsonpath>=0.82.2
|
|
14
|
+
|
|
15
|
+
[options.entry_points]
|
|
16
|
+
ntf.assertions =
|
|
17
|
+
startswith = ntf_sample_plugin.assertions:assert_startswith
|
|
18
|
+
ntf.functions =
|
|
19
|
+
functions = ntf_sample_plugin.functions:FUNCTIONS
|
|
20
|
+
ntf.reporters =
|
|
21
|
+
print = ntf_sample_plugin.reporter:print_report
|
|
22
|
+
ntf.transports =
|
|
23
|
+
requests_no_session = ntf_sample_plugin.transport:requests_no_session
|
|
24
|
+
ntf.renderers =
|
|
25
|
+
upper = ntf_sample_plugin.renderer:UpperRenderer
|
|
26
|
+
|
|
27
|
+
[options.packages.find]
|
|
28
|
+
include =
|
|
29
|
+
ntf_sample_plugin*
|
|
30
|
+
|
|
31
|
+
[egg_info]
|
|
32
|
+
tag_build =
|
|
33
|
+
tag_date = 0
|
|
34
|
+
|