hookbase 2.1.1__tar.gz → 2.3.0__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 (80) hide show
  1. {hookbase-2.1.1 → hookbase-2.3.0}/PKG-INFO +1 -1
  2. hookbase-2.3.0/src/hookbase/_version.py +1 -0
  3. {hookbase-2.1.1 → hookbase-2.3.0}/src/hookbase/models/__init__.py +12 -0
  4. {hookbase-2.1.1 → hookbase-2.3.0}/src/hookbase/models/destinations.py +79 -2
  5. {hookbase-2.1.1 → hookbase-2.3.0}/src/hookbase/models/endpoints.py +3 -0
  6. hookbase-2.3.0/tests/resources/test_destinations.py +193 -0
  7. hookbase-2.1.1/src/hookbase/_version.py +0 -1
  8. hookbase-2.1.1/tests/resources/test_destinations.py +0 -72
  9. {hookbase-2.1.1 → hookbase-2.3.0}/.github/workflows/python-publish.yml +0 -0
  10. {hookbase-2.1.1 → hookbase-2.3.0}/.gitignore +0 -0
  11. {hookbase-2.1.1 → hookbase-2.3.0}/LICENSE +0 -0
  12. {hookbase-2.1.1 → hookbase-2.3.0}/README.md +0 -0
  13. {hookbase-2.1.1 → hookbase-2.3.0}/examples/async_usage.py +0 -0
  14. {hookbase-2.1.1 → hookbase-2.3.0}/examples/basic_inbound.py +0 -0
  15. {hookbase-2.1.1 → hookbase-2.3.0}/examples/error_handling.py +0 -0
  16. {hookbase-2.1.1 → hookbase-2.3.0}/examples/send_webhooks.py +0 -0
  17. {hookbase-2.1.1 → hookbase-2.3.0}/examples/verify_webhooks.py +0 -0
  18. {hookbase-2.1.1 → hookbase-2.3.0}/pyproject.toml +0 -0
  19. {hookbase-2.1.1 → hookbase-2.3.0}/src/hookbase/__init__.py +0 -0
  20. {hookbase-2.1.1 → hookbase-2.3.0}/src/hookbase/_client.py +0 -0
  21. {hookbase-2.1.1 → hookbase-2.3.0}/src/hookbase/_constants.py +0 -0
  22. {hookbase-2.1.1 → hookbase-2.3.0}/src/hookbase/_pagination.py +0 -0
  23. {hookbase-2.1.1 → hookbase-2.3.0}/src/hookbase/client.py +0 -0
  24. {hookbase-2.1.1 → hookbase-2.3.0}/src/hookbase/errors.py +0 -0
  25. {hookbase-2.1.1 → hookbase-2.3.0}/src/hookbase/models/_base.py +0 -0
  26. {hookbase-2.1.1 → hookbase-2.3.0}/src/hookbase/models/analytics.py +0 -0
  27. {hookbase-2.1.1 → hookbase-2.3.0}/src/hookbase/models/api_keys.py +0 -0
  28. {hookbase-2.1.1 → hookbase-2.3.0}/src/hookbase/models/applications.py +0 -0
  29. {hookbase-2.1.1 → hookbase-2.3.0}/src/hookbase/models/common.py +0 -0
  30. {hookbase-2.1.1 → hookbase-2.3.0}/src/hookbase/models/cron_jobs.py +0 -0
  31. {hookbase-2.1.1 → hookbase-2.3.0}/src/hookbase/models/deliveries.py +0 -0
  32. {hookbase-2.1.1 → hookbase-2.3.0}/src/hookbase/models/dlq.py +0 -0
  33. {hookbase-2.1.1 → hookbase-2.3.0}/src/hookbase/models/event_types.py +0 -0
  34. {hookbase-2.1.1 → hookbase-2.3.0}/src/hookbase/models/events.py +0 -0
  35. {hookbase-2.1.1 → hookbase-2.3.0}/src/hookbase/models/filters.py +0 -0
  36. {hookbase-2.1.1 → hookbase-2.3.0}/src/hookbase/models/messages.py +0 -0
  37. {hookbase-2.1.1 → hookbase-2.3.0}/src/hookbase/models/organizations.py +0 -0
  38. {hookbase-2.1.1 → hookbase-2.3.0}/src/hookbase/models/portal_tokens.py +0 -0
  39. {hookbase-2.1.1 → hookbase-2.3.0}/src/hookbase/models/routes.py +0 -0
  40. {hookbase-2.1.1 → hookbase-2.3.0}/src/hookbase/models/schemas.py +0 -0
  41. {hookbase-2.1.1 → hookbase-2.3.0}/src/hookbase/models/sources.py +0 -0
  42. {hookbase-2.1.1 → hookbase-2.3.0}/src/hookbase/models/subscriptions.py +0 -0
  43. {hookbase-2.1.1 → hookbase-2.3.0}/src/hookbase/models/transforms.py +0 -0
  44. {hookbase-2.1.1 → hookbase-2.3.0}/src/hookbase/models/tunnels.py +0 -0
  45. {hookbase-2.1.1 → hookbase-2.3.0}/src/hookbase/py.typed +0 -0
  46. {hookbase-2.1.1 → hookbase-2.3.0}/src/hookbase/resources/__init__.py +0 -0
  47. {hookbase-2.1.1 → hookbase-2.3.0}/src/hookbase/resources/_base.py +0 -0
  48. {hookbase-2.1.1 → hookbase-2.3.0}/src/hookbase/resources/analytics.py +0 -0
  49. {hookbase-2.1.1 → hookbase-2.3.0}/src/hookbase/resources/api_keys.py +0 -0
  50. {hookbase-2.1.1 → hookbase-2.3.0}/src/hookbase/resources/applications.py +0 -0
  51. {hookbase-2.1.1 → hookbase-2.3.0}/src/hookbase/resources/cron_jobs.py +0 -0
  52. {hookbase-2.1.1 → hookbase-2.3.0}/src/hookbase/resources/deliveries.py +0 -0
  53. {hookbase-2.1.1 → hookbase-2.3.0}/src/hookbase/resources/destinations.py +0 -0
  54. {hookbase-2.1.1 → hookbase-2.3.0}/src/hookbase/resources/dlq.py +0 -0
  55. {hookbase-2.1.1 → hookbase-2.3.0}/src/hookbase/resources/endpoints.py +0 -0
  56. {hookbase-2.1.1 → hookbase-2.3.0}/src/hookbase/resources/event_types.py +0 -0
  57. {hookbase-2.1.1 → hookbase-2.3.0}/src/hookbase/resources/events.py +0 -0
  58. {hookbase-2.1.1 → hookbase-2.3.0}/src/hookbase/resources/filters.py +0 -0
  59. {hookbase-2.1.1 → hookbase-2.3.0}/src/hookbase/resources/message_log.py +0 -0
  60. {hookbase-2.1.1 → hookbase-2.3.0}/src/hookbase/resources/messages.py +0 -0
  61. {hookbase-2.1.1 → hookbase-2.3.0}/src/hookbase/resources/organizations.py +0 -0
  62. {hookbase-2.1.1 → hookbase-2.3.0}/src/hookbase/resources/portal_tokens.py +0 -0
  63. {hookbase-2.1.1 → hookbase-2.3.0}/src/hookbase/resources/routes.py +0 -0
  64. {hookbase-2.1.1 → hookbase-2.3.0}/src/hookbase/resources/schemas.py +0 -0
  65. {hookbase-2.1.1 → hookbase-2.3.0}/src/hookbase/resources/sources.py +0 -0
  66. {hookbase-2.1.1 → hookbase-2.3.0}/src/hookbase/resources/subscriptions.py +0 -0
  67. {hookbase-2.1.1 → hookbase-2.3.0}/src/hookbase/resources/transforms.py +0 -0
  68. {hookbase-2.1.1 → hookbase-2.3.0}/src/hookbase/resources/tunnels.py +0 -0
  69. {hookbase-2.1.1 → hookbase-2.3.0}/src/hookbase/webhook.py +0 -0
  70. {hookbase-2.1.1 → hookbase-2.3.0}/tests/__init__.py +0 -0
  71. {hookbase-2.1.1 → hookbase-2.3.0}/tests/conftest.py +0 -0
  72. {hookbase-2.1.1 → hookbase-2.3.0}/tests/resources/__init__.py +0 -0
  73. {hookbase-2.1.1 → hookbase-2.3.0}/tests/resources/test_applications.py +0 -0
  74. {hookbase-2.1.1 → hookbase-2.3.0}/tests/resources/test_dlq.py +0 -0
  75. {hookbase-2.1.1 → hookbase-2.3.0}/tests/resources/test_messages.py +0 -0
  76. {hookbase-2.1.1 → hookbase-2.3.0}/tests/resources/test_sources.py +0 -0
  77. {hookbase-2.1.1 → hookbase-2.3.0}/tests/test_client.py +0 -0
  78. {hookbase-2.1.1 → hookbase-2.3.0}/tests/test_errors.py +0 -0
  79. {hookbase-2.1.1 → hookbase-2.3.0}/tests/test_pagination.py +0 -0
  80. {hookbase-2.1.1 → hookbase-2.3.0}/tests/test_webhook.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: hookbase
