port-ocean 0.22.9__py3-none-any.whl → 0.22.11__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/clients/port/mixins/integrations.py +45 -0
- port_ocean/core/handlers/entities_state_applier/port/applier.py +6 -2
- port_ocean/core/handlers/resync_state_updater/updater.py +7 -1
- port_ocean/core/integrations/mixins/sync_raw.py +11 -4
- port_ocean/helpers/metric/metric.py +74 -40
- port_ocean/helpers/metric/utils.py +0 -2
- port_ocean/ocean.py +11 -8
- port_ocean/tests/core/handlers/mixins/test_sync_raw.py +236 -10
- {port_ocean-0.22.9.dist-info → port_ocean-0.22.11.dist-info}/METADATA +1 -1
- {port_ocean-0.22.9.dist-info → port_ocean-0.22.11.dist-info}/RECORD +13 -13
- {port_ocean-0.22.9.dist-info → port_ocean-0.22.11.dist-info}/LICENSE.md +0 -0
- {port_ocean-0.22.9.dist-info → port_ocean-0.22.11.dist-info}/WHEEL +0 -0
- {port_ocean-0.22.9.dist-info → port_ocean-0.22.11.dist-info}/entry_points.txt +0 -0
|
@@ -25,6 +25,10 @@ class LogAttributes(TypedDict):
|
|
|
25
25
|
ingestUrl: str
|
|
26
26
|
|
|
27
27
|
|
|
28
|
+
class MetricsAttributes(TypedDict):
|
|
29
|
+
ingestUrl: str
|
|
30
|
+
|
|
31
|
+
|
|
28
32
|
class IntegrationClientMixin:
|
|
29
33
|
def __init__(
|
|
30
34
|
self,
|
|
@@ -38,6 +42,7 @@ class IntegrationClientMixin:
|
|
|
38
42
|
self.auth = auth
|
|
39
43
|
self.client = client
|
|
40
44
|
self._log_attributes: LogAttributes | None = None
|
|
45
|
+
self._metrics_attributes: MetricsAttributes | None = None
|
|
41
46
|
|
|
42
47
|
async def is_integration_provision_enabled(
|
|
43
48
|
self, integration_type: str, should_raise: bool = True, should_log: bool = True
|
|
@@ -106,6 +111,12 @@ class IntegrationClientMixin:
|
|
|
106
111
|
self._log_attributes = response["logAttributes"]
|
|
107
112
|
return self._log_attributes
|
|
108
113
|
|
|
114
|
+
async def get_metrics_attributes(self) -> LogAttributes:
|
|
115
|
+
if self._metrics_attributes is None:
|
|
116
|
+
response = await self.get_current_integration()
|
|
117
|
+
self._metrics_attributes = response["metricAttributes"]
|
|
118
|
+
return self._metrics_attributes
|
|
119
|
+
|
|
109
120
|
async def _poll_integration_until_default_provisioning_is_complete(
|
|
110
121
|
self,
|
|
111
122
|
) -> Dict[str, Any]:
|
|
@@ -197,6 +208,40 @@ class IntegrationClientMixin:
|
|
|
197
208
|
handle_port_status_code(response)
|
|
198
209
|
return response.json()["integration"]
|
|
199
210
|
|
|
211
|
+
async def post_integration_sync_metrics(
|
|
212
|
+
self, metrics: list[dict[str, Any]]
|
|
213
|
+
) -> None:
|
|
214
|
+
logger.debug("starting POST metrics request", metrics=metrics)
|
|
215
|
+
metrics_attributes = await self.get_metrics_attributes()
|
|
216
|
+
headers = await self.auth.headers()
|
|
217
|
+
response = await self.client.post(
|
|
218
|
+
metrics_attributes["ingestUrl"],
|
|
219
|
+
headers=headers,
|
|
220
|
+
json={
|
|
221
|
+
"syncKindsMetrics": metrics,
|
|
222
|
+
},
|
|
223
|
+
)
|
|
224
|
+
handle_port_status_code(response, should_log=False)
|
|
225
|
+
logger.debug("Finished POST metrics request")
|
|
226
|
+
|
|
227
|
+
async def put_integration_sync_metrics(self, kind_metrics: dict[str, Any]) -> None:
|
|
228
|
+
logger.debug("starting PUT metrics request", kind_metrics=kind_metrics)
|
|
229
|
+
metrics_attributes = await self.get_metrics_attributes()
|
|
230
|
+
url = (
|
|
231
|
+
metrics_attributes["ingestUrl"]
|
|
232
|
+
+ f"/resync/{kind_metrics['eventId']}/kind/{kind_metrics['kindIdentifier']}"
|
|
233
|
+
)
|
|
234
|
+
headers = await self.auth.headers()
|
|
235
|
+
response = await self.client.put(
|
|
236
|
+
url,
|
|
237
|
+
headers=headers,
|
|
238
|
+
json={
|
|
239
|
+
"syncKindMetrics": kind_metrics,
|
|
240
|
+
},
|
|
241
|
+
)
|
|
242
|
+
handle_port_status_code(response, should_log=False)
|
|
243
|
+
logger.debug("Finished PUT metrics request")
|
|
244
|
+
|
|
200
245
|
async def ingest_integration_logs(self, logs: list[dict[str, Any]]) -> None:
|
|
201
246
|
logger.debug("Ingesting logs")
|
|
202
247
|
log_attributes = await self.get_log_attributes()
|
|
@@ -104,8 +104,12 @@ class HttpEntitiesStateApplier(BaseEntitiesStateApplier):
|
|
|
104
104
|
):
|
|
105
105
|
await self._safe_delete(diff.deleted, kept_entities, user_agent_type)
|
|
106
106
|
ocean.metrics.inc_metric(
|
|
107
|
-
name=MetricType.
|
|
108
|
-
labels=[
|
|
107
|
+
name=MetricType.OBJECT_COUNT_NAME,
|
|
108
|
+
labels=[
|
|
109
|
+
ocean.metrics.current_resource_kind(),
|
|
110
|
+
MetricPhase.DELETE,
|
|
111
|
+
MetricPhase.DeletionResult.DELETED,
|
|
112
|
+
],
|
|
109
113
|
value=len(diff.deleted),
|
|
110
114
|
)
|
|
111
115
|
else:
|
|
@@ -90,4 +90,10 @@ class ResyncStateUpdater:
|
|
|
90
90
|
labels=[ocean.metrics.current_resource_kind(), MetricPhase.RESYNC],
|
|
91
91
|
value=int(status == IntegrationStateStatus.Completed),
|
|
92
92
|
)
|
|
93
|
-
|
|
93
|
+
|
|
94
|
+
await ocean.metrics.send_metrics_to_webhook(
|
|
95
|
+
kind=ocean.metrics.current_resource_kind()
|
|
96
|
+
)
|
|
97
|
+
# await ocean.metrics.report_sync_metrics(
|
|
98
|
+
# kinds=[ocean.metrics.current_resource_kind()]
|
|
99
|
+
# ) # TODO: uncomment this when end points are ready
|
|
@@ -614,8 +614,10 @@ class SyncRawMixin(HandlerMixin, EventsMixin):
|
|
|
614
614
|
use_cache=False
|
|
615
615
|
)
|
|
616
616
|
logger.info(f"Resync will use the following mappings: {app_config.dict()}")
|
|
617
|
-
|
|
618
|
-
|
|
617
|
+
|
|
618
|
+
kinds = [f"{resource.kind}-{index}" for index, resource in enumerate(app_config.resources)]
|
|
619
|
+
ocean.metrics.initialize_metrics(kinds)
|
|
620
|
+
# await ocean.metrics.report_sync_metrics(kinds=kinds) # TODO: uncomment this when end points are ready
|
|
619
621
|
|
|
620
622
|
# Execute resync_start hooks
|
|
621
623
|
for resync_start_fn in self.event_strategy["resync_start"]:
|
|
@@ -643,7 +645,7 @@ class SyncRawMixin(HandlerMixin, EventsMixin):
|
|
|
643
645
|
async with resource_context(resource,index):
|
|
644
646
|
resource_kind_id = f"{resource.kind}-{index}"
|
|
645
647
|
ocean.metrics.sync_state = SyncState.SYNCING
|
|
646
|
-
await ocean.metrics.
|
|
648
|
+
# await ocean.metrics.report_kind_sync_metrics(kind=resource_kind_id) # TODO: uncomment this when end points are ready
|
|
647
649
|
|
|
648
650
|
task = asyncio.create_task(
|
|
649
651
|
self._register_in_batches(resource, user_agent_type)
|
|
@@ -653,9 +655,14 @@ class SyncRawMixin(HandlerMixin, EventsMixin):
|
|
|
653
655
|
kind_results: tuple[list[Entity], list[Exception]] = await task
|
|
654
656
|
|
|
655
657
|
creation_results.append(kind_results)
|
|
658
|
+
|
|
656
659
|
if ocean.metrics.sync_state != SyncState.FAILED:
|
|
657
660
|
ocean.metrics.sync_state = SyncState.COMPLETED
|
|
658
|
-
|
|
661
|
+
|
|
662
|
+
await ocean.metrics.send_metrics_to_webhook(
|
|
663
|
+
kind=resource_kind_id
|
|
664
|
+
)
|
|
665
|
+
# await ocean.metrics.report_kind_sync_metrics(kind=resource_kind_id) # TODO: uncomment this when end points are ready
|
|
659
666
|
|
|
660
667
|
await self.sort_and_upsert_failed_entities(user_agent_type)
|
|
661
668
|
|
|
@@ -13,6 +13,7 @@ import prometheus_client.parser
|
|
|
13
13
|
|
|
14
14
|
if TYPE_CHECKING:
|
|
15
15
|
from port_ocean.config.settings import MetricsSettings, IntegrationSettings
|
|
16
|
+
from port_ocean.clients.port.client import PortClient
|
|
16
17
|
|
|
17
18
|
|
|
18
19
|
class MetricPhase:
|
|
@@ -35,21 +36,22 @@ class MetricPhase:
|
|
|
35
36
|
class ExtractResult:
|
|
36
37
|
EXTRACTED = "raw_extracted"
|
|
37
38
|
|
|
39
|
+
class DeletionResult:
|
|
40
|
+
DELETED = "deleted"
|
|
41
|
+
|
|
38
42
|
|
|
39
43
|
class MetricType:
|
|
40
44
|
# Define metric names as constants
|
|
41
45
|
DURATION_NAME = "duration_seconds"
|
|
42
46
|
OBJECT_COUNT_NAME = "object_count"
|
|
43
|
-
ERROR_COUNT_NAME = "error_count"
|
|
44
47
|
SUCCESS_NAME = "success"
|
|
45
48
|
RATE_LIMIT_WAIT_NAME = "rate_limit_wait_seconds"
|
|
46
|
-
DELETION_COUNT_NAME = "deletion_count"
|
|
47
49
|
|
|
48
50
|
|
|
49
51
|
class SyncState:
|
|
50
52
|
SYNCING = "syncing"
|
|
51
53
|
COMPLETED = "completed"
|
|
52
|
-
|
|
54
|
+
PENDING = "pending"
|
|
53
55
|
FAILED = "failed"
|
|
54
56
|
|
|
55
57
|
|
|
@@ -65,11 +67,6 @@ _metrics_registry: Dict[str, Tuple[str, str, List[str]]] = {
|
|
|
65
67
|
"object_count description",
|
|
66
68
|
["kind", "phase", "object_count_type"],
|
|
67
69
|
),
|
|
68
|
-
MetricType.ERROR_COUNT_NAME: (
|
|
69
|
-
MetricType.ERROR_COUNT_NAME,
|
|
70
|
-
"error_count description",
|
|
71
|
-
["kind", "phase"],
|
|
72
|
-
),
|
|
73
70
|
MetricType.SUCCESS_NAME: (
|
|
74
71
|
MetricType.SUCCESS_NAME,
|
|
75
72
|
"success description",
|
|
@@ -80,11 +77,6 @@ _metrics_registry: Dict[str, Tuple[str, str, List[str]]] = {
|
|
|
80
77
|
"rate_limit_wait description",
|
|
81
78
|
["kind", "phase", "endpoint"],
|
|
82
79
|
),
|
|
83
|
-
MetricType.DELETION_COUNT_NAME: (
|
|
84
|
-
MetricType.DELETION_COUNT_NAME,
|
|
85
|
-
"deletion_count description",
|
|
86
|
-
["kind", "phase"],
|
|
87
|
-
),
|
|
88
80
|
}
|
|
89
81
|
|
|
90
82
|
|
|
@@ -115,16 +107,18 @@ class Metrics:
|
|
|
115
107
|
self,
|
|
116
108
|
metrics_settings: "MetricsSettings",
|
|
117
109
|
integration_configuration: "IntegrationSettings",
|
|
110
|
+
port_client: "PortClient",
|
|
118
111
|
) -> None:
|
|
119
112
|
self.metrics_settings = metrics_settings
|
|
120
113
|
self.integration_configuration = integration_configuration
|
|
114
|
+
self.port_client = port_client
|
|
121
115
|
self.registry = prometheus_client.CollectorRegistry()
|
|
122
116
|
self.metrics: dict[str, Gauge] = {}
|
|
123
117
|
self.load_metrics()
|
|
124
118
|
self._integration_version: Optional[str] = None
|
|
125
119
|
self._ocean_version: Optional[str] = None
|
|
126
120
|
self.event_id = ""
|
|
127
|
-
self.sync_state = SyncState.
|
|
121
|
+
self.sync_state = SyncState.PENDING
|
|
128
122
|
|
|
129
123
|
@property
|
|
130
124
|
def event_id(self) -> str:
|
|
@@ -163,9 +157,6 @@ class Metrics:
|
|
|
163
157
|
return self.metrics_settings.enabled
|
|
164
158
|
|
|
165
159
|
def load_metrics(self) -> None:
|
|
166
|
-
if not self.enabled:
|
|
167
|
-
return None
|
|
168
|
-
|
|
169
160
|
# Load all registered metrics
|
|
170
161
|
for name, (_, description, labels) in _metrics_registry.items():
|
|
171
162
|
self.metrics[name] = Gauge(
|
|
@@ -173,8 +164,6 @@ class Metrics:
|
|
|
173
164
|
)
|
|
174
165
|
|
|
175
166
|
def get_metric(self, name: str, labels: list[str]) -> Gauge | EmptyMetric:
|
|
176
|
-
if not self.enabled:
|
|
177
|
-
return EmptyMetric()
|
|
178
167
|
metrics = self.metrics.get(name)
|
|
179
168
|
if not metrics:
|
|
180
169
|
return EmptyMetric()
|
|
@@ -188,9 +177,6 @@ class Metrics:
|
|
|
188
177
|
labels (list[str]): The labels to apply to the metric.
|
|
189
178
|
value (float): The value to inc.
|
|
190
179
|
"""
|
|
191
|
-
if not self.enabled:
|
|
192
|
-
return None
|
|
193
|
-
|
|
194
180
|
self.get_metric(name, labels).inc(value)
|
|
195
181
|
|
|
196
182
|
def set_metric(self, name: str, labels: list[str], value: float) -> None:
|
|
@@ -201,9 +187,6 @@ class Metrics:
|
|
|
201
187
|
labels (list[str]): The labels to apply to the metric.
|
|
202
188
|
value (float): The value to set.
|
|
203
189
|
"""
|
|
204
|
-
if not self.enabled:
|
|
205
|
-
return None
|
|
206
|
-
|
|
207
190
|
self.get_metric(name, labels).set(value)
|
|
208
191
|
|
|
209
192
|
def initialize_metrics(self, kind_blockes: list[str]) -> None:
|
|
@@ -271,15 +254,39 @@ class Metrics:
|
|
|
271
254
|
self.registry
|
|
272
255
|
).decode()
|
|
273
256
|
|
|
274
|
-
async def
|
|
275
|
-
self, metric_name: Optional[str] = None,
|
|
257
|
+
async def report_sync_metrics(
|
|
258
|
+
self, metric_name: Optional[str] = None, kinds: Optional[list[str]] = None
|
|
276
259
|
) -> None:
|
|
277
|
-
if
|
|
260
|
+
if kinds is None:
|
|
278
261
|
return None
|
|
279
262
|
|
|
280
|
-
|
|
263
|
+
metrics = []
|
|
264
|
+
|
|
265
|
+
for kind in kinds:
|
|
266
|
+
metric = self.generate_metrics(metric_name, kind)
|
|
267
|
+
metrics.extend(metric)
|
|
268
|
+
|
|
269
|
+
try:
|
|
270
|
+
await self.port_client.post_integration_sync_metrics(metrics)
|
|
271
|
+
except Exception as e:
|
|
272
|
+
logger.error(f"Error posting metrics: {e}", metrics=metrics)
|
|
273
|
+
|
|
274
|
+
async def report_kind_sync_metrics(
|
|
275
|
+
self, metric_name: Optional[str] = None, kind: Optional[str] = None
|
|
276
|
+
) -> None:
|
|
277
|
+
metrics = self.generate_metrics(metric_name, kind)
|
|
278
|
+
if not metrics:
|
|
281
279
|
return None
|
|
282
280
|
|
|
281
|
+
try:
|
|
282
|
+
for metric in metrics:
|
|
283
|
+
await self.port_client.put_integration_sync_metrics(metric)
|
|
284
|
+
except Exception as e:
|
|
285
|
+
logger.error(f"Error putting metrics: {e}", metrics=metrics)
|
|
286
|
+
|
|
287
|
+
def generate_metrics(
|
|
288
|
+
self, metric_name: Optional[str] = None, kind: Optional[str] = None
|
|
289
|
+
) -> list[dict[str, Any]]:
|
|
283
290
|
try:
|
|
284
291
|
latest_raw = self.generate_latest()
|
|
285
292
|
metric_families = prometheus_client.parser.text_string_to_metric_families(
|
|
@@ -318,27 +325,54 @@ class Metrics:
|
|
|
318
325
|
|
|
319
326
|
# If no metrics were filtered, exit early
|
|
320
327
|
if not metrics_dict.get("kind", {}):
|
|
321
|
-
return
|
|
328
|
+
return []
|
|
322
329
|
|
|
330
|
+
events = []
|
|
323
331
|
for kind_key, metrics in metrics_dict.get("kind", {}).items():
|
|
324
332
|
# Skip if we're filtering by kind and this isn't the requested kind
|
|
325
333
|
if kind and kind_key != kind:
|
|
326
334
|
continue
|
|
327
335
|
|
|
328
336
|
event = {
|
|
329
|
-
"
|
|
330
|
-
"
|
|
331
|
-
"
|
|
332
|
-
"
|
|
333
|
-
"
|
|
334
|
-
"kind":
|
|
335
|
-
|
|
336
|
-
|
|
337
|
+
"integrationType": self.integration_configuration.type,
|
|
338
|
+
"integrationIdentifier": self.integration_configuration.identifier,
|
|
339
|
+
"integrationVersion": self.integration_version,
|
|
340
|
+
"oceanVersion": self.ocean_version,
|
|
341
|
+
"kindIdentifier": kind_key,
|
|
342
|
+
"kind": (
|
|
343
|
+
"-".join(kind_key.split("-")[:-1])
|
|
344
|
+
if "-" in kind_key
|
|
345
|
+
else kind_key
|
|
346
|
+
),
|
|
347
|
+
"kindIndex": 0 if kind_key == "__runtime__" else int(kind_key[-1]),
|
|
348
|
+
"eventId": self.event_id,
|
|
349
|
+
"syncState": self.sync_state,
|
|
337
350
|
"metrics": metrics,
|
|
338
351
|
}
|
|
339
|
-
|
|
352
|
+
events.append(event)
|
|
353
|
+
return events
|
|
354
|
+
except Exception as e:
|
|
355
|
+
logger.error(f"Error sending metrics to webhook: {e}")
|
|
356
|
+
return []
|
|
357
|
+
|
|
358
|
+
async def send_metrics_to_webhook(
|
|
359
|
+
self, metric_name: Optional[str] = None, kind: Optional[str] = None
|
|
360
|
+
) -> None:
|
|
361
|
+
try:
|
|
362
|
+
if not self.enabled:
|
|
363
|
+
return None
|
|
364
|
+
|
|
365
|
+
if not self.metrics_settings.webhook_url:
|
|
366
|
+
return None
|
|
367
|
+
|
|
368
|
+
metrics = self.generate_metrics(metric_name, kind)
|
|
369
|
+
if not metrics:
|
|
370
|
+
return None
|
|
371
|
+
|
|
372
|
+
for metric in metrics:
|
|
373
|
+
logger.info(f"Sending metrics to webhook {metric['kind']}: {metric}")
|
|
340
374
|
await AsyncClient().post(
|
|
341
|
-
url=self.metrics_settings.webhook_url, json=
|
|
375
|
+
url=self.metrics_settings.webhook_url, json=metric
|
|
342
376
|
)
|
|
343
377
|
except Exception as e:
|
|
344
378
|
logger.error(f"Error sending metrics to webhook: {e}")
|
|
@@ -11,8 +11,6 @@ def TimeMetric(phase: str) -> Any:
|
|
|
11
11
|
|
|
12
12
|
@wraps(func)
|
|
13
13
|
async def wrapper(*args: Any, **kwargs: dict[Any, Any]) -> Any:
|
|
14
|
-
if not ocean.metrics.enabled:
|
|
15
|
-
return await func(*args, **kwargs)
|
|
16
14
|
start = time.monotonic()
|
|
17
15
|
res = await func(*args, **kwargs)
|
|
18
16
|
end = time.monotonic()
|
port_ocean/ocean.py
CHANGED
|
@@ -57,9 +57,20 @@ class Ocean:
|
|
|
57
57
|
*self.config.get_sensitive_fields_data()
|
|
58
58
|
)
|
|
59
59
|
self.integration_router = integration_router or APIRouter()
|
|
60
|
+
|
|
61
|
+
self.port_client = PortClient(
|
|
62
|
+
base_url=self.config.port.base_url,
|
|
63
|
+
client_id=self.config.port.client_id,
|
|
64
|
+
client_secret=self.config.port.client_secret,
|
|
65
|
+
integration_identifier=self.config.integration.identifier,
|
|
66
|
+
integration_type=self.config.integration.type,
|
|
67
|
+
integration_version=__integration_version__,
|
|
68
|
+
)
|
|
69
|
+
|
|
60
70
|
self.metrics = port_ocean.helpers.metric.metric.Metrics(
|
|
61
71
|
metrics_settings=self.config.metrics,
|
|
62
72
|
integration_configuration=self.config.integration,
|
|
73
|
+
port_client=self.port_client,
|
|
63
74
|
)
|
|
64
75
|
|
|
65
76
|
self.webhook_manager = LiveEventsProcessorManager(
|
|
@@ -69,14 +80,6 @@ class Ocean:
|
|
|
69
80
|
max_wait_seconds_before_shutdown=self.config.max_wait_seconds_before_shutdown,
|
|
70
81
|
)
|
|
71
82
|
|
|
72
|
-
self.port_client = PortClient(
|
|
73
|
-
base_url=self.config.port.base_url,
|
|
74
|
-
client_id=self.config.port.client_id,
|
|
75
|
-
client_secret=self.config.port.client_secret,
|
|
76
|
-
integration_identifier=self.config.integration.identifier,
|
|
77
|
-
integration_type=self.config.integration.type,
|
|
78
|
-
integration_version=__integration_version__,
|
|
79
|
-
)
|
|
80
83
|
self.integration = (
|
|
81
84
|
integration_class(ocean) if integration_class else BaseIntegration(ocean)
|
|
82
85
|
)
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
from graphlib import CycleError
|
|
2
|
-
from typing import Any
|
|
2
|
+
from typing import Any, AsyncGenerator
|
|
3
3
|
|
|
4
|
+
from port_ocean.clients.port.client import PortClient
|
|
4
5
|
from port_ocean.core.utils.entity_topological_sorter import EntityTopologicalSorter
|
|
5
6
|
from port_ocean.exceptions.core import OceanAbortException
|
|
6
7
|
import pytest
|
|
@@ -24,6 +25,8 @@ from port_ocean.clients.port.types import UserAgentType
|
|
|
24
25
|
from dataclasses import dataclass
|
|
25
26
|
from typing import List, Optional
|
|
26
27
|
from port_ocean.tests.core.conftest import create_entity, no_op_event_context
|
|
28
|
+
from port_ocean.helpers.metric.metric import Metrics
|
|
29
|
+
from port_ocean.config.settings import MetricsSettings, IntegrationSettings
|
|
27
30
|
|
|
28
31
|
|
|
29
32
|
@pytest.fixture
|
|
@@ -36,7 +39,47 @@ def mock_sync_raw_mixin(
|
|
|
36
39
|
sync_raw_mixin._entity_processor = mock_entity_processor
|
|
37
40
|
sync_raw_mixin._entities_state_applier = mock_entities_state_applier
|
|
38
41
|
sync_raw_mixin._port_app_config_handler = mock_port_app_config_handler
|
|
39
|
-
|
|
42
|
+
|
|
43
|
+
# Create raw data that matches the entity structure
|
|
44
|
+
raw_data = [
|
|
45
|
+
{
|
|
46
|
+
"id": "entity_1",
|
|
47
|
+
"name": "Entity 1",
|
|
48
|
+
"service": "entity_3",
|
|
49
|
+
"web_url": "https://example.com/entity1",
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
"id": "entity_2",
|
|
53
|
+
"name": "Entity 2",
|
|
54
|
+
"service": "entity_4",
|
|
55
|
+
"web_url": "https://example.com/entity2",
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
"id": "entity_3",
|
|
59
|
+
"name": "Entity 3",
|
|
60
|
+
"service": "",
|
|
61
|
+
"web_url": "https://example.com/entity3",
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
"id": "entity_4",
|
|
65
|
+
"name": "Entity 4",
|
|
66
|
+
"service": "entity_3",
|
|
67
|
+
"web_url": "https://example.com/entity4",
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
"id": "entity_5",
|
|
71
|
+
"name": "Entity 5",
|
|
72
|
+
"service": "entity_1",
|
|
73
|
+
"web_url": "https://example.com/entity5",
|
|
74
|
+
},
|
|
75
|
+
]
|
|
76
|
+
|
|
77
|
+
# Create an async generator that yields the raw data
|
|
78
|
+
async def raw_results_generator() -> AsyncGenerator[list[dict[str, Any]], None]:
|
|
79
|
+
yield raw_data
|
|
80
|
+
|
|
81
|
+
# Return a list containing the async generator and an empty error list
|
|
82
|
+
sync_raw_mixin._get_resource_raw_results = AsyncMock(return_value=([raw_results_generator()], [])) # type: ignore
|
|
40
83
|
sync_raw_mixin._entity_processor.parse_items = AsyncMock(return_value=MagicMock()) # type: ignore
|
|
41
84
|
|
|
42
85
|
return sync_raw_mixin
|
|
@@ -51,9 +94,33 @@ def mock_sync_raw_mixin_with_jq_processor(
|
|
|
51
94
|
return mock_sync_raw_mixin
|
|
52
95
|
|
|
53
96
|
|
|
97
|
+
@pytest.fixture
|
|
98
|
+
def mock_ocean(mock_port_client: PortClient) -> Ocean:
|
|
99
|
+
with patch("port_ocean.ocean.Ocean.__init__", return_value=None):
|
|
100
|
+
ocean_mock = Ocean(
|
|
101
|
+
MagicMock(), MagicMock(), MagicMock(), MagicMock(), MagicMock()
|
|
102
|
+
)
|
|
103
|
+
ocean_mock.config = MagicMock()
|
|
104
|
+
ocean_mock.config.port = MagicMock()
|
|
105
|
+
ocean_mock.config.port.port_app_config_cache_ttl = 60
|
|
106
|
+
ocean_mock.port_client = mock_port_client
|
|
107
|
+
|
|
108
|
+
# Create real metrics instance
|
|
109
|
+
metrics_settings = MetricsSettings(enabled=True)
|
|
110
|
+
integration_settings = IntegrationSettings(type="test", identifier="test")
|
|
111
|
+
ocean_mock.metrics = Metrics(
|
|
112
|
+
metrics_settings=metrics_settings,
|
|
113
|
+
integration_configuration=integration_settings,
|
|
114
|
+
port_client=mock_port_client,
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
return ocean_mock
|
|
118
|
+
|
|
119
|
+
|
|
54
120
|
@pytest.mark.asyncio
|
|
55
121
|
async def test_sync_raw_mixin_self_dependency(
|
|
56
122
|
mock_sync_raw_mixin: SyncRawMixin,
|
|
123
|
+
mock_ocean: Ocean,
|
|
57
124
|
) -> None:
|
|
58
125
|
entities_params = [
|
|
59
126
|
("entity_1", "service", {"service": "entity_1"}, True),
|
|
@@ -62,8 +129,14 @@ async def test_sync_raw_mixin_self_dependency(
|
|
|
62
129
|
entities = [create_entity(*entity_param) for entity_param in entities_params]
|
|
63
130
|
|
|
64
131
|
calc_result_mock = MagicMock()
|
|
65
|
-
calc_result_mock.entity_selector_diff
|
|
66
|
-
|
|
132
|
+
calc_result_mock.entity_selector_diff = EntitySelectorDiff(
|
|
133
|
+
passed=entities, failed=[] # No failed entities in this test case
|
|
134
|
+
)
|
|
135
|
+
calc_result_mock.errors = [] # No errors in this test case
|
|
136
|
+
calc_result_mock.number_of_transformed_entities = len(
|
|
137
|
+
entities
|
|
138
|
+
) # Add this to match real behavior
|
|
139
|
+
calc_result_mock.misonfigured_entity_keys = {} # Add this to match real behavior
|
|
67
140
|
|
|
68
141
|
mock_sync_raw_mixin.entity_processor.parse_items = AsyncMock(return_value=calc_result_mock) # type: ignore
|
|
69
142
|
|
|
@@ -105,6 +178,50 @@ async def test_sync_raw_mixin_self_dependency(
|
|
|
105
178
|
for call in mock_order_by_entities_dependencies.call_args_list
|
|
106
179
|
] == [entity for entity in entities if entity.identifier == "entity_1"]
|
|
107
180
|
|
|
181
|
+
# Add assertions for actual metrics
|
|
182
|
+
metrics = mock_ocean.metrics.generate_metrics()
|
|
183
|
+
assert len(metrics) == 2
|
|
184
|
+
|
|
185
|
+
# Verify object counts
|
|
186
|
+
for metric in metrics:
|
|
187
|
+
if metric["kind"] == "project":
|
|
188
|
+
assert (
|
|
189
|
+
metric["metrics"]["phase"]["extract"]["object_count_type"][
|
|
190
|
+
"raw_extracted"
|
|
191
|
+
]["object_count"]
|
|
192
|
+
== 5
|
|
193
|
+
)
|
|
194
|
+
assert (
|
|
195
|
+
metric["metrics"]["phase"]["transform"][
|
|
196
|
+
"object_count_type"
|
|
197
|
+
]["transformed"]["object_count"]
|
|
198
|
+
== 2
|
|
199
|
+
)
|
|
200
|
+
assert (
|
|
201
|
+
metric["metrics"]["phase"]["transform"][
|
|
202
|
+
"object_count_type"
|
|
203
|
+
]["filtered_out"]["object_count"]
|
|
204
|
+
== 3
|
|
205
|
+
)
|
|
206
|
+
assert (
|
|
207
|
+
metric["metrics"]["phase"]["load"]["object_count_type"][
|
|
208
|
+
"failed"
|
|
209
|
+
]["object_count"]
|
|
210
|
+
== 1
|
|
211
|
+
)
|
|
212
|
+
assert (
|
|
213
|
+
metric["metrics"]["phase"]["load"]["object_count_type"][
|
|
214
|
+
"loaded"
|
|
215
|
+
]["object_count"]
|
|
216
|
+
== 1
|
|
217
|
+
)
|
|
218
|
+
|
|
219
|
+
# Verify success
|
|
220
|
+
assert metric["metrics"]["phase"]["resync"]["success"] == 1
|
|
221
|
+
|
|
222
|
+
# Verify sync state
|
|
223
|
+
assert metric["syncState"] == "completed"
|
|
224
|
+
|
|
108
225
|
|
|
109
226
|
@pytest.mark.asyncio
|
|
110
227
|
async def test_sync_raw_mixin_circular_dependency(
|
|
@@ -117,8 +234,14 @@ async def test_sync_raw_mixin_circular_dependency(
|
|
|
117
234
|
entities = [create_entity(*entity_param) for entity_param in entities_params]
|
|
118
235
|
|
|
119
236
|
calc_result_mock = MagicMock()
|
|
120
|
-
calc_result_mock.entity_selector_diff
|
|
121
|
-
|
|
237
|
+
calc_result_mock.entity_selector_diff = EntitySelectorDiff(
|
|
238
|
+
passed=entities, failed=[] # No failed entities in this test case
|
|
239
|
+
)
|
|
240
|
+
calc_result_mock.errors = [] # No errors in this test case
|
|
241
|
+
calc_result_mock.number_of_transformed_entities = len(
|
|
242
|
+
entities
|
|
243
|
+
) # Add this to match real behavior
|
|
244
|
+
calc_result_mock.misonfigured_entity_keys = {} # Add this to match real behavior
|
|
122
245
|
|
|
123
246
|
mock_sync_raw_mixin.entity_processor.parse_items = AsyncMock(return_value=calc_result_mock) # type: ignore
|
|
124
247
|
|
|
@@ -183,11 +306,56 @@ async def test_sync_raw_mixin_circular_dependency(
|
|
|
183
306
|
== 2
|
|
184
307
|
)
|
|
185
308
|
|
|
309
|
+
# Add assertions for actual metrics
|
|
310
|
+
metrics = mock_ocean.metrics.generate_metrics()
|
|
311
|
+
assert len(metrics) == 2
|
|
312
|
+
|
|
313
|
+
# Verify object counts
|
|
314
|
+
for metric in metrics:
|
|
315
|
+
if metric["kind"] == "project":
|
|
316
|
+
assert (
|
|
317
|
+
metric["metrics"]["phase"]["extract"]["object_count_type"][
|
|
318
|
+
"raw_extracted"
|
|
319
|
+
]["object_count"]
|
|
320
|
+
== 5
|
|
321
|
+
)
|
|
322
|
+
assert (
|
|
323
|
+
metric["metrics"]["phase"]["transform"][
|
|
324
|
+
"object_count_type"
|
|
325
|
+
]["transformed"]["object_count"]
|
|
326
|
+
== 2
|
|
327
|
+
)
|
|
328
|
+
assert (
|
|
329
|
+
metric["metrics"]["phase"]["transform"][
|
|
330
|
+
"object_count_type"
|
|
331
|
+
]["filtered_out"]["object_count"]
|
|
332
|
+
== 3
|
|
333
|
+
)
|
|
334
|
+
assert (
|
|
335
|
+
metric["metrics"]["phase"]["load"]["object_count_type"][
|
|
336
|
+
"failed"
|
|
337
|
+
]["object_count"]
|
|
338
|
+
== 2
|
|
339
|
+
)
|
|
340
|
+
assert (
|
|
341
|
+
metric["metrics"]["phase"]["load"]["object_count_type"][
|
|
342
|
+
"loaded"
|
|
343
|
+
]["object_count"]
|
|
344
|
+
== 0
|
|
345
|
+
)
|
|
346
|
+
|
|
347
|
+
# Verify success
|
|
348
|
+
assert metric["metrics"]["phase"]["resync"]["success"] == 1
|
|
349
|
+
|
|
350
|
+
# Verify sync state
|
|
351
|
+
assert metric["syncState"] == "completed"
|
|
352
|
+
|
|
186
353
|
|
|
187
354
|
@pytest.mark.asyncio
|
|
188
355
|
async def test_sync_raw_mixin_dependency(
|
|
189
356
|
mock_sync_raw_mixin: SyncRawMixin, mock_ocean: Ocean
|
|
190
357
|
) -> None:
|
|
358
|
+
# Create entities with more realistic data
|
|
191
359
|
entities_params = [
|
|
192
360
|
("entity_1", "service", {"service": "entity_3"}, True),
|
|
193
361
|
("entity_2", "service", {"service": "entity_4"}, True),
|
|
@@ -197,10 +365,18 @@ async def test_sync_raw_mixin_dependency(
|
|
|
197
365
|
]
|
|
198
366
|
entities = [create_entity(*entity_param) for entity_param in entities_params]
|
|
199
367
|
|
|
368
|
+
# Create a more realistic CalculationResult mock
|
|
200
369
|
calc_result_mock = MagicMock()
|
|
201
|
-
calc_result_mock.entity_selector_diff
|
|
202
|
-
|
|
370
|
+
calc_result_mock.entity_selector_diff = EntitySelectorDiff(
|
|
371
|
+
passed=entities, failed=[] # No failed entities in this test case
|
|
372
|
+
)
|
|
373
|
+
calc_result_mock.errors = [] # No errors in this test case
|
|
374
|
+
calc_result_mock.number_of_transformed_entities = len(
|
|
375
|
+
entities
|
|
376
|
+
) # Add this to match real behavior
|
|
377
|
+
calc_result_mock.misonfigured_entity_keys = {} # Add this to match real behavior
|
|
203
378
|
|
|
379
|
+
# Mock the parse_items method to return our realistic mock
|
|
204
380
|
mock_sync_raw_mixin.entity_processor.parse_items = AsyncMock(return_value=calc_result_mock) # type: ignore
|
|
205
381
|
|
|
206
382
|
mock_order_by_entities_dependencies = MagicMock(
|
|
@@ -270,6 +446,44 @@ async def test_sync_raw_mixin_dependency(
|
|
|
270
446
|
"entity_3-entity_1-entity_4-entity_5-entity_2",
|
|
271
447
|
)
|
|
272
448
|
|
|
449
|
+
# Add assertions for actual metrics
|
|
450
|
+
metrics = mock_ocean.metrics.generate_metrics()
|
|
451
|
+
assert len(metrics) == 2
|
|
452
|
+
|
|
453
|
+
# Verify object counts
|
|
454
|
+
for metric in metrics:
|
|
455
|
+
if metric["kind"] == "project":
|
|
456
|
+
assert (
|
|
457
|
+
metric["metrics"]["phase"]["extract"]["object_count_type"][
|
|
458
|
+
"raw_extracted"
|
|
459
|
+
]["object_count"]
|
|
460
|
+
== 5
|
|
461
|
+
)
|
|
462
|
+
assert (
|
|
463
|
+
metric["metrics"]["phase"]["transform"][
|
|
464
|
+
"object_count_type"
|
|
465
|
+
]["transformed"]["object_count"]
|
|
466
|
+
== 5
|
|
467
|
+
)
|
|
468
|
+
assert (
|
|
469
|
+
metric["metrics"]["phase"]["transform"][
|
|
470
|
+
"object_count_type"
|
|
471
|
+
]["filtered_out"]["object_count"]
|
|
472
|
+
== 0
|
|
473
|
+
)
|
|
474
|
+
assert (
|
|
475
|
+
metric["metrics"]["phase"]["load"]["object_count_type"][
|
|
476
|
+
"failed"
|
|
477
|
+
]["object_count"]
|
|
478
|
+
== 5
|
|
479
|
+
)
|
|
480
|
+
|
|
481
|
+
# Verify success
|
|
482
|
+
assert metric["metrics"]["phase"]["resync"]["success"] == 1
|
|
483
|
+
|
|
484
|
+
# Verify sync state
|
|
485
|
+
assert metric["syncState"] == "completed"
|
|
486
|
+
|
|
273
487
|
|
|
274
488
|
@pytest.mark.asyncio
|
|
275
489
|
async def test_register_raw(
|
|
@@ -670,6 +884,7 @@ async def test_register_resource_raw_skip_event_type_http_request_upsert_called_
|
|
|
670
884
|
async def test_on_resync_start_hooks_are_called(
|
|
671
885
|
mock_sync_raw_mixin: SyncRawMixin,
|
|
672
886
|
mock_port_app_config: PortAppConfig,
|
|
887
|
+
mock_ocean: Ocean,
|
|
673
888
|
) -> None:
|
|
674
889
|
# Setup
|
|
675
890
|
resync_start_called = False
|
|
@@ -679,7 +894,9 @@ async def test_on_resync_start_hooks_are_called(
|
|
|
679
894
|
resync_start_called = True
|
|
680
895
|
|
|
681
896
|
mock_sync_raw_mixin.on_resync_start(on_resync_start)
|
|
682
|
-
|
|
897
|
+
mock_ocean.metrics.report_sync_metrics = AsyncMock(return_value=None) # type: ignore
|
|
898
|
+
mock_ocean.metrics.report_kind_sync_metrics = AsyncMock(return_value=None) # type: ignore
|
|
899
|
+
mock_ocean.metrics.send_metrics_to_webhook = AsyncMock(return_value=None) # type: ignore
|
|
683
900
|
# Execute
|
|
684
901
|
async with event_context(EventType.RESYNC, trigger_type="machine") as event:
|
|
685
902
|
event.port_app_config = mock_port_app_config
|
|
@@ -707,6 +924,9 @@ async def test_on_resync_complete_hooks_are_called_on_success(
|
|
|
707
924
|
|
|
708
925
|
mock_sync_raw_mixin.on_resync_complete(on_resync_complete)
|
|
709
926
|
mock_ocean.port_client.search_entities.return_value = [] # type: ignore
|
|
927
|
+
mock_ocean.metrics.report_sync_metrics = AsyncMock(return_value=None) # type: ignore
|
|
928
|
+
mock_ocean.metrics.report_kind_sync_metrics = AsyncMock(return_value=None) # type: ignore
|
|
929
|
+
mock_ocean.metrics.send_metrics_to_webhook = AsyncMock(return_value=None) # type: ignore
|
|
710
930
|
|
|
711
931
|
# Execute
|
|
712
932
|
async with event_context(EventType.RESYNC, trigger_type="machine") as event:
|
|
@@ -777,6 +997,9 @@ async def test_multiple_on_resync_start_on_resync_complete_hooks_called_in_order
|
|
|
777
997
|
mock_sync_raw_mixin.on_resync_complete(on_resync_complete2)
|
|
778
998
|
mock_ocean.port_client.search_entities.return_value = [] # type: ignore
|
|
779
999
|
|
|
1000
|
+
mock_ocean.metrics.report_sync_metrics = AsyncMock(return_value=None) # type: ignore
|
|
1001
|
+
mock_ocean.metrics.report_kind_sync_metrics = AsyncMock(return_value=None) # type: ignore
|
|
1002
|
+
mock_ocean.metrics.send_metrics_to_webhook = AsyncMock(return_value=None) # type: ignore
|
|
780
1003
|
# Execute
|
|
781
1004
|
async with event_context(EventType.RESYNC, trigger_type="machine") as event:
|
|
782
1005
|
event.port_app_config = mock_port_app_config
|
|
@@ -798,6 +1021,7 @@ async def test_multiple_on_resync_start_on_resync_complete_hooks_called_in_order
|
|
|
798
1021
|
async def test_on_resync_start_hook_error_prevents_resync(
|
|
799
1022
|
mock_sync_raw_mixin: SyncRawMixin,
|
|
800
1023
|
mock_port_app_config: PortAppConfig,
|
|
1024
|
+
mock_ocean: Ocean,
|
|
801
1025
|
) -> None:
|
|
802
1026
|
# Setup
|
|
803
1027
|
resync_complete_called = False
|
|
@@ -812,7 +1036,9 @@ async def test_on_resync_start_hook_error_prevents_resync(
|
|
|
812
1036
|
|
|
813
1037
|
mock_sync_raw_mixin.on_resync_start(on_resync_start)
|
|
814
1038
|
mock_sync_raw_mixin.on_resync_complete(on_resync_complete)
|
|
815
|
-
|
|
1039
|
+
mock_ocean.metrics.report_sync_metrics = AsyncMock(return_value=None) # type: ignore
|
|
1040
|
+
mock_ocean.metrics.report_kind_sync_metrics = AsyncMock(return_value=None) # type: ignore
|
|
1041
|
+
mock_ocean.metrics.send_metrics_to_webhook = AsyncMock(return_value=None) # type: ignore
|
|
816
1042
|
original_get_resource_raw_results = mock_sync_raw_mixin._get_resource_raw_results
|
|
817
1043
|
|
|
818
1044
|
async def track_resync(*args: Any, **kwargs: Any) -> Any:
|
|
@@ -53,7 +53,7 @@ port_ocean/clients/port/client.py,sha256=dv0mxIOde6J-wFi1FXXZkoNPVHrZzY7RSMhNkDD
|
|
|
53
53
|
port_ocean/clients/port/mixins/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
54
54
|
port_ocean/clients/port/mixins/blueprints.py,sha256=aMCG4zePsMSMjMLiGrU37h5z5_ElfMzTcTvqvOI5wXY,4683
|
|
55
55
|
port_ocean/clients/port/mixins/entities.py,sha256=-1Gs74z_8eviWItHIpveQhKdA7gnjbqZ3STS4jgGONs,11668
|
|
56
|
-
port_ocean/clients/port/mixins/integrations.py,sha256=
|
|
56
|
+
port_ocean/clients/port/mixins/integrations.py,sha256=QuPZ4MC8FtJ-3FKbm0CqJ5TOxtSyaQLR_rsJ-p7-y_Q,11115
|
|
57
57
|
port_ocean/clients/port/mixins/migrations.py,sha256=vdL_A_NNUogvzujyaRLIoZEu5vmKDY2BxTjoGP94YzI,1467
|
|
58
58
|
port_ocean/clients/port/mixins/organization.py,sha256=A2cP5V49KnjoAXxjmnm_XGth4ftPSU0qURNfnyUyS_Y,1041
|
|
59
59
|
port_ocean/clients/port/retry_transport.py,sha256=PtIZOAZ6V-ncpVysRUsPOgt8Sf01QLnTKB5YeKBxkJk,1861
|
|
@@ -87,7 +87,7 @@ port_ocean/core/handlers/base.py,sha256=cTarblazu8yh8xz2FpB-dzDKuXxtoi143XJgPbV_
|
|
|
87
87
|
port_ocean/core/handlers/entities_state_applier/__init__.py,sha256=kgLZDCeCEzi4r-0nzW9k78haOZNf6PX7mJOUr34A4c8,173
|
|
88
88
|
port_ocean/core/handlers/entities_state_applier/base.py,sha256=5wHL0icfFAYRPqk8iV_wN49GdJ3aRUtO8tumSxBi4Wo,2268
|
|
89
89
|
port_ocean/core/handlers/entities_state_applier/port/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
90
|
-
port_ocean/core/handlers/entities_state_applier/port/applier.py,sha256=
|
|
90
|
+
port_ocean/core/handlers/entities_state_applier/port/applier.py,sha256=CcrKlFG0eAvUqWit_2SjDrYfTDmMlr4PPSiPBIw7qhM,6367
|
|
91
91
|
port_ocean/core/handlers/entities_state_applier/port/get_related_entities.py,sha256=1zncwCbE-Gej0xaWKlzZgoXxOBe9bgs_YxlZ8QW3NdI,1751
|
|
92
92
|
port_ocean/core/handlers/entities_state_applier/port/order_by_entities_dependencies.py,sha256=lyv6xKzhYfd6TioUgR3AVRSJqj7JpAaj1LxxU2xAqeo,1720
|
|
93
93
|
port_ocean/core/handlers/entity_processor/__init__.py,sha256=FvFCunFg44wNQoqlybem9MthOs7p1Wawac87uSXz9U8,156
|
|
@@ -101,7 +101,7 @@ port_ocean/core/handlers/queue/__init__.py,sha256=1fICM0ZLATmmj6f7cdq_eV2kmw0_jy
|
|
|
101
101
|
port_ocean/core/handlers/queue/abstract_queue.py,sha256=q_gpaWFFZHxM3XovEbgsDn8jEOLM45iAZWVC81Paxto,620
|
|
102
102
|
port_ocean/core/handlers/queue/local_queue.py,sha256=EzqsGIX43xbVAcePwTcCg5QDrXATQpy-VzWxxN_OyAM,574
|
|
103
103
|
port_ocean/core/handlers/resync_state_updater/__init__.py,sha256=kG6y-JQGpPfuTHh912L_bctIDCzAK4DN-d00S7rguWU,81
|
|
104
|
-
port_ocean/core/handlers/resync_state_updater/updater.py,sha256=
|
|
104
|
+
port_ocean/core/handlers/resync_state_updater/updater.py,sha256=KZ55dubVYmFHxUOzdUFBPGLQhQSVBiRAoyk3R-NKKRU,3819
|
|
105
105
|
port_ocean/core/handlers/webhook/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
106
106
|
port_ocean/core/handlers/webhook/abstract_webhook_processor.py,sha256=5KwZkdkDd5HdVkXPzKiqabodZKl-hOtMypkTKd8Hq3M,3891
|
|
107
107
|
port_ocean/core/handlers/webhook/processor_manager.py,sha256=ipyAXoFtF84EGczyzRcZCzQG4Ippjo4eMsnVxMVz12A,12072
|
|
@@ -113,7 +113,7 @@ port_ocean/core/integrations/mixins/events.py,sha256=2L7P3Jhp8XBqddh2_o9Cn4N261n
|
|
|
113
113
|
port_ocean/core/integrations/mixins/handler.py,sha256=mZ7-0UlG3LcrwJttFbMe-R4xcOU2H_g33tZar7PwTv8,3771
|
|
114
114
|
port_ocean/core/integrations/mixins/live_events.py,sha256=8HklZmlyffYY_LeDe8xbt3Tb08rlLkqVhFF-2NQeJP4,4126
|
|
115
115
|
port_ocean/core/integrations/mixins/sync.py,sha256=Vm_898pLKBwfVewtwouDWsXoxcOLicnAy6pzyqqk6U8,4053
|
|
116
|
-
port_ocean/core/integrations/mixins/sync_raw.py,sha256=
|
|
116
|
+
port_ocean/core/integrations/mixins/sync_raw.py,sha256=4ikStO_BurcB5Hy1uYcWMO-exYJbOnu6by9eYmMJbJU,29490
|
|
117
117
|
port_ocean/core/integrations/mixins/utils.py,sha256=oN4Okz6xlaefpid1_Pud8HPSw9BwwjRohyNsknq-Myg,2309
|
|
118
118
|
port_ocean/core/models.py,sha256=YpJ2XOB3Zt9_M-rcMrMjugFNzBDg2hCUKgqvEt7now0,2348
|
|
119
119
|
port_ocean/core/ocean_types.py,sha256=4VipWFOHEh_d9LmWewQccwx1p2dtrRYW0YURVgNsAjo,1398
|
|
@@ -131,15 +131,15 @@ port_ocean/exceptions/utils.py,sha256=gjOqpi-HpY1l4WlMFsGA9yzhxDhajhoGGdDDyGbLnq
|
|
|
131
131
|
port_ocean/exceptions/webhook_processor.py,sha256=yQYazg53Y-ohb7HfViwq1opH_ZUuUdhHSRxcUNveFpI,114
|
|
132
132
|
port_ocean/helpers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
133
133
|
port_ocean/helpers/async_client.py,sha256=SRlP6o7_FCSY3UHnRlZdezppePVxxOzZ0z861vE3K40,1783
|
|
134
|
-
port_ocean/helpers/metric/metric.py,sha256=
|
|
135
|
-
port_ocean/helpers/metric/utils.py,sha256=
|
|
134
|
+
port_ocean/helpers/metric/metric.py,sha256=F7R5JGmyGPsvqBY7wlDfOc15GX28-Kslbw99Y0aETv0,12785
|
|
135
|
+
port_ocean/helpers/metric/utils.py,sha256=Wnr-6HwVwBtYJ3so44OkhDRs8udLMSB1oduzl2-zRHo,781
|
|
136
136
|
port_ocean/helpers/retry.py,sha256=gmS4YxM6N4fboFp7GSgtOzyBJemxs46bnrz4L4rDS6Y,16136
|
|
137
137
|
port_ocean/log/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
138
138
|
port_ocean/log/handlers.py,sha256=ncVjgqrZRh6BhyRrA6DQG86Wsbxph1yWYuEC0cWfe-Q,3631
|
|
139
139
|
port_ocean/log/logger_setup.py,sha256=0K3zVG0YYrYOWEV8-rCGks1o-bMRxgHXlqawu9w_tSw,2656
|
|
140
140
|
port_ocean/log/sensetive.py,sha256=lVKiZH6b7TkrZAMmhEJRhcl67HNM94e56x12DwFgCQk,2920
|
|
141
141
|
port_ocean/middlewares.py,sha256=9wYCdyzRZGK1vjEJ28FY_DkfwDNENmXp504UKPf5NaQ,2727
|
|
142
|
-
port_ocean/ocean.py,sha256=
|
|
142
|
+
port_ocean/ocean.py,sha256=8yUw9pDBGkqBHza_PKtINz_7G69Ia6o1m8H-SvlKOOk,7462
|
|
143
143
|
port_ocean/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
144
144
|
port_ocean/run.py,sha256=COoRSmLG4hbsjIW5DzhV0NYVegI9xHd1POv6sg4U1No,2217
|
|
145
145
|
port_ocean/sonar-project.properties,sha256=X_wLzDOkEVmpGLRMb2fg9Rb0DxWwUFSvESId8qpvrPI,73
|
|
@@ -155,7 +155,7 @@ port_ocean/tests/core/defaults/test_common.py,sha256=sR7RqB3ZYV6Xn6NIg-c8k5K6JcG
|
|
|
155
155
|
port_ocean/tests/core/handlers/entities_state_applier/test_applier.py,sha256=WNg1fWZsXu0MDnz9-ahRiPb_OPofWx7E8wxBx0cyZKs,8946
|
|
156
156
|
port_ocean/tests/core/handlers/entity_processor/test_jq_entity_processor.py,sha256=8WpMn559Mf0TFWmloRpZrVgr6yWwyA0C4n2lVHCtyq4,13596
|
|
157
157
|
port_ocean/tests/core/handlers/mixins/test_live_events.py,sha256=iAwVpr3n3PIkXQLw7hxd-iB_SR_vyfletVXJLOmyz28,12480
|
|
158
|
-
port_ocean/tests/core/handlers/mixins/test_sync_raw.py,sha256=
|
|
158
|
+
port_ocean/tests/core/handlers/mixins/test_sync_raw.py,sha256=ZjAWXpheHa61M9nIj4FUGKt9xMeI4Z1AvE6Nko-uru8,43482
|
|
159
159
|
port_ocean/tests/core/handlers/port_app_config/test_api.py,sha256=eJZ6SuFBLz71y4ca3DNqKag6d6HUjNJS0aqQPwiLMTI,1999
|
|
160
160
|
port_ocean/tests/core/handlers/port_app_config/test_base.py,sha256=hSh556bJM9zuELwhwnyKSfd9z06WqWXIfe-6hCl5iKI,9799
|
|
161
161
|
port_ocean/tests/core/handlers/queue/test_local_queue.py,sha256=9Ly0HzZXbs6Rbl_bstsIdInC3h2bgABU3roP9S_PnJM,2582
|
|
@@ -188,8 +188,8 @@ port_ocean/utils/repeat.py,sha256=U2OeCkHPWXmRTVoPV-VcJRlQhcYqPWI5NfmPlb1JIbc,32
|
|
|
188
188
|
port_ocean/utils/signal.py,sha256=mMVq-1Ab5YpNiqN4PkiyTGlV_G0wkUDMMjTZp5z3pb0,1514
|
|
189
189
|
port_ocean/utils/time.py,sha256=pufAOH5ZQI7gXvOvJoQXZXZJV-Dqktoj9Qp9eiRwmJ4,1939
|
|
190
190
|
port_ocean/version.py,sha256=UsuJdvdQlazzKGD3Hd5-U7N69STh8Dq9ggJzQFnu9fU,177
|
|
191
|
-
port_ocean-0.22.
|
|
192
|
-
port_ocean-0.22.
|
|
193
|
-
port_ocean-0.22.
|
|
194
|
-
port_ocean-0.22.
|
|
195
|
-
port_ocean-0.22.
|
|
191
|
+
port_ocean-0.22.11.dist-info/LICENSE.md,sha256=WNHhf_5RCaeuKWyq_K39vmp9F28LxKsB4SpomwSZ2L0,11357
|
|
192
|
+
port_ocean-0.22.11.dist-info/METADATA,sha256=Fo942o0gljfDJTPxcKfgK3fpbBVSQluymPor_ztGo2Q,6765
|
|
193
|
+
port_ocean-0.22.11.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
|
|
194
|
+
port_ocean-0.22.11.dist-info/entry_points.txt,sha256=F_DNUmGZU2Kme-8NsWM5LLE8piGMafYZygRYhOVtcjA,54
|
|
195
|
+
port_ocean-0.22.11.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|