relayed 0.2.0__tar.gz → 0.2.1__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.
- {relayed-0.2.0 → relayed-0.2.1}/PKG-INFO +1 -1
- relayed-0.2.1/tests/test_sdk.py +156 -0
- relayed-0.2.0/tests/test_sdk.py +0 -23
- {relayed-0.2.0 → relayed-0.2.1}/.gitignore +0 -0
- {relayed-0.2.0 → relayed-0.2.1}/LICENSE +0 -0
- {relayed-0.2.0 → relayed-0.2.1}/README.md +0 -0
- {relayed-0.2.0 → relayed-0.2.1}/pyproject.toml +0 -0
- {relayed-0.2.0 → relayed-0.2.1}/src/relayed/__init__.py +0 -0
- {relayed-0.2.0 → relayed-0.2.1}/src/relayed/_client.py +0 -0
- {relayed-0.2.0 → relayed-0.2.1}/src/relayed/_errors.py +0 -0
- {relayed-0.2.0 → relayed-0.2.1}/src/relayed/_webhooks.py +0 -0
- {relayed-0.2.0 → relayed-0.2.1}/tests/test_webhooks.py +0 -0
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import json
|
|
2
|
+
|
|
3
|
+
import httpx
|
|
4
|
+
import pytest
|
|
5
|
+
|
|
6
|
+
from relayed import (
|
|
7
|
+
RelayedClient,
|
|
8
|
+
RelayedAuthError,
|
|
9
|
+
RelayedNotFoundError,
|
|
10
|
+
RelayedConflictError,
|
|
11
|
+
RelayedClientError,
|
|
12
|
+
RelayedServerError,
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
API_KEY = "test-api-key"
|
|
16
|
+
BASE_URL = "http://relayed.test"
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def make_client(handler) -> RelayedClient:
|
|
20
|
+
"""Build a real RelayedClient but route its requests through a mock transport.
|
|
21
|
+
|
|
22
|
+
Only the transport is swapped, so the client's own base_url and auth headers
|
|
23
|
+
are still exercised (and can be asserted on).
|
|
24
|
+
"""
|
|
25
|
+
client = RelayedClient(API_KEY, base_url=BASE_URL)
|
|
26
|
+
client._client._transport = httpx.MockTransport(handler)
|
|
27
|
+
return client
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def test_send_event_sends_correct_request():
|
|
31
|
+
"""send_event POSTs the event body with the idempotency key and returns the parsed response."""
|
|
32
|
+
captured = {}
|
|
33
|
+
|
|
34
|
+
def handler(request: httpx.Request) -> httpx.Response:
|
|
35
|
+
captured["request"] = request
|
|
36
|
+
return httpx.Response(202, json={"event_id": "evt_1", "delivery_ids": ["d1", "d2"]})
|
|
37
|
+
|
|
38
|
+
client = make_client(handler)
|
|
39
|
+
result = client.send_event("test.event", {"message": "hi"}, idempotency_key="idem-1")
|
|
40
|
+
|
|
41
|
+
req = captured["request"]
|
|
42
|
+
assert req.method == "POST"
|
|
43
|
+
assert req.url.path == "/v1/events"
|
|
44
|
+
assert req.headers["Authorization"] == f"Bearer {API_KEY}"
|
|
45
|
+
assert req.headers["idempotency-key"] == "idem-1"
|
|
46
|
+
assert json.loads(req.content) == {"event_type": "test.event", "payload": {"message": "hi"}}
|
|
47
|
+
assert result == {"event_id": "evt_1", "delivery_ids": ["d1", "d2"]}
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def test_create_subscription_sends_correct_request():
|
|
51
|
+
"""create_subscription POSTs destination_url/event_types/description and returns the created subscription."""
|
|
52
|
+
captured = {}
|
|
53
|
+
|
|
54
|
+
def handler(request: httpx.Request) -> httpx.Response:
|
|
55
|
+
captured["request"] = request
|
|
56
|
+
return httpx.Response(201, json={"id": "sub_1", "webhook_secret": "whsec_1"})
|
|
57
|
+
|
|
58
|
+
client = make_client(handler)
|
|
59
|
+
result = client.create_subscription(
|
|
60
|
+
destination_url="https://example.com/hook",
|
|
61
|
+
event_types=["test.event"],
|
|
62
|
+
description="my hook",
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
req = captured["request"]
|
|
66
|
+
assert req.method == "POST"
|
|
67
|
+
assert req.url.path == "/v1/subscriptions"
|
|
68
|
+
assert json.loads(req.content) == {
|
|
69
|
+
"destination_url": "https://example.com/hook",
|
|
70
|
+
"event_types": ["test.event"],
|
|
71
|
+
"description": "my hook",
|
|
72
|
+
}
|
|
73
|
+
assert result == {"id": "sub_1", "webhook_secret": "whsec_1"}
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def test_list_subscriptions_returns_list():
|
|
77
|
+
def handler(request: httpx.Request) -> httpx.Response:
|
|
78
|
+
assert request.method == "GET"
|
|
79
|
+
assert request.url.path == "/v1/subscriptions"
|
|
80
|
+
return httpx.Response(200, json=[{"id": "sub_1"}, {"id": "sub_2"}])
|
|
81
|
+
|
|
82
|
+
client = make_client(handler)
|
|
83
|
+
assert client.list_subscriptions() == [{"id": "sub_1"}, {"id": "sub_2"}]
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def test_get_subscription_uses_path_id():
|
|
87
|
+
def handler(request: httpx.Request) -> httpx.Response:
|
|
88
|
+
assert request.method == "GET"
|
|
89
|
+
assert request.url.path == "/v1/subscriptions/sub_1"
|
|
90
|
+
return httpx.Response(200, json={"id": "sub_1"})
|
|
91
|
+
|
|
92
|
+
client = make_client(handler)
|
|
93
|
+
assert client.get_subscription("sub_1") == {"id": "sub_1"}
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def test_delete_subscription_returns_none_on_204():
|
|
97
|
+
def handler(request: httpx.Request) -> httpx.Response:
|
|
98
|
+
assert request.method == "DELETE"
|
|
99
|
+
assert request.url.path == "/v1/subscriptions/sub_1"
|
|
100
|
+
return httpx.Response(204)
|
|
101
|
+
|
|
102
|
+
client = make_client(handler)
|
|
103
|
+
assert client.delete_subscription("sub_1") is None
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def test_list_dead_letters_returns_list():
|
|
107
|
+
def handler(request: httpx.Request) -> httpx.Response:
|
|
108
|
+
assert request.url.path == "/v1/deadletter"
|
|
109
|
+
return httpx.Response(200, json=[{"id": "dl_1"}])
|
|
110
|
+
|
|
111
|
+
client = make_client(handler)
|
|
112
|
+
assert client.list_dead_letters() == [{"id": "dl_1"}]
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def test_replay_dead_letter_returns_first_delivery_id():
|
|
116
|
+
def handler(request: httpx.Request) -> httpx.Response:
|
|
117
|
+
assert request.method == "POST"
|
|
118
|
+
assert request.url.path == "/v1/deadletter/dl_1/replay"
|
|
119
|
+
return httpx.Response(200, json={"delivery_ids": ["d_new"]})
|
|
120
|
+
|
|
121
|
+
client = make_client(handler)
|
|
122
|
+
assert client.replay_dead_letter("dl_1") == "d_new"
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
@pytest.mark.parametrize(
|
|
126
|
+
"status, exc",
|
|
127
|
+
[
|
|
128
|
+
(401, RelayedAuthError),
|
|
129
|
+
(403, RelayedAuthError),
|
|
130
|
+
(404, RelayedNotFoundError),
|
|
131
|
+
(409, RelayedConflictError),
|
|
132
|
+
(400, RelayedClientError),
|
|
133
|
+
(422, RelayedClientError),
|
|
134
|
+
(500, RelayedServerError),
|
|
135
|
+
(503, RelayedServerError),
|
|
136
|
+
],
|
|
137
|
+
)
|
|
138
|
+
def test_error_status_maps_to_exception(status, exc):
|
|
139
|
+
"""Non-2xx responses raise the mapped exception, preserving status_code and body."""
|
|
140
|
+
def handler(request: httpx.Request) -> httpx.Response:
|
|
141
|
+
return httpx.Response(status, text="boom")
|
|
142
|
+
|
|
143
|
+
client = make_client(handler)
|
|
144
|
+
with pytest.raises(exc) as info:
|
|
145
|
+
client.list_subscriptions()
|
|
146
|
+
assert info.value.status_code == status
|
|
147
|
+
assert info.value.response_body == "boom"
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
def test_context_manager_closes_client():
|
|
151
|
+
def handler(request: httpx.Request) -> httpx.Response:
|
|
152
|
+
return httpx.Response(200, json=[])
|
|
153
|
+
|
|
154
|
+
with make_client(handler) as client:
|
|
155
|
+
assert client.list_subscriptions() == []
|
|
156
|
+
assert client._client.is_closed
|
relayed-0.2.0/tests/test_sdk.py
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
# import uuid
|
|
2
|
-
|
|
3
|
-
# from relayed.sdk.src.relayed.relayed_sdk import RelayedClient
|
|
4
|
-
# import os
|
|
5
|
-
# from dotenv import load_dotenv, find_dotenv
|
|
6
|
-
# from pathlib import Path
|
|
7
|
-
|
|
8
|
-
# load_dotenv(find_dotenv(), override=False)
|
|
9
|
-
# relayed = RelayedClient(os.getenv("API_KEY"), base_url="http://localhost:8000")
|
|
10
|
-
|
|
11
|
-
# subscription = relayed.create_subscription(
|
|
12
|
-
# destination_url="https://webhook.site/1a4b3201-2814-46b7-aa13-ababfa88b463",
|
|
13
|
-
# event_types=["test.event"],
|
|
14
|
-
# )
|
|
15
|
-
# print("subscription:", subscription["id"], "webhook_secret:", subscription["webhook_secret"])
|
|
16
|
-
|
|
17
|
-
# result = relayed.send_event(
|
|
18
|
-
# event_type="test.event",
|
|
19
|
-
# payload={"message": "Hello from the SDK", "source": "test_sdk.py"},
|
|
20
|
-
# idempotency_key=str(uuid.uuid4()),
|
|
21
|
-
# )
|
|
22
|
-
|
|
23
|
-
# print("event:", result["event_id"], "deliveries:", result["delivery_ids"])
|
|
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
|