3
- Version: 2.1.1
3
+ Version: 2.3.0
4
4
  Summary: Official Python SDK for the Hookbase webhook management platform
5
5
  Project-URL: Homepage, https://hookbase.app
6
6
  Project-URL: Documentation, https://docs.hookbase.app/sdk/python
@@ -0,0 +1 @@
1
+ __version__ = "2.3.0"
@@ -18,9 +18,15 @@ from .deliveries import (
18
18
  )
19
19
  from .destinations import (
20
20
  AuthType,
21
+ AzureBlobConfig,
21
22
  CreateDestinationParams,
22
23
  Destination,
24
+ DestinationType,
25
+ FieldMapping,
26
+ GCSConfig,
23
27
  HttpMethod,
28
+ R2Config,
29
+ S3Config,
24
30
  TestResult,
25
31
  UpdateDestinationParams,
26
32
  )
@@ -123,9 +129,15 @@ __all__ = [
123
129
  "ReplayResult",
124
130
  # Destinations
125
131
  "AuthType",
132
+ "AzureBlobConfig",
126
133
  "CreateDestinationParams",
127
134
  "Destination",
135
+ "DestinationType",
136
+ "FieldMapping",
137
+ "GCSConfig",
128
138
  "HttpMethod",
139
+ "R2Config",
140
+ "S3Config",
129
141
  "TestResult",
130
142
  "UpdateDestinationParams",
131
143
  # DLQ
@@ -9,6 +9,52 @@ from ._base import HookbaseModel
9
9
 
10
10
  HttpMethod = Literal["GET", "POST", "PUT", "PATCH", "DELETE"]
11
11
  AuthType = Literal["none", "basic", "bearer", "api_key", "custom_header"]
12
+ DestinationType = Literal["http", "s3", "r2", "gcs", "azure_blob"]
13
+ FileFormat = Literal["json", "jsonl"]
14
+ PartitionBy = Literal["date", "hour", "source"]
15
+ FieldMappingType = Literal["string", "number", "boolean", "timestamp", "json"]
16
+
17
+
18
+ class FieldMapping(HookbaseModel):
19
+ source: str
20
+ target: str
21
+ type: FieldMappingType
22
+ default: str | None = None
23
+
24
+
25
+ class S3Config(HookbaseModel):
26
+ bucket: str
27
+ region: str
28
+ access_key_id: str
29
+ secret_access_key: str
30
+ prefix: str | None = None
31
+ file_format: FileFormat | None = None
32
+ partition_by: PartitionBy | None = None
33
+
34
+
35
+ class R2Config(HookbaseModel):
36
+ bucket: str
37
+ prefix: str | None = None
38
+ file_format: FileFormat | None = None
39
+ partition_by: PartitionBy | None = None
40
+
41
+
42
+ class GCSConfig(HookbaseModel):
43
+ bucket: str
44
+ project_id: str
45
+ service_account_key: str
46
+ prefix: str | None = None
47
+ file_format: FileFormat | None = None
48
+ partition_by: PartitionBy | None = None
49
+
50
+
51
+ class AzureBlobConfig(HookbaseModel):
52
+ account_name: str
53
+ account_key: str
54
+ container_name: str
55
+ prefix: str | None = None
56
+ file_format: FileFormat | None = None
57
+ partition_by: PartitionBy | None = None
12
58
 
13
59
 
14
60
  class Destination(HookbaseModel):
@@ -17,7 +63,8 @@ class Destination(HookbaseModel):
17
63
  name: str
18
64
  slug: str
19
65
  description: str | None = None
20
- url: str
66
+ type: DestinationType = "http"
67
+ url: str = ""
21
68
  method: HttpMethod = "POST"
22
69
  headers: dict[str, str] | None = None
23
70
  auth_type: str | None = "none"
@@ -28,6 +75,9 @@ class Destination(HookbaseModel):
28
75
  rate_limit: int | None = None
29
76
  rate_limit_window: int | None = None
30
77
  is_active: bool = True
78
+ use_static_ip: bool = True
79
+ config: dict[str, Any] | None = None
80
+ field_mapping: list[FieldMapping] | None = None
31
81
  delivery_count: int = 0
32
82
  last_delivery_at: str | None = None
33
83
  created_at: str = ""
@@ -53,6 +103,26 @@ class Destination(HookbaseModel):
53
103
  return None
54
104
  return v
55
105
 
106
+ @field_validator("config", mode="before")
107
+ @classmethod
108
+ def parse_config(cls, v: Any) -> Any:
109
+ if isinstance(v, str):
110
+ try:
111
+ return json.loads(v)
112
+ except (json.JSONDecodeError, ValueError):
113
+ return None
114
+ return v
115
+
116
+ @field_validator("field_mapping", mode="before")
117
+ @classmethod
118
+ def parse_field_mapping(cls, v: Any) -> Any:
119
+ if isinstance(v, str):
120
+ try:
121
+ return json.loads(v)
122
+ except (json.JSONDecodeError, ValueError):
123
+ return None
124
+ return v
125
+
56
126
  @field_validator("is_active", mode="before")
57
127
  @classmethod
58
128
  def parse_is_active(cls, v: Any) -> Any:
@@ -65,7 +135,8 @@ class CreateDestinationParams(HookbaseModel):
65
135
  name: str
66
136
  slug: str | None = None
67
137
  description: str | None = None
68
- url: str
138
+ type: DestinationType | None = None
139
+ url: str | None = None
69
140
  method: HttpMethod | None = None
70
141
  headers: dict[str, str] | None = None
71
142
  auth_type: AuthType | None = None
@@ -75,6 +146,9 @@ class CreateDestinationParams(HookbaseModel):
75
146
  retry_interval: int | None = None
76
147
  rate_limit: int | None = None
77
148
  rate_limit_window: int | None = None
149
+ config: dict[str, Any] | None = None
150
+ field_mapping: list[FieldMapping] | None = None
151
+ use_static_ip: bool | None = None
78
152
 
79
153
 
80
154
  class UpdateDestinationParams(HookbaseModel):
@@ -91,6 +165,9 @@ class UpdateDestinationParams(HookbaseModel):
91
165
  rate_limit: int | None = None
92
166
  rate_limit_window: int | None = None
93
167
  is_active: bool | None = None
168
+ config: dict[str, Any] | None = None
169
+ field_mapping: list[FieldMapping] | None = None
170
+ use_static_ip: bool | None = None
94
171
 
95
172
 
96
173
  class TestResult(HookbaseModel):
@@ -30,6 +30,7 @@ class WebhookEndpoint(HookbaseModel):
30
30
  return {}
31
31
  return v
32
32
  metadata: dict[str, Any] | None = None
33
+ use_static_ip: bool = True
33
34
  total_messages: int = 0
34
35
  total_successes: int = 0
35
36
  total_failures: int = 0
@@ -49,6 +50,7 @@ class CreateEndpointParams(HookbaseModel):
49
50
  rate_limit_period: int | None = None
50
51
  headers: dict[str, str] | None = None
51
52
  metadata: dict[str, Any] | None = None
53
+ use_static_ip: bool | None = None
52
54
 
53
55
 
54
56
  class UpdateEndpointParams(HookbaseModel):
@@ -60,6 +62,7 @@ class UpdateEndpointParams(HookbaseModel):
60
62
  rate_limit_period: int | None = None
61
63
  headers: dict[str, str] | None = None
62
64
  metadata: dict[str, Any] | None = None
65
+ use_static_ip: bool | None = None
63
66
 
64
67
 
65
68
  class EndpointStats(HookbaseModel):
@@ -0,0 +1,193 @@
1
+ from __future__ import annotations
2
+
3
+ import pytest
4
+ import respx
5
+
6
+ from hookbase import Hookbase
7
+ from hookbase.models import Destination, FieldMapping, TestResult
8
+
9
+ from ..conftest import make_paginated_response
10
+
11
+
12
+ @pytest.fixture
13
+ def mock_api():
14
+ with respx.mock(base_url="https://api.hookbase.app") as mock:
15
+ yield mock
16
+
17
+
18
+ @pytest.fixture
19
+ def client(mock_api):
20
+ c = Hookbase(api_key="whr_test")
21
+ yield c
22
+ c.close()
23
+
24
+
25
+ DEST_DATA = {
26
+ "id": "dst_1",
27
+ "organizationId": "org_1",
28
+ "name": "Backend",
29
+ "slug": "backend",
30
+ "type": "http",
31
+ "url": "https://example.com/webhooks",
32
+ "method": "POST",
33
+ "authType": "none",
34
+ "timeout": 30,
35
+ "retryCount": 3,
36
+ "retryInterval": 60,
37
+ "isActive": True,
38
+ "config": None,
39
+ "fieldMapping": None,
40
+ "deliveryCount": 100,
41
+ "createdAt": "2024-01-01T00:00:00Z",
42
+ "updatedAt": "2024-01-01T00:00:00Z",
43
+ }
44
+
45
+ S3_DEST_DATA = {
46
+ "id": "dst_s3",
47
+ "organizationId": "org_1",
48
+ "name": "S3 Archive",
49
+ "slug": "s3-archive",
50
+ "type": "s3",
51
+ "url": "",
52
+ "method": "POST",
53
+ "authType": "none",
54
+ "timeout": 30,
55
+ "retryCount": 3,
56
+ "retryInterval": 60,
57
+ "isActive": True,
58
+ "config": {
59
+ "bucket": "my-webhooks",
60
+ "region": "us-east-1",
61
+ "accessKeyId": "AKIAIOSFODNN7EXAMPLE",
62
+ "secretAccessKey": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",
63
+ "prefix": "events/",
64
+ "fileFormat": "jsonl",
65
+ "partitionBy": "date",
66
+ },
67
+ "fieldMapping": [
68
+ {"source": "$.id", "target": "event_id", "type": "string"},
69
+ {"source": "$.payload", "target": "data", "type": "json"},
70
+ {"source": "$.timestamp", "target": "received_at", "type": "timestamp", "default": "now()"},
71
+ ],
72
+ "deliveryCount": 0,
73
+ "createdAt": "2024-01-01T00:00:00Z",
74
+ "updatedAt": "2024-01-01T00:00:00Z",
75
+ }
76
+
77
+
78
+ def test_list_destinations(mock_api, client):
79
+ mock_api.get("/api/destinations").respond(200, json=make_paginated_response(
80
+ [DEST_DATA], data_key="destinations", total=1,
81
+ ))
82
+ page = client.destinations.list()
83
+ assert len(page) == 1
84
+ assert page.data[0].name == "Backend"
85
+
86
+
87
+ def test_get_destination(mock_api, client):
88
+ mock_api.get("/api/destinations/dst_1").respond(200, json={"destination": DEST_DATA})
89
+ dest = client.destinations.get("dst_1")
90
+ assert isinstance(dest, Destination)
91
+ assert dest.url == "https://example.com/webhooks"
92
+ assert dest.type == "http"
93
+ assert dest.config is None
94
+ assert dest.field_mapping is None
95
+
96
+
97
+ def test_get_warehouse_destination(mock_api, client):
98
+ mock_api.get("/api/destinations/dst_s3").respond(200, json={"destination": S3_DEST_DATA})
99
+ dest = client.destinations.get("dst_s3")
100
+ assert isinstance(dest, Destination)
101
+ assert dest.type == "s3"
102
+ assert dest.config is not None
103
+ assert dest.config["bucket"] == "my-webhooks"
104
+ assert dest.config["region"] == "us-east-1"
105
+ assert dest.field_mapping is not None
106
+ assert len(dest.field_mapping) == 3
107
+ assert dest.field_mapping[0].source == "$.id"
108
+ assert dest.field_mapping[0].target == "event_id"
109
+ assert dest.field_mapping[0].type == "string"
110
+ assert dest.field_mapping[2].default == "now()"
111
+
112
+
113
+ def test_create_destination(mock_api, client):
114
+ mock_api.post("/api/destinations").respond(200, json={"destination": DEST_DATA})
115
+ dest = client.destinations.create({"name": "Backend", "url": "https://example.com/webhooks"})
116
+ assert dest.id == "dst_1"
117
+ assert dest.type == "http"
118
+
119
+
120
+ def test_create_warehouse_destination(mock_api, client):
121
+ mock_api.post("/api/destinations").respond(200, json={"destination": S3_DEST_DATA})
122
+ dest = client.destinations.create({
123
+ "name": "S3 Archive",
124
+ "type": "s3",
125
+ "config": {
126
+ "bucket": "my-webhooks",
127
+ "region": "us-east-1",
128
+ "accessKeyId": "AKIAIOSFODNN7EXAMPLE",
129
+ "secretAccessKey": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",
130
+ },
131
+ "fieldMapping": [
132
+ {"source": "$.id", "target": "event_id", "type": "string"},
133
+ ],
134
+ })
135
+ assert dest.id == "dst_s3"
136
+ assert dest.type == "s3"
137
+ assert dest.config is not None
138
+ assert dest.field_mapping is not None
139
+
140
+
141
+ def test_update_warehouse_destination_config(mock_api, client):
142
+ updated = {**S3_DEST_DATA, "config": {**S3_DEST_DATA["config"], "bucket": "new-bucket"}}
143
+ mock_api.patch("/api/destinations/dst_s3").respond(200, json={"destination": updated})
144
+ client.destinations.update("dst_s3", {
145
+ "config": {
146
+ "bucket": "new-bucket",
147
+ "region": "us-east-1",
148
+ "accessKeyId": "AKIA",
149
+ "secretAccessKey": "secret",
150
+ },
151
+ "fieldMapping": [
152
+ {"source": "$.body", "target": "payload", "type": "json"},
153
+ ],
154
+ })
155
+
156
+
157
+ def test_field_mapping_model():
158
+ fm = FieldMapping(source="$.id", target="event_id", type="string")
159
+ assert fm.source == "$.id"
160
+ assert fm.target == "event_id"
161
+ assert fm.type == "string"
162
+ assert fm.default is None
163
+
164
+ fm_with_default = FieldMapping(
165
+ source="$.ts", target="timestamp", type="timestamp", default="now()",
166
+ )
167
+ assert fm_with_default.default == "now()"
168
+
169
+
170
+ def test_destination_without_type_defaults():
171
+ """Destinations without type field should default to http."""
172
+ data = {
173
+ "id": "dst_old",
174
+ "name": "Old Dest",
175
+ "slug": "old-dest",
176
+ "url": "https://example.com",
177
+ "method": "POST",
178
+ "isActive": True,
179
+ }
180
+ dest = Destination(**data)
181
+ assert dest.type == "http"
182
+ assert dest.config is None
183
+ assert dest.field_mapping is None
184
+
185
+
186
+ def test_test_destination(mock_api, client):
187
+ mock_api.post("/api/destinations/dst_1/test").respond(200, json={
188
+ "success": True, "statusCode": 200, "duration": 150.5,
189
+ })
190
+ result = client.destinations.test("dst_1")
191
+ assert isinstance(result, TestResult)
192
+ assert result.success is True
193
+ assert result.status_code == 200
@@ -1 +0,0 @@
1
- __version__ = "2.1.1"
@@ -1,72 +0,0 @@
1
- from __future__ import annotations
2
-
3
- import pytest
4
- import respx
5
-
6
- from hookbase import Hookbase
7
- from hookbase.models import Destination, TestResult
8
-
9
- from ..conftest import make_paginated_response
10
-
11
-
12
- @pytest.fixture
13
- def mock_api():
14
- with respx.mock(base_url="https://api.hookbase.app") as mock:
15
- yield mock
16
-
17
-
18
- @pytest.fixture
19
- def client(mock_api):
20
- c = Hookbase(api_key="whr_test")
21
- yield c
22
- c.close()
23
-
24
-
25
- DEST_DATA = {
26
- "id": "dst_1",
27
- "organizationId": "org_1",
28
- "name": "Backend",
29
- "slug": "backend",
30
- "url": "https://example.com/webhooks",
31
- "method": "POST",
32
- "authType": "none",
33
- "timeout": 30,
34
- "retryCount": 3,
35
- "retryInterval": 60,
36
- "isActive": True,
37
- "deliveryCount": 100,
38
- "createdAt": "2024-01-01T00:00:00Z",
39
- "updatedAt": "2024-01-01T00:00:00Z",
40
- }
41
-
42
-
43
- def test_list_destinations(mock_api, client):
44
- mock_api.get("/api/destinations").respond(200, json=make_paginated_response(
45
- [DEST_DATA], data_key="destinations", total=1,
46
- ))
47
- page = client.destinations.list()
48
- assert len(page) == 1
49
- assert page.data[0].name == "Backend"
50
-
51
-
52
- def test_get_destination(mock_api, client):
53
- mock_api.get("/api/destinations/dst_1").respond(200, json={"destination": DEST_DATA})
54
- dest = client.destinations.get("dst_1")
55
- assert isinstance(dest, Destination)
56
- assert dest.url == "https://example.com/webhooks"
57
-
58
-
59
- def test_create_destination(mock_api, client):
60
- mock_api.post("/api/destinations").respond(200, json={"destination": DEST_DATA})
61
- dest = client.destinations.create({"name": "Backend", "url": "https://example.com/webhooks"})
62
- assert dest.id == "dst_1"
63
-
64
-
65
- def test_test_destination(mock_api, client):
66
- mock_api.post("/api/destinations/dst_1/test").respond(200, json={
67
- "success": True, "statusCode": 200, "duration": 150.5,
68
- })
69
- result = client.destinations.test("dst_1")
70
- assert isinstance(result, TestResult)
71
- assert result.success is True
72
- assert result.status_code == 200
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