piphi-runtime-testkit-python 0.1.1__py3-none-any.whl → 0.1.2__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.
@@ -1,16 +1,23 @@
1
1
  """Pytest-first helpers for testing PiPhi runtime integrations."""
2
2
 
3
3
  from .assertions import assert_entities_response, assert_event_sent, assert_telemetry_sent
4
- from .builders import build_config_payload, build_config_snapshot, build_runtime_headers
5
- from .mock_core import CapturedRequest, MockCoreServer
4
+ from .builders import (
5
+ build_config_payload,
6
+ build_config_snapshot,
7
+ build_core_config_row,
8
+ build_runtime_headers,
9
+ )
10
+ from .mock_core import CapturedRequest, MockCoreServer, RUNTIME_CONFIG_FETCH_PATH
6
11
 
7
12
  __all__ = [
8
13
  "CapturedRequest",
9
14
  "MockCoreServer",
15
+ "RUNTIME_CONFIG_FETCH_PATH",
10
16
  "assert_entities_response",
11
17
  "assert_event_sent",
12
18
  "assert_telemetry_sent",
13
19
  "build_config_payload",
14
20
  "build_config_snapshot",
21
+ "build_core_config_row",
15
22
  "build_runtime_headers",
16
23
  ]
@@ -50,16 +50,55 @@ def build_config_snapshot(
50
50
  container_id: str = "test-container",
51
51
  integration_id: str = "test-integration",
52
52
  generation: int = 1,
53
+ deleted_config_ids: list[str] | None = None,
54
+ config_hash: str | None = None,
55
+ schema_version: int = 1,
56
+ updated_at: str | None = None,
53
57
  extra: dict[str, Any] | None = None,
54
58
  ) -> dict[str, Any]:
55
59
  """Build a snapshot payload for `/config/sync` style tests."""
56
60
 
57
61
  payload: dict[str, Any] = {
62
+ "schema_version": schema_version,
58
63
  "container_id": container_id,
59
64
  "integration_id": integration_id,
60
65
  "generation": generation,
61
66
  "configs": configs or [],
67
+ "deleted_config_ids": deleted_config_ids or [],
62
68
  }
69
+ if config_hash is not None:
70
+ payload["config_hash"] = config_hash
71
+ if updated_at is not None:
72
+ payload["updated_at"] = updated_at
63
73
  if extra:
64
74
  payload.update(extra)
65
75
  return payload
76
+
77
+
78
+ def build_core_config_row(
79
+ *,
80
+ config_data: dict[str, Any] | None = None,
81
+ config_id: str = "config-1",
82
+ container_id: str = "test-container",
83
+ integration_id: str = "test-integration",
84
+ generation: int = 1,
85
+ extra: dict[str, Any] | None = None,
86
+ ) -> dict[str, Any]:
87
+ """Build a Core database-shaped config row for startup rehydrate tests."""
88
+
89
+ payload = build_config_payload(
90
+ config_id=config_id,
91
+ container_id=container_id,
92
+ integration_id=integration_id,
93
+ extra=config_data,
94
+ )
95
+ row: dict[str, Any] = {
96
+ "id": config_id,
97
+ "container_id": container_id,
98
+ "integration_id": integration_id,
99
+ "generation": generation,
100
+ "config_data": payload,
101
+ }
102
+ if extra:
103
+ row.update(extra)
104
+ return row
@@ -9,6 +9,7 @@ from typing import Any
9
9
 
10
10
  TELEMETRY_PATH = "/api/v2/integrations/telemetry"
11
11
  EVENT_PATH = "/api/v2/events/ingest"
12
+ RUNTIME_CONFIG_FETCH_PATH = "/api/v2/integrations/config/fetch/all/by/container/internal"
12
13
 
13
14
 
14
15
  @dataclass(slots=True)
@@ -24,23 +25,48 @@ class _RequestStore:
24
25
  def __init__(self) -> None:
25
26
  self.telemetry_requests: list[CapturedRequest] = []
26
27
  self.event_requests: list[CapturedRequest] = []
28
+ self.runtime_config_requests: list[CapturedRequest] = []
27
29
  self.telemetry_status = 200
28
30
  self.event_status = 200
31
+ self.runtime_config_status = 200
29
32
  self.telemetry_json: Any = {"ok": True}
30
33
  self.event_json: Any = {"ok": True}
34
+ self.runtime_config_json: Any = []
31
35
 
32
36
  def reset(self) -> None:
33
37
  self.telemetry_requests.clear()
34
38
  self.event_requests.clear()
39
+ self.runtime_config_requests.clear()
35
40
  self.telemetry_status = 200
36
41
  self.event_status = 200
42
+ self.runtime_config_status = 200
37
43
  self.telemetry_json = {"ok": True}
38
44
  self.event_json = {"ok": True}
45
+ self.runtime_config_json = []
39
46
 
40
47
 
41
48
  class _MockCoreRequestHandler(BaseHTTPRequestHandler):
42
49
  store: _RequestStore
43
50
 
51
+ def do_GET(self) -> None: # noqa: N802
52
+ request = CapturedRequest(
53
+ method="GET",
54
+ path=self.path,
55
+ headers={key: value for key, value in self.headers.items()},
56
+ body=b"",
57
+ json_body=None,
58
+ )
59
+
60
+ if self.path.split("?", 1)[0] == RUNTIME_CONFIG_FETCH_PATH:
61
+ self.store.runtime_config_requests.append(request)
62
+ self._send_json(
63
+ self.store.runtime_config_status,
64
+ self.store.runtime_config_json,
65
+ )
66
+ return
67
+
68
+ self._send_json(404, {"ok": False, "detail": "unknown path"})
69
+
44
70
  def do_POST(self) -> None: # noqa: N802
