port-ocean 0.20.3__py3-none-any.whl → 0.20.4__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.
Potentially problematic release.
This version of port-ocean might be problematic. Click here for more details.
- port_ocean/core/handlers/webhook/abstract_webhook_processor.py +2 -2
- port_ocean/core/handlers/webhook/processor_manager.py +16 -12
- port_ocean/tests/core/handlers/webhook/test_abstract_webhook_processor.py +2 -2
- port_ocean/tests/core/handlers/webhook/test_processor_manager.py +174 -36
- {port_ocean-0.20.3.dist-info → port_ocean-0.20.4.dist-info}/METADATA +1 -1
- {port_ocean-0.20.3.dist-info → port_ocean-0.20.4.dist-info}/RECORD +9 -9
- {port_ocean-0.20.3.dist-info → port_ocean-0.20.4.dist-info}/LICENSE.md +0 -0
- {port_ocean-0.20.3.dist-info → port_ocean-0.20.4.dist-info}/WHEEL +0 -0
- {port_ocean-0.20.3.dist-info → port_ocean-0.20.4.dist-info}/entry_points.txt +0 -0
|
@@ -109,9 +109,9 @@ class AbstractWebhookProcessor(ABC):
|
|
|
109
109
|
pass
|
|
110
110
|
|
|
111
111
|
@abstractmethod
|
|
112
|
-
def should_process_event(self, event: WebhookEvent) -> bool:
|
|
112
|
+
async def should_process_event(self, event: WebhookEvent) -> bool:
|
|
113
113
|
pass
|
|
114
114
|
|
|
115
115
|
@abstractmethod
|
|
116
|
-
def get_matching_kinds(self, event: WebhookEvent) -> list[str]:
|
|
116
|
+
async def get_matching_kinds(self, event: WebhookEvent) -> list[str]:
|
|
117
117
|
pass
|
|
@@ -47,7 +47,7 @@ class LiveEventsProcessorManager(LiveEventsMixin, EventsMixin):
|
|
|
47
47
|
except Exception as e:
|
|
48
48
|
logger.exception(f"Error starting queue processor for {path}: {str(e)}")
|
|
49
49
|
|
|
50
|
-
def _extract_matching_processors(
|
|
50
|
+
async def _extract_matching_processors(
|
|
51
51
|
self, webhook_event: WebhookEvent, path: str
|
|
52
52
|
) -> list[tuple[ResourceConfig, AbstractWebhookProcessor]]:
|
|
53
53
|
"""Find and extract the matching processor for an event"""
|
|
@@ -56,8 +56,8 @@ class LiveEventsProcessorManager(LiveEventsMixin, EventsMixin):
|
|
|
56
56
|
|
|
57
57
|
for processor_class in self._processors_classes[path]:
|
|
58
58
|
processor = processor_class(webhook_event.clone())
|
|
59
|
-
if processor.should_process_event(webhook_event):
|
|
60
|
-
kinds = processor.get_matching_kinds(webhook_event)
|
|
59
|
+
if await processor.should_process_event(webhook_event):
|
|
60
|
+
kinds = await processor.get_matching_kinds(webhook_event)
|
|
61
61
|
for kind in kinds:
|
|
62
62
|
for resource in event.port_app_config.resources:
|
|
63
63
|
if resource.kind == kind:
|
|
@@ -92,26 +92,30 @@ class LiveEventsProcessorManager(LiveEventsMixin, EventsMixin):
|
|
|
92
92
|
parent_override=webhook_event.event_context,
|
|
93
93
|
):
|
|
94
94
|
matching_processors_with_resource = (
|
|
95
|
-
self._extract_matching_processors(webhook_event, path)
|
|
95
|
+
await self._extract_matching_processors(webhook_event, path)
|
|
96
96
|
)
|
|
97
97
|
webhook_event_raw_results_for_all_resources = await asyncio.gather(
|
|
98
98
|
*(
|
|
99
99
|
self._process_single_event(processor, path, resource)
|
|
100
100
|
for resource, processor in matching_processors_with_resource
|
|
101
|
-
)
|
|
101
|
+
),
|
|
102
|
+
return_exceptions=True,
|
|
102
103
|
)
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
104
|
+
|
|
105
|
+
successful_raw_results: list[WebhookEventRawResults] = [
|
|
106
|
+
result
|
|
107
|
+
for result in webhook_event_raw_results_for_all_resources
|
|
108
|
+
if isinstance(result, WebhookEventRawResults)
|
|
109
|
+
]
|
|
110
|
+
|
|
111
|
+
if successful_raw_results:
|
|
106
112
|
logger.info(
|
|
107
113
|
"Exporting raw event results to entities",
|
|
108
114
|
webhook_event_raw_results_for_all_resources_length=len(
|
|
109
|
-
|
|
115
|
+
successful_raw_results
|
|
110
116
|
),
|
|
111
117
|
)
|
|
112
|
-
await self.sync_raw_results(
|
|
113
|
-
webhook_event_raw_results_for_all_resources
|
|
114
|
-
)
|
|
118
|
+
await self.sync_raw_results(successful_raw_results)
|
|
115
119
|
except asyncio.CancelledError:
|
|
116
120
|
logger.info(f"Queue processor for {path} is shutting down")
|
|
117
121
|
for _, processor in matching_processors_with_resource:
|
|
@@ -32,7 +32,7 @@ class ConcreteWebhookProcessor(AbstractWebhookProcessor):
|
|
|
32
32
|
) -> WebhookEventRawResults:
|
|
33
33
|
return WebhookEventRawResults(updated_raw_results=[{}], deleted_raw_results=[])
|
|
34
34
|
|
|
35
|
-
def should_process_event(self, webhook_event: WebhookEvent) -> bool:
|
|
35
|
+
async def should_process_event(self, webhook_event: WebhookEvent) -> bool:
|
|
36
36
|
return True
|
|
37
37
|
|
|
38
38
|
async def before_processing(self) -> None:
|
|
@@ -47,7 +47,7 @@ class ConcreteWebhookProcessor(AbstractWebhookProcessor):
|
|
|
47
47
|
await super().cancel()
|
|
48
48
|
self.cancel_called = True
|
|
49
49
|
|
|
50
|
-
def get_matching_kinds(self, event: WebhookEvent) -> list[str]:
|
|
50
|
+
async def get_matching_kinds(self, event: WebhookEvent) -> list[str]:
|
|
51
51
|
return ["test"]
|
|
52
52
|
|
|
53
53
|
|
|
@@ -54,10 +54,10 @@ class MockProcessor(AbstractWebhookProcessor):
|
|
|
54
54
|
) -> WebhookEventRawResults:
|
|
55
55
|
return WebhookEventRawResults(updated_raw_results=[], deleted_raw_results=[])
|
|
56
56
|
|
|
57
|
-
def should_process_event(self, event: WebhookEvent) -> bool:
|
|
57
|
+
async def should_process_event(self, event: WebhookEvent) -> bool:
|
|
58
58
|
return True
|
|
59
59
|
|
|
60
|
-
def get_matching_kinds(self, event: WebhookEvent) -> list[str]:
|
|
60
|
+
async def get_matching_kinds(self, event: WebhookEvent) -> list[str]:
|
|
61
61
|
return ["repository"]
|
|
62
62
|
|
|
63
63
|
|
|
@@ -75,10 +75,10 @@ class MockProcessorFalse(AbstractWebhookProcessor):
|
|
|
75
75
|
) -> WebhookEventRawResults:
|
|
76
76
|
return WebhookEventRawResults(updated_raw_results=[], deleted_raw_results=[])
|
|
77
77
|
|
|
78
|
-
def should_process_event(self, event: WebhookEvent) -> bool:
|
|
78
|
+
async def should_process_event(self, event: WebhookEvent) -> bool:
|
|
79
79
|
return False
|
|
80
80
|
|
|
81
|
-
def get_matching_kinds(self, event: WebhookEvent) -> list[str]:
|
|
81
|
+
async def get_matching_kinds(self, event: WebhookEvent) -> list[str]:
|
|
82
82
|
return ["repository"]
|
|
83
83
|
|
|
84
84
|
|
|
@@ -110,10 +110,10 @@ class MockWebhookProcessor(AbstractWebhookProcessor):
|
|
|
110
110
|
async def cancel(self) -> None:
|
|
111
111
|
self.cancel_called = True
|
|
112
112
|
|
|
113
|
-
def should_process_event(self, event: WebhookEvent) -> bool:
|
|
113
|
+
async def should_process_event(self, event: WebhookEvent) -> bool:
|
|
114
114
|
return True
|
|
115
115
|
|
|
116
|
-
def get_matching_kinds(self, event: WebhookEvent) -> list[str]:
|
|
116
|
+
async def get_matching_kinds(self, event: WebhookEvent) -> list[str]:
|
|
117
117
|
return ["test"]
|
|
118
118
|
|
|
119
119
|
|
|
@@ -155,10 +155,10 @@ class MockWebhookHandlerForProcessWebhookRequest(AbstractWebhookProcessor):
|
|
|
155
155
|
self.handled = True
|
|
156
156
|
return WebhookEventRawResults(updated_raw_results=[], deleted_raw_results=[])
|
|
157
157
|
|
|
158
|
-
def get_matching_kinds(self, event: WebhookEvent) -> list[str]:
|
|
158
|
+
async def get_matching_kinds(self, event: WebhookEvent) -> list[str]:
|
|
159
159
|
return ["repository"]
|
|
160
160
|
|
|
161
|
-
def should_process_event(self, event: WebhookEvent) -> bool:
|
|
161
|
+
async def should_process_event(self, event: WebhookEvent) -> bool:
|
|
162
162
|
"""Filter the event data before processing."""
|
|
163
163
|
return True
|
|
164
164
|
|
|
@@ -329,16 +329,16 @@ async def test_extractMatchingProcessors_processorMatch(
|
|
|
329
329
|
|
|
330
330
|
async with event_context(EventType.HTTP_REQUEST, trigger_type="request") as event:
|
|
331
331
|
event.port_app_config = mock_port_app_config
|
|
332
|
-
processors = processor_manager._extract_matching_processors(
|
|
332
|
+
processors = await processor_manager._extract_matching_processors(
|
|
333
333
|
webhook_event, test_path
|
|
334
334
|
)
|
|
335
335
|
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
336
|
+
assert len(processors) == 1
|
|
337
|
+
config, processor = processors[0]
|
|
338
|
+
assert isinstance(processor, MockProcessor)
|
|
339
|
+
assert config.kind == "repository"
|
|
340
|
+
assert processor.event != webhook_event
|
|
341
|
+
assert processor.event.payload == webhook_event.payload
|
|
342
342
|
|
|
343
343
|
|
|
344
344
|
@pytest.mark.asyncio
|
|
@@ -355,7 +355,9 @@ async def test_extractMatchingProcessors_noMatch(
|
|
|
355
355
|
EventType.HTTP_REQUEST, trigger_type="request"
|
|
356
356
|
) as event:
|
|
357
357
|
event.port_app_config = mock_port_app_config
|
|
358
|
-
processor_manager._extract_matching_processors(
|
|
358
|
+
await processor_manager._extract_matching_processors(
|
|
359
|
+
webhook_event, test_path
|
|
360
|
+
)
|
|
359
361
|
|
|
360
362
|
|
|
361
363
|
@pytest.mark.asyncio
|
|
@@ -370,7 +372,7 @@ async def test_extractMatchingProcessors_multipleMatches(
|
|
|
370
372
|
|
|
371
373
|
async with event_context(EventType.HTTP_REQUEST, trigger_type="request") as event:
|
|
372
374
|
event.port_app_config = mock_port_app_config
|
|
373
|
-
processors = processor_manager._extract_matching_processors(
|
|
375
|
+
processors = await processor_manager._extract_matching_processors(
|
|
374
376
|
webhook_event, test_path
|
|
375
377
|
)
|
|
376
378
|
|
|
@@ -391,7 +393,7 @@ async def test_extractMatchingProcessors_onlyOneMatches(
|
|
|
391
393
|
|
|
392
394
|
async with event_context(EventType.HTTP_REQUEST, trigger_type="request") as event:
|
|
393
395
|
event.port_app_config = mock_port_app_config
|
|
394
|
-
processors = processor_manager._extract_matching_processors(
|
|
396
|
+
processors = await processor_manager._extract_matching_processors(
|
|
395
397
|
webhook_event, test_path
|
|
396
398
|
)
|
|
397
399
|
|
|
@@ -542,10 +544,10 @@ async def test_integrationTest_postRequestSent_webhookEventRawResultProcessed_en
|
|
|
542
544
|
processed_events.append(event_data)
|
|
543
545
|
return event_data
|
|
544
546
|
|
|
545
|
-
def should_process_event(self, event: WebhookEvent) -> bool:
|
|
547
|
+
async def should_process_event(self, event: WebhookEvent) -> bool:
|
|
546
548
|
return True
|
|
547
549
|
|
|
548
|
-
def get_matching_kinds(self, event: WebhookEvent) -> list[str]:
|
|
550
|
+
async def get_matching_kinds(self, event: WebhookEvent) -> list[str]:
|
|
549
551
|
return ["repository"]
|
|
550
552
|
|
|
551
553
|
processing_complete = asyncio.Event()
|
|
@@ -649,10 +651,10 @@ async def test_integrationTest_postRequestSent_reachedTimeout_entityNotUpserted(
|
|
|
649
651
|
updated_raw_results=[], deleted_raw_results=[]
|
|
650
652
|
)
|
|
651
653
|
|
|
652
|
-
def should_process_event(self, event: WebhookEvent) -> bool:
|
|
654
|
+
async def should_process_event(self, event: WebhookEvent) -> bool:
|
|
653
655
|
return True
|
|
654
656
|
|
|
655
|
-
def get_matching_kinds(self, event: WebhookEvent) -> list[str]:
|
|
657
|
+
async def get_matching_kinds(self, event: WebhookEvent) -> list[str]:
|
|
656
658
|
return ["repository"]
|
|
657
659
|
|
|
658
660
|
processing_complete = asyncio.Event()
|
|
@@ -766,20 +768,20 @@ async def test_integrationTest_postRequestSent_noMatchingHandlers_entityNotUpser
|
|
|
766
768
|
)
|
|
767
769
|
return event_data
|
|
768
770
|
|
|
769
|
-
def should_process_event(self, event: WebhookEvent) -> bool:
|
|
771
|
+
async def should_process_event(self, event: WebhookEvent) -> bool:
|
|
770
772
|
return False
|
|
771
773
|
|
|
772
|
-
def get_matching_kinds(self, event: WebhookEvent) -> list[str]:
|
|
774
|
+
async def get_matching_kinds(self, event: WebhookEvent) -> list[str]:
|
|
773
775
|
return ["repository"]
|
|
774
776
|
|
|
775
777
|
processing_complete = asyncio.Event()
|
|
776
778
|
original_process_data = LiveEventsProcessorManager._extract_matching_processors
|
|
777
779
|
|
|
778
|
-
def patched_extract_matching_processors(
|
|
780
|
+
async def patched_extract_matching_processors(
|
|
779
781
|
self: LiveEventsProcessorManager, event: WebhookEvent, path: str
|
|
780
782
|
) -> list[tuple[ResourceConfig, AbstractWebhookProcessor]]:
|
|
781
783
|
try:
|
|
782
|
-
return original_process_data(self, event, path)
|
|
784
|
+
return await original_process_data(self, event, path)
|
|
783
785
|
except Exception as e:
|
|
784
786
|
test_state["exception_thrown"] = e # type: ignore
|
|
785
787
|
return []
|
|
@@ -882,10 +884,10 @@ async def test_integrationTest_postRequestSent_webhookEventRawResultProcessedFor
|
|
|
882
884
|
processed_events.append(event_data)
|
|
883
885
|
return event_data
|
|
884
886
|
|
|
885
|
-
def should_process_event(self, event: WebhookEvent) -> bool:
|
|
887
|
+
async def should_process_event(self, event: WebhookEvent) -> bool:
|
|
886
888
|
return True
|
|
887
889
|
|
|
888
|
-
def get_matching_kinds(self, event: WebhookEvent) -> list[str]:
|
|
890
|
+
async def get_matching_kinds(self, event: WebhookEvent) -> list[str]:
|
|
889
891
|
return ["repository"]
|
|
890
892
|
|
|
891
893
|
class TestProcessorB(AbstractWebhookProcessor):
|
|
@@ -913,10 +915,10 @@ async def test_integrationTest_postRequestSent_webhookEventRawResultProcessedFor
|
|
|
913
915
|
processed_events.append(event_data)
|
|
914
916
|
return event_data
|
|
915
917
|
|
|
916
|
-
def should_process_event(self, event: WebhookEvent) -> bool:
|
|
918
|
+
async def should_process_event(self, event: WebhookEvent) -> bool:
|
|
917
919
|
return True
|
|
918
920
|
|
|
919
|
-
def get_matching_kinds(self, event: WebhookEvent) -> list[str]:
|
|
921
|
+
async def get_matching_kinds(self, event: WebhookEvent) -> list[str]:
|
|
920
922
|
return ["repository"]
|
|
921
923
|
|
|
922
924
|
class TestProcessorFiltersOut(AbstractWebhookProcessor):
|
|
@@ -944,10 +946,10 @@ async def test_integrationTest_postRequestSent_webhookEventRawResultProcessedFor
|
|
|
944
946
|
processed_events.append(event_data)
|
|
945
947
|
return event_data
|
|
946
948
|
|
|
947
|
-
def should_process_event(self, event: WebhookEvent) -> bool:
|
|
949
|
+
async def should_process_event(self, event: WebhookEvent) -> bool:
|
|
948
950
|
return False
|
|
949
951
|
|
|
950
|
-
def get_matching_kinds(self, event: WebhookEvent) -> list[str]:
|
|
952
|
+
async def get_matching_kinds(self, event: WebhookEvent) -> list[str]:
|
|
951
953
|
return ["repository"]
|
|
952
954
|
|
|
953
955
|
processing_complete = asyncio.Event()
|
|
@@ -1071,10 +1073,10 @@ async def test_integrationTest_postRequestSent_webhookEventRawResultProcessedwit
|
|
|
1071
1073
|
processed_events.append(event_data)
|
|
1072
1074
|
return event_data
|
|
1073
1075
|
|
|
1074
|
-
def should_process_event(self, event: WebhookEvent) -> bool:
|
|
1076
|
+
async def should_process_event(self, event: WebhookEvent) -> bool:
|
|
1075
1077
|
return True
|
|
1076
1078
|
|
|
1077
|
-
def get_matching_kinds(self, event: WebhookEvent) -> list[str]:
|
|
1079
|
+
async def get_matching_kinds(self, event: WebhookEvent) -> list[str]:
|
|
1078
1080
|
return ["repository"]
|
|
1079
1081
|
|
|
1080
1082
|
processing_complete = asyncio.Event()
|
|
@@ -1195,10 +1197,10 @@ async def test_integrationTest_postRequestSent_webhookEventRawResultProcessedwit
|
|
|
1195
1197
|
processed_events.append(event_data)
|
|
1196
1198
|
return event_data
|
|
1197
1199
|
|
|
1198
|
-
def should_process_event(self, event: WebhookEvent) -> bool:
|
|
1200
|
+
async def should_process_event(self, event: WebhookEvent) -> bool:
|
|
1199
1201
|
return True
|
|
1200
1202
|
|
|
1201
|
-
def get_matching_kinds(self, event: WebhookEvent) -> list[str]:
|
|
1203
|
+
async def get_matching_kinds(self, event: WebhookEvent) -> list[str]:
|
|
1202
1204
|
return ["repository"]
|
|
1203
1205
|
|
|
1204
1206
|
processing_complete = asyncio.Event()
|
|
@@ -1262,3 +1264,139 @@ async def test_integrationTest_postRequestSent_webhookEventRawResultProcessedwit
|
|
|
1262
1264
|
mock_delete.assert_not_called()
|
|
1263
1265
|
|
|
1264
1266
|
await mock_context.app.webhook_manager.shutdown()
|
|
1267
|
+
|
|
1268
|
+
|
|
1269
|
+
@pytest.mark.asyncio
|
|
1270
|
+
@patch(
|
|
1271
|
+
"port_ocean.core.handlers.entities_state_applier.port.applier.HttpEntitiesStateApplier.upsert"
|
|
1272
|
+
)
|
|
1273
|
+
@patch(
|
|
1274
|
+
"port_ocean.core.handlers.entities_state_applier.port.applier.HttpEntitiesStateApplier.delete"
|
|
1275
|
+
)
|
|
1276
|
+
async def test_integrationTest_postRequestSent_oneProcessorThrowsException_onlySuccessfulResultsProcessed(
|
|
1277
|
+
mock_delete: AsyncMock,
|
|
1278
|
+
mock_upsert: AsyncMock,
|
|
1279
|
+
mock_context: PortOceanContext,
|
|
1280
|
+
mock_port_app_config: PortAppConfig,
|
|
1281
|
+
monkeypatch: pytest.MonkeyPatch,
|
|
1282
|
+
) -> None:
|
|
1283
|
+
"""Integration test for webhook processing where one processor throws an exception"""
|
|
1284
|
+
|
|
1285
|
+
monkeypatch.setattr(
|
|
1286
|
+
"port_ocean.core.integrations.mixins.handler.ocean", mock_context
|
|
1287
|
+
)
|
|
1288
|
+
monkeypatch.setattr(
|
|
1289
|
+
"port_ocean.core.integrations.mixins.live_events.ocean", mock_context
|
|
1290
|
+
)
|
|
1291
|
+
processed_events: list[WebhookEventRawResults] = []
|
|
1292
|
+
mock_upsert.return_value = [entity]
|
|
1293
|
+
|
|
1294
|
+
class SuccessfulProcessor(AbstractWebhookProcessor):
|
|
1295
|
+
async def authenticate(
|
|
1296
|
+
self, payload: Dict[str, Any], headers: Dict[str, str]
|
|
1297
|
+
) -> bool:
|
|
1298
|
+
return True
|
|
1299
|
+
|
|
1300
|
+
async def validate_payload(self, payload: Dict[str, Any]) -> bool:
|
|
1301
|
+
return True
|
|
1302
|
+
|
|
1303
|
+
async def handle_event(
|
|
1304
|
+
self, payload: EventPayload, resource: ResourceConfig
|
|
1305
|
+
) -> WebhookEventRawResults:
|
|
1306
|
+
event_data = WebhookEventRawResults(
|
|
1307
|
+
updated_raw_results=[
|
|
1308
|
+
{
|
|
1309
|
+
"name": "repo-one",
|
|
1310
|
+
"links": {"html": {"href": "https://example.com/repo-one"}},
|
|
1311
|
+
"main_branch": "main",
|
|
1312
|
+
}
|
|
1313
|
+
],
|
|
1314
|
+
deleted_raw_results=[],
|
|
1315
|
+
)
|
|
1316
|
+
processed_events.append(event_data)
|
|
1317
|
+
return event_data
|
|
1318
|
+
|
|
1319
|
+
async def should_process_event(self, event: WebhookEvent) -> bool:
|
|
1320
|
+
return True
|
|
1321
|
+
|
|
1322
|
+
async def get_matching_kinds(self, event: WebhookEvent) -> list[str]:
|
|
1323
|
+
return ["repository"]
|
|
1324
|
+
|
|
1325
|
+
class FailingProcessor(AbstractWebhookProcessor):
|
|
1326
|
+
async def authenticate(
|
|
1327
|
+
self, payload: Dict[str, Any], headers: Dict[str, str]
|
|
1328
|
+
) -> bool:
|
|
1329
|
+
return True
|
|
1330
|
+
|
|
1331
|
+
async def validate_payload(self, payload: Dict[str, Any]) -> bool:
|
|
1332
|
+
return True
|
|
1333
|
+
|
|
1334
|
+
async def handle_event(
|
|
1335
|
+
self, payload: EventPayload, resource: ResourceConfig
|
|
1336
|
+
) -> WebhookEventRawResults:
|
|
1337
|
+
raise ValueError("Simulated failure in processor")
|
|
1338
|
+
|
|
1339
|
+
async def should_process_event(self, event: WebhookEvent) -> bool:
|
|
1340
|
+
return True
|
|
1341
|
+
|
|
1342
|
+
async def get_matching_kinds(self, event: WebhookEvent) -> list[str]:
|
|
1343
|
+
return ["repository"]
|
|
1344
|
+
|
|
1345
|
+
processing_complete = asyncio.Event()
|
|
1346
|
+
original_process_data = LiveEventsMixin.sync_raw_results
|
|
1347
|
+
|
|
1348
|
+
async def patched_export_single_resource(
|
|
1349
|
+
self: LiveEventsMixin, webhookEventRawResults: list[WebhookEventRawResults]
|
|
1350
|
+
) -> None:
|
|
1351
|
+
try:
|
|
1352
|
+
await original_process_data(self, webhookEventRawResults)
|
|
1353
|
+
except Exception as e:
|
|
1354
|
+
raise e
|
|
1355
|
+
finally:
|
|
1356
|
+
processing_complete.set()
|
|
1357
|
+
|
|
1358
|
+
monkeypatch.setattr(
|
|
1359
|
+
LiveEventsMixin,
|
|
1360
|
+
"sync_raw_results",
|
|
1361
|
+
patched_export_single_resource,
|
|
1362
|
+
)
|
|
1363
|
+
test_path = "/webhook-test"
|
|
1364
|
+
mock_context.app.integration = BaseIntegration(ocean)
|
|
1365
|
+
mock_context.app.webhook_manager = LiveEventsProcessorManager(
|
|
1366
|
+
mock_context.app.integration_router, SignalHandler()
|
|
1367
|
+
)
|
|
1368
|
+
|
|
1369
|
+
# Register both processors
|
|
1370
|
+
mock_context.app.webhook_manager.register_processor(test_path, SuccessfulProcessor)
|
|
1371
|
+
mock_context.app.webhook_manager.register_processor(test_path, FailingProcessor)
|
|
1372
|
+
await mock_context.app.webhook_manager.start_processing_event_messages()
|
|
1373
|
+
mock_context.app.fast_api_app.include_router(
|
|
1374
|
+
mock_context.app.webhook_manager._router
|
|
1375
|
+
)
|
|
1376
|
+
client = TestClient(mock_context.app.fast_api_app)
|
|
1377
|
+
|
|
1378
|
+
test_payload = {"test": "data"}
|
|
1379
|
+
|
|
1380
|
+
async with event_context(EventType.HTTP_REQUEST, trigger_type="request") as event:
|
|
1381
|
+
mock_context.app.webhook_manager.port_app_config_handler.get_port_app_config = AsyncMock(return_value=mock_port_app_config) # type: ignore
|
|
1382
|
+
event.port_app_config = (
|
|
1383
|
+
await mock_context.app.webhook_manager.port_app_config_handler.get_port_app_config()
|
|
1384
|
+
)
|
|
1385
|
+
|
|
1386
|
+
response = client.post(
|
|
1387
|
+
test_path, json=test_payload, headers={"Content-Type": "application/json"}
|
|
1388
|
+
)
|
|
1389
|
+
|
|
1390
|
+
assert response.status_code == 200
|
|
1391
|
+
assert response.json() == {"status": "ok"}
|
|
1392
|
+
|
|
1393
|
+
try:
|
|
1394
|
+
await asyncio.wait_for(processing_complete.wait(), timeout=10.0)
|
|
1395
|
+
except asyncio.TimeoutError:
|
|
1396
|
+
pytest.fail("Event processing timed out")
|
|
1397
|
+
|
|
1398
|
+
assert len(processed_events) == 1
|
|
1399
|
+
assert mock_upsert.call_count == 1
|
|
1400
|
+
mock_delete.assert_not_called()
|
|
1401
|
+
|
|
1402
|
+
await mock_context.app.webhook_manager.shutdown()
|
|
@@ -103,8 +103,8 @@ port_ocean/core/handlers/queue/local_queue.py,sha256=EzqsGIX43xbVAcePwTcCg5QDrXA
|
|
|
103
103
|
port_ocean/core/handlers/resync_state_updater/__init__.py,sha256=kG6y-JQGpPfuTHh912L_bctIDCzAK4DN-d00S7rguWU,81
|
|
104
104
|
port_ocean/core/handlers/resync_state_updater/updater.py,sha256=Yg9ET6ZV5B9GW7u6zZA6GlB_71kmvxvYX2FWgQNzMvo,3182
|
|
105
105
|
port_ocean/core/handlers/webhook/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
106
|
-
port_ocean/core/handlers/webhook/abstract_webhook_processor.py,sha256=
|
|
107
|
-
port_ocean/core/handlers/webhook/processor_manager.py,sha256=
|
|
106
|
+
port_ocean/core/handlers/webhook/abstract_webhook_processor.py,sha256=5KwZkdkDd5HdVkXPzKiqabodZKl-hOtMypkTKd8Hq3M,3891
|
|
107
|
+
port_ocean/core/handlers/webhook/processor_manager.py,sha256=Pmg81IT0i3MCFWC6648Ln4NfpAWvpyrPZwOFfdTPkDE,11928
|
|
108
108
|
port_ocean/core/handlers/webhook/webhook_event.py,sha256=Iuw6IX3PPjwHECUeFgrJl6K249mJ-DPAGhP8OMxbc1c,4096
|
|
109
109
|
port_ocean/core/integrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
110
110
|
port_ocean/core/integrations/base.py,sha256=eS0WDOfCTim1UOQQrNuP14I6hvT_fr8dof_cr1ls01s,3107
|
|
@@ -156,8 +156,8 @@ port_ocean/tests/core/handlers/mixins/test_sync_raw.py,sha256=gxQ4e9hQuMS8-o5Ubi
|
|
|
156
156
|
port_ocean/tests/core/handlers/port_app_config/test_api.py,sha256=eJZ6SuFBLz71y4ca3DNqKag6d6HUjNJS0aqQPwiLMTI,1999
|
|
157
157
|
port_ocean/tests/core/handlers/port_app_config/test_base.py,sha256=tdjpFUnUZ6TNMxc3trKkzmMTGTb7oKIeu3rRXv_fV3g,6872
|
|
158
158
|
port_ocean/tests/core/handlers/queue/test_local_queue.py,sha256=9Ly0HzZXbs6Rbl_bstsIdInC3h2bgABU3roP9S_PnJM,2582
|
|
159
|
-
port_ocean/tests/core/handlers/webhook/test_abstract_webhook_processor.py,sha256=
|
|
160
|
-
port_ocean/tests/core/handlers/webhook/test_processor_manager.py,sha256=
|
|
159
|
+
port_ocean/tests/core/handlers/webhook/test_abstract_webhook_processor.py,sha256=zKwHhPAYEZoZ5Z2UETp1t--mbkS8uyvlXThB0obZTTc,3340
|
|
160
|
+
port_ocean/tests/core/handlers/webhook/test_processor_manager.py,sha256=Nb-3VXVRol9fM5pLZQ1iGyPsZcHkWSNGG3bDHWjuR3Y,49285
|
|
161
161
|
port_ocean/tests/core/handlers/webhook/test_webhook_event.py,sha256=oR4dEHLO65mp6rkfNfszZcfFoRZlB8ZWee4XetmsuIk,3181
|
|
162
162
|
port_ocean/tests/core/test_utils.py,sha256=Z3kdhb5V7Svhcyy3EansdTpgHL36TL6erNtU-OPwAcI,2647
|
|
163
163
|
port_ocean/tests/core/utils/test_entity_topological_sorter.py,sha256=zuq5WSPy_88PemG3mOUIHTxWMR_js1R7tOzUYlgBd68,3447
|
|
@@ -184,8 +184,8 @@ port_ocean/utils/repeat.py,sha256=U2OeCkHPWXmRTVoPV-VcJRlQhcYqPWI5NfmPlb1JIbc,32
|
|
|
184
184
|
port_ocean/utils/signal.py,sha256=mMVq-1Ab5YpNiqN4PkiyTGlV_G0wkUDMMjTZp5z3pb0,1514
|
|
185
185
|
port_ocean/utils/time.py,sha256=pufAOH5ZQI7gXvOvJoQXZXZJV-Dqktoj9Qp9eiRwmJ4,1939
|
|
186
186
|
port_ocean/version.py,sha256=UsuJdvdQlazzKGD3Hd5-U7N69STh8Dq9ggJzQFnu9fU,177
|
|
187
|
-
port_ocean-0.20.
|
|
188
|
-
port_ocean-0.20.
|
|
189
|
-
port_ocean-0.20.
|
|
190
|
-
port_ocean-0.20.
|
|
191
|
-
port_ocean-0.20.
|
|
187
|
+
port_ocean-0.20.4.dist-info/LICENSE.md,sha256=WNHhf_5RCaeuKWyq_K39vmp9F28LxKsB4SpomwSZ2L0,11357
|
|
188
|
+
port_ocean-0.20.4.dist-info/METADATA,sha256=TTDuej8wAckEOTu_3qM4GmnO0ReLwaN2SY7SSZ74pXw,6669
|
|
189
|
+
port_ocean-0.20.4.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
|
|
190
|
+
port_ocean-0.20.4.dist-info/entry_points.txt,sha256=F_DNUmGZU2Kme-8NsWM5LLE8piGMafYZygRYhOVtcjA,54
|
|
191
|
+
port_ocean-0.20.4.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|