45
71
  content_length = int(self.headers.get("Content-Length", "0"))
46
72
  body = self.rfile.read(content_length)
@@ -119,6 +145,10 @@ class MockCoreServer:
119
145
  def event_requests(self) -> list[CapturedRequest]:
120
146
  return self._store.event_requests
121
147
 
148
+ @property
149
+ def runtime_config_requests(self) -> list[CapturedRequest]:
150
+ return self._store.runtime_config_requests
151
+
122
152
  def set_telemetry_response(self, *, status_code: int = 200, json_body: Any = None) -> None:
123
153
  self._store.telemetry_status = status_code
124
154
  self._store.telemetry_json = {"ok": status_code < 400} if json_body is None else json_body
@@ -127,6 +157,13 @@ class MockCoreServer:
127
157
  self._store.event_status = status_code
128
158
  self._store.event_json = {"ok": status_code < 400} if json_body is None else json_body
129
159
 
160
+ def set_runtime_config_response(self, *, status_code: int = 200, json_body: Any = None) -> None:
161
+ self._store.runtime_config_status = status_code
162
+ self._store.runtime_config_json = [] if json_body is None else json_body
163
+
164
+ def set_runtime_config_rows(self, rows: list[dict[str, Any]]) -> None:
165
+ self.set_runtime_config_response(status_code=200, json_body=rows)
166
+
130
167
  def reset(self) -> None:
131
168
  self._store.reset()
132
169
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: piphi-runtime-testkit-python
3
- Version: 0.1.1
3
+ Version: 0.1.2
4
4
  Summary: Pytest-first helpers for testing PiPhi runtime integrations
5
5
  Keywords: piphi,pytest,testing,runtime,iot
6
6
  Author-Email: KelvinSan <support@piphi.network>
@@ -0,0 +1,10 @@
1
+ piphi_runtime_testkit_python-0.1.2.dist-info/METADATA,sha256=vtARpxGqDCRUiKNBaNTk6t43wKMNFOU4_E4KzSV45UA,25426
2
+ piphi_runtime_testkit_python-0.1.2.dist-info/WHEEL,sha256=Z36eTX6lG3PITRleSd5hAZHCcz52yg3c0JQVxKBbLW0,90
3
+ piphi_runtime_testkit_python-0.1.2.dist-info/entry_points.txt,sha256=zTIXoQOJK3VVIMOfKpB5Y3vnSbyFgyU45GZCb7fLGHI,120
4
+ piphi_runtime_testkit_python-0.1.2.dist-info/licenses/LICENSE,sha256=pS6szQI4X7qAin1ODdoDp-XwZvsFy6ZZ28-JAwGHgzo,1070
5
+ piphi_runtime_testkit_python/__init__.py,sha256=Fy3rD1zp3NH_g4__52H7CWUeY0ErwTI8ChDRvlj361Y,668
6
+ piphi_runtime_testkit_python/assertions.py,sha256=g-lNyYwbpKYB3VduR9K8aFwKzMIFor0K2svBn_TfzxU,6882
7
+ piphi_runtime_testkit_python/builders.py,sha256=UmxPB1fSDGqhQzcpmmzBH4w3ZSGxtWHXQ4bfZL18kd0,2961
8
+ piphi_runtime_testkit_python/mock_core.py,sha256=vpAF0xDvoPHLoKbKuoxm3n1l92Yz28QxBlJNGe91oWk,6692
9
+ piphi_runtime_testkit_python/pytest_plugin.py,sha256=8LUxO-2o7PZOQeMLQ2THbtfwn2HJ91vXkwGiYipmNuw,965
10
+ piphi_runtime_testkit_python-0.1.2.dist-info/RECORD,,
@@ -1,10 +0,0 @@
1
- piphi_runtime_testkit_python-0.1.1.dist-info/METADATA,sha256=RXYsA-sGse_dMF_B6B3T3bZ_T1cKlA-7U1fy7VRk0XU,25426
2
- piphi_runtime_testkit_python-0.1.1.dist-info/WHEEL,sha256=Z36eTX6lG3PITRleSd5hAZHCcz52yg3c0JQVxKBbLW0,90
3
- piphi_runtime_testkit_python-0.1.1.dist-info/entry_points.txt,sha256=zTIXoQOJK3VVIMOfKpB5Y3vnSbyFgyU45GZCb7fLGHI,120
4
- piphi_runtime_testkit_python-0.1.1.dist-info/licenses/LICENSE,sha256=pS6szQI4X7qAin1ODdoDp-XwZvsFy6ZZ28-JAwGHgzo,1070
5
- piphi_runtime_testkit_python/__init__.py,sha256=j8QfREn-Uqx_XkWVqeEOLvyoBr9Xye5PO_0ZmbvZe-U,535
6
- piphi_runtime_testkit_python/assertions.py,sha256=g-lNyYwbpKYB3VduR9K8aFwKzMIFor0K2svBn_TfzxU,6882
7
- piphi_runtime_testkit_python/builders.py,sha256=fRB1W4-OwzyNhqiIbAbU9Sg2n5SKNcoKquHbN46zQdM,1760
8
- piphi_runtime_testkit_python/mock_core.py,sha256=Sqwl_sJ63scYkW3CIsSpAowjynFAyeAcjWwdQ3xtgfc,5180
9
- piphi_runtime_testkit_python/pytest_plugin.py,sha256=8LUxO-2o7PZOQeMLQ2THbtfwn2HJ91vXkwGiYipmNuw,965
10
- piphi_runtime_testkit_python-0.1.1.dist-info/RECORD,,