port-ocean 0.18.3__tar.gz → 0.18.5__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.
Potentially problematic release.
This version of port-ocean might be problematic. Click here for more details.
- {port_ocean-0.18.3 → port_ocean-0.18.5}/PKG-INFO +1 -1
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/clients/port/mixins/entities.py +3 -1
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/context/event.py +8 -1
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/core/handlers/port_app_config/api.py +4 -1
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/core/integrations/mixins/sync_raw.py +18 -24
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/exceptions/api.py +7 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/tests/core/handlers/mixins/test_sync_raw.py +131 -214
- port_ocean-0.18.5/port_ocean/tests/core/handlers/port_app_config/test_api.py +67 -0
- port_ocean-0.18.5/port_ocean/tests/core/handlers/port_app_config/test_base.py +197 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/pyproject.toml +1 -1
- {port_ocean-0.18.3 → port_ocean-0.18.5}/LICENSE.md +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/README.md +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/integrations/_infra/Dockerfile.Deb +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/integrations/_infra/Dockerfile.alpine +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/integrations/_infra/Dockerfile.base.builder +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/integrations/_infra/Dockerfile.base.runner +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/integrations/_infra/Dockerfile.dockerignore +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/integrations/_infra/Makefile +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/integrations/_infra/grpcio.sh +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/integrations/_infra/init.sh +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/__init__.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/bootstrap.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/cli/__init__.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/cli/cli.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/cli/commands/__init__.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/cli/commands/defaults/__init___.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/cli/commands/defaults/clean.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/cli/commands/defaults/dock.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/cli/commands/defaults/group.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/cli/commands/list_integrations.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/cli/commands/main.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/cli/commands/new.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/cli/commands/pull.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/cli/commands/sail.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/cli/commands/version.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/cli/cookiecutter/__init__.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/cli/cookiecutter/cookiecutter.json +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/cli/cookiecutter/extensions.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/cli/cookiecutter/hooks/post_gen_project.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/.env.example +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/.gitignore +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/.port/resources/.gitignore +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/.port/resources/blueprints.json +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/.port/resources/port-app-config.yml +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/.port/spec.yaml +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/CHANGELOG.md +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/CONTRIBUTING.md +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/README.md +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/changelog/.gitignore +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/debug.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/main.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/poetry.toml +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/pyproject.toml +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/sonar-project.properties +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/tests/__init__.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/tests/test_sample.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/cli/utils.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/clients/__init__.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/clients/port/__init__.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/clients/port/authentication.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/clients/port/client.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/clients/port/mixins/__init__.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/clients/port/mixins/blueprints.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/clients/port/mixins/integrations.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/clients/port/mixins/migrations.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/clients/port/mixins/organization.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/clients/port/retry_transport.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/clients/port/types.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/clients/port/utils.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/config/__init__.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/config/base.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/config/dynamic.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/config/settings.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/consumers/__init__.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/consumers/kafka_consumer.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/context/__init__.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/context/ocean.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/context/resource.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/core/__init__.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/core/defaults/__init__.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/core/defaults/clean.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/core/defaults/common.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/core/defaults/initialize.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/core/event_listener/__init__.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/core/event_listener/base.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/core/event_listener/factory.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/core/event_listener/http.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/core/event_listener/kafka.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/core/event_listener/once.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/core/event_listener/polling.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/core/event_listener/webhooks_only.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/core/handlers/__init__.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/core/handlers/base.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/core/handlers/entities_state_applier/__init__.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/core/handlers/entities_state_applier/base.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/core/handlers/entities_state_applier/port/__init__.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/core/handlers/entities_state_applier/port/applier.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/core/handlers/entities_state_applier/port/get_related_entities.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/core/handlers/entities_state_applier/port/order_by_entities_dependencies.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/core/handlers/entity_processor/__init__.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/core/handlers/entity_processor/base.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/core/handlers/entity_processor/jq_entity_processor.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/core/handlers/port_app_config/__init__.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/core/handlers/port_app_config/base.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/core/handlers/port_app_config/models.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/core/handlers/resync_state_updater/__init__.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/core/handlers/resync_state_updater/updater.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/core/integrations/__init__.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/core/integrations/base.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/core/integrations/mixins/__init__.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/core/integrations/mixins/events.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/core/integrations/mixins/handler.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/core/integrations/mixins/sync.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/core/integrations/mixins/utils.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/core/models.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/core/ocean_types.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/core/utils/entity_topological_sorter.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/core/utils/utils.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/debug_cli.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/exceptions/__init__.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/exceptions/base.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/exceptions/clients.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/exceptions/context.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/exceptions/core.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/exceptions/port_defaults.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/exceptions/utils.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/helpers/__init__.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/helpers/async_client.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/helpers/retry.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/log/__init__.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/log/handlers.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/log/logger_setup.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/log/sensetive.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/middlewares.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/ocean.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/py.typed +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/run.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/sonar-project.properties +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/tests/__init__.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/tests/clients/port/mixins/test_entities.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/tests/clients/port/mixins/test_organization_mixin.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/tests/conftest.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/tests/core/defaults/test_common.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/tests/core/handlers/entity_processor/test_jq_entity_processor.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/tests/core/test_utils.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/tests/core/utils/test_entity_topological_sorter.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/tests/core/utils/test_resolve_entities_diff.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/tests/helpers/__init__.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/tests/helpers/fake_port_api.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/tests/helpers/fixtures.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/tests/helpers/integration.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/tests/helpers/ocean_app.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/tests/helpers/port_client.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/tests/helpers/smoke_test.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/tests/log/test_handlers.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/tests/test_smoke.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/tests/utils/test_async_iterators.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/tests/utils/test_cache.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/utils/__init__.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/utils/async_http.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/utils/async_iterators.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/utils/cache.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/utils/misc.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/utils/queue_utils.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/utils/repeat.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/utils/signal.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/utils/time.py +0 -0
- {port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/version.py +0 -0
|
@@ -22,7 +22,9 @@ class EntityClientMixin:
|
|
|
22
22
|
# Semaphore is used to limit the number of concurrent requests to port, to avoid overloading it.
|
|
23
23
|
# The number of concurrent requests is set to 90% of the max connections limit, to leave some room for other
|
|
24
24
|
# requests that are not related to entities.
|
|
25
|
-
self.semaphore = asyncio.Semaphore(
|
|
25
|
+
self.semaphore = asyncio.Semaphore(
|
|
26
|
+
round(0.5 * PORT_HTTP_MAX_CONNECTIONS_LIMIT)
|
|
27
|
+
) # 50% of the max connections limit in order to avoid overloading port
|
|
26
28
|
|
|
27
29
|
async def upsert_entity(
|
|
28
30
|
self,
|
|
@@ -19,6 +19,7 @@ from pydispatch import dispatcher # type: ignore
|
|
|
19
19
|
from werkzeug.local import LocalStack, LocalProxy
|
|
20
20
|
|
|
21
21
|
from port_ocean.context.resource import resource
|
|
22
|
+
from port_ocean.exceptions.api import EmptyPortAppConfigError
|
|
22
23
|
from port_ocean.exceptions.context import (
|
|
23
24
|
EventContextNotFoundError,
|
|
24
25
|
ResourceContextNotFoundError,
|
|
@@ -176,8 +177,14 @@ async def event_context(
|
|
|
176
177
|
logger.info("Event started")
|
|
177
178
|
try:
|
|
178
179
|
yield event
|
|
179
|
-
except:
|
|
180
|
+
except EmptyPortAppConfigError as e:
|
|
181
|
+
logger.error(
|
|
182
|
+
f"Skipping resync due to empty mapping: {str(e)}", exc_info=True
|
|
183
|
+
)
|
|
184
|
+
raise
|
|
185
|
+
except Exception as e:
|
|
180
186
|
success = False
|
|
187
|
+
logger.error(f"Event failed with error: {str(e)}", exc_info=True)
|
|
181
188
|
raise
|
|
182
189
|
else:
|
|
183
190
|
success = True
|
|
@@ -3,6 +3,7 @@ from typing import Any
|
|
|
3
3
|
from loguru import logger
|
|
4
4
|
|
|
5
5
|
from port_ocean.core.handlers.port_app_config.base import BasePortAppConfig
|
|
6
|
+
from port_ocean.exceptions.api import EmptyPortAppConfigError
|
|
6
7
|
|
|
7
8
|
|
|
8
9
|
class APIPortAppConfig(BasePortAppConfig):
|
|
@@ -20,7 +21,9 @@ class APIPortAppConfig(BasePortAppConfig):
|
|
|
20
21
|
if not config:
|
|
21
22
|
logger.error(
|
|
22
23
|
"The integration port app config is empty. "
|
|
24
|
+
f"Integration: {integration}, "
|
|
25
|
+
f"Config: {config}. "
|
|
23
26
|
"Please make sure to configure your port app config using Port's API."
|
|
24
27
|
)
|
|
25
|
-
|
|
28
|
+
raise EmptyPortAppConfigError()
|
|
26
29
|
return config
|
|
@@ -220,33 +220,27 @@ class SyncRawMixin(HandlerMixin, EventsMixin):
|
|
|
220
220
|
)
|
|
221
221
|
modified_objects = []
|
|
222
222
|
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
223
|
+
try:
|
|
224
|
+
changed_entities = await self._map_entities_compared_with_port(
|
|
225
|
+
objects_diff[0].entity_selector_diff.passed,
|
|
226
|
+
resource,
|
|
227
|
+
user_agent_type
|
|
228
|
+
)
|
|
229
|
+
if changed_entities:
|
|
230
|
+
logger.info("Upserting changed entities", changed_entities=len(changed_entities),
|
|
231
|
+
total_entities=len(objects_diff[0].entity_selector_diff.passed))
|
|
232
|
+
await self.entities_state_applier.upsert(
|
|
233
|
+
changed_entities, user_agent_type
|
|
229
234
|
)
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
changed_entities, user_agent_type
|
|
236
|
-
)
|
|
237
|
-
else:
|
|
238
|
-
logger.info("Entities in batch didn't changed since last sync, skipping", total_entities=len(objects_diff[0].entity_selector_diff.passed))
|
|
239
|
-
|
|
240
|
-
modified_objects = [ocean.port_client._reduce_entity(entity) for entity in objects_diff[0].entity_selector_diff.passed]
|
|
241
|
-
except Exception as e:
|
|
242
|
-
logger.warning(f"Failed to resolve batch entities with Port, falling back to upserting all entities: {str(e)}")
|
|
243
|
-
modified_objects = await self.entities_state_applier.upsert(
|
|
244
|
-
objects_diff[0].entity_selector_diff.passed, user_agent_type
|
|
245
|
-
)
|
|
246
|
-
else:
|
|
235
|
+
else:
|
|
236
|
+
logger.info("Entities in batch didn't changed since last sync, skipping", total_entities=len(objects_diff[0].entity_selector_diff.passed))
|
|
237
|
+
modified_objects = [ocean.port_client._reduce_entity(entity) for entity in objects_diff[0].entity_selector_diff.passed]
|
|
238
|
+
except Exception as e:
|
|
239
|
+
logger.warning(f"Failed to resolve batch entities with Port, falling back to upserting all entities: {str(e)}")
|
|
247
240
|
modified_objects = await self.entities_state_applier.upsert(
|
|
248
241
|
objects_diff[0].entity_selector_diff.passed, user_agent_type
|
|
249
|
-
|
|
242
|
+
)
|
|
243
|
+
|
|
250
244
|
return CalculationResult(
|
|
251
245
|
objects_diff[0].entity_selector_diff._replace(passed=modified_objects),
|
|
252
246
|
errors=objects_diff[0].errors,
|
|
@@ -13,3 +13,10 @@ class BaseAPIException(BaseOceanException, abc.ABC):
|
|
|
13
13
|
class InternalServerException(BaseAPIException):
|
|
14
14
|
def response(self) -> Response:
|
|
15
15
|
return PlainTextResponse(content="Internal server error", status_code=500)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class EmptyPortAppConfigError(Exception):
|
|
19
|
+
"""Exception raised when the Port app configuration is empty."""
|
|
20
|
+
|
|
21
|
+
def __init__(self, message: str = "Port app config is empty") -> None:
|
|
22
|
+
super().__init__(message)
|
{port_ocean-0.18.3 → port_ocean-0.18.5}/port_ocean/tests/core/handlers/mixins/test_sync_raw.py
RENAMED
|
@@ -433,93 +433,76 @@ async def test_sync_raw_mixin_dependency(
|
|
|
433
433
|
@pytest.mark.asyncio
|
|
434
434
|
async def test_register_raw(
|
|
435
435
|
mock_sync_raw_mixin_with_jq_processor: SyncRawMixin,
|
|
436
|
-
|
|
437
|
-
mock_context: PortOceanContext,
|
|
438
|
-
monkeypatch: pytest.MonkeyPatch,
|
|
436
|
+
mock_resource_config: ResourceConfig,
|
|
439
437
|
) -> None:
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
monkeypatch.setattr(mock_context.app, "is_saas", lambda: False)
|
|
456
|
-
|
|
457
|
-
async with event_context(EventType.HTTP_REQUEST, trigger_type="machine") as event:
|
|
458
|
-
# Use patch to mock the method instead of direct assignment
|
|
459
|
-
with patch.object(
|
|
460
|
-
mock_sync_raw_mixin_with_jq_processor.port_app_config_handler,
|
|
461
|
-
"get_port_app_config",
|
|
462
|
-
return_value=PortAppConfig(
|
|
463
|
-
enable_merge_entity=True,
|
|
464
|
-
delete_dependent_entities=True,
|
|
465
|
-
create_missing_related_entities=False,
|
|
466
|
-
resources=[
|
|
467
|
-
ResourceConfig(
|
|
468
|
-
kind=kind,
|
|
469
|
-
selector=Selector(query="true"),
|
|
470
|
-
port=PortResourceConfig(
|
|
471
|
-
entity=MappingsConfig(
|
|
472
|
-
mappings=EntityMapping(
|
|
473
|
-
identifier=".id | tostring",
|
|
474
|
-
title=".name",
|
|
475
|
-
blueprint='"service"',
|
|
476
|
-
properties={"url": ".web_url"},
|
|
477
|
-
relations={},
|
|
478
|
-
)
|
|
479
|
-
)
|
|
480
|
-
),
|
|
481
|
-
)
|
|
482
|
-
],
|
|
483
|
-
),
|
|
484
|
-
):
|
|
485
|
-
# Ensure the event.port_app_config is set correctly
|
|
486
|
-
event.port_app_config = await mock_sync_raw_mixin_with_jq_processor.port_app_config_handler.get_port_app_config(
|
|
487
|
-
use_cache=False
|
|
488
|
-
)
|
|
489
|
-
|
|
490
|
-
def upsert_side_effect(
|
|
491
|
-
entities: list[Entity], user_agent_type: UserAgentType
|
|
492
|
-
) -> list[Entity]:
|
|
493
|
-
# Simulate returning the passed entities
|
|
494
|
-
return entities
|
|
438
|
+
# Mock the integration settings with skip_check_diff
|
|
439
|
+
with patch.object(ocean.config.integration, "skip_check_diff", False):
|
|
440
|
+
kind = "service"
|
|
441
|
+
user_agent_type = UserAgentType.exporter
|
|
442
|
+
raw_entity = [
|
|
443
|
+
{"id": "entity_1", "name": "entity_1", "web_url": "https://example.com"},
|
|
444
|
+
]
|
|
445
|
+
expected_result = [
|
|
446
|
+
{
|
|
447
|
+
"identifier": "entity_1",
|
|
448
|
+
"blueprint": "service",
|
|
449
|
+
"name": "entity_1",
|
|
450
|
+
"properties": {},
|
|
451
|
+
},
|
|
452
|
+
]
|
|
495
453
|
|
|
496
|
-
|
|
454
|
+
async with event_context(
|
|
455
|
+
EventType.HTTP_REQUEST, trigger_type="machine"
|
|
456
|
+
) as event:
|
|
457
|
+
# Use patch to mock the method instead of direct assignment
|
|
497
458
|
with patch.object(
|
|
498
|
-
mock_sync_raw_mixin_with_jq_processor.
|
|
499
|
-
"
|
|
500
|
-
|
|
459
|
+
mock_sync_raw_mixin_with_jq_processor.port_app_config_handler,
|
|
460
|
+
"get_port_app_config",
|
|
461
|
+
return_value=PortAppConfig(
|
|
462
|
+
enable_merge_entity=True,
|
|
463
|
+
delete_dependent_entities=True,
|
|
464
|
+
create_missing_related_entities=False,
|
|
465
|
+
resources=[mock_resource_config],
|
|
466
|
+
),
|
|
501
467
|
):
|
|
502
|
-
#
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
kind, raw_entity, user_agent_type
|
|
506
|
-
)
|
|
468
|
+
# Ensure the event.port_app_config is set correctly
|
|
469
|
+
event.port_app_config = await mock_sync_raw_mixin_with_jq_processor.port_app_config_handler.get_port_app_config(
|
|
470
|
+
use_cache=False
|
|
507
471
|
)
|
|
508
472
|
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
473
|
+
def upsert_side_effect(
|
|
474
|
+
entities: list[Entity], user_agent_type: UserAgentType
|
|
475
|
+
) -> list[Entity]:
|
|
476
|
+
# Simulate returning the passed entities
|
|
477
|
+
return entities
|
|
478
|
+
|
|
479
|
+
# Patch the upsert method with the side effect
|
|
480
|
+
with patch.object(
|
|
481
|
+
mock_sync_raw_mixin_with_jq_processor.entities_state_applier,
|
|
482
|
+
"upsert",
|
|
483
|
+
side_effect=upsert_side_effect,
|
|
484
|
+
):
|
|
485
|
+
# Call the register_raw method
|
|
486
|
+
registered_entities = (
|
|
487
|
+
await mock_sync_raw_mixin_with_jq_processor.register_raw(
|
|
488
|
+
kind, raw_entity, user_agent_type
|
|
489
|
+
)
|
|
490
|
+
)
|
|
491
|
+
|
|
492
|
+
# Assert that the registered entities match the expected results
|
|
493
|
+
assert len(registered_entities) == len(expected_result)
|
|
494
|
+
for entity, result in zip(registered_entities, expected_result):
|
|
495
|
+
assert entity.identifier == result["identifier"]
|
|
496
|
+
assert entity.blueprint == result["blueprint"]
|
|
497
|
+
assert entity.properties == result["properties"]
|
|
515
498
|
|
|
516
499
|
|
|
517
500
|
@pytest.mark.asyncio
|
|
518
501
|
async def test_unregister_raw(
|
|
519
502
|
mock_sync_raw_mixin_with_jq_processor: SyncRawMixin,
|
|
520
|
-
mock_ocean: Ocean,
|
|
521
503
|
mock_context: PortOceanContext,
|
|
522
504
|
monkeypatch: pytest.MonkeyPatch,
|
|
505
|
+
mock_resource_config: ResourceConfig,
|
|
523
506
|
) -> None:
|
|
524
507
|
kind = "service"
|
|
525
508
|
user_agent_type = UserAgentType.exporter
|
|
@@ -547,23 +530,7 @@ async def test_unregister_raw(
|
|
|
547
530
|
enable_merge_entity=True,
|
|
548
531
|
delete_dependent_entities=True,
|
|
549
532
|
create_missing_related_entities=False,
|
|
550
|
-
resources=[
|
|
551
|
-
ResourceConfig(
|
|
552
|
-
kind=kind,
|
|
553
|
-
selector=Selector(query="true"),
|
|
554
|
-
port=PortResourceConfig(
|
|
555
|
-
entity=MappingsConfig(
|
|
556
|
-
mappings=EntityMapping(
|
|
557
|
-
identifier=".id | tostring",
|
|
558
|
-
title=".name",
|
|
559
|
-
blueprint='"service"',
|
|
560
|
-
properties={"url": ".web_url"},
|
|
561
|
-
relations={},
|
|
562
|
-
)
|
|
563
|
-
)
|
|
564
|
-
),
|
|
565
|
-
)
|
|
566
|
-
],
|
|
533
|
+
resources=[mock_resource_config],
|
|
567
534
|
),
|
|
568
535
|
):
|
|
569
536
|
# Ensure the event.port_app_config is set correctly
|
|
@@ -718,142 +685,92 @@ class CalculationResult:
|
|
|
718
685
|
|
|
719
686
|
|
|
720
687
|
@pytest.mark.asyncio
|
|
721
|
-
async def
|
|
722
|
-
mock_sync_raw_mixin: SyncRawMixin,
|
|
723
|
-
mock_port_app_config: PortAppConfig,
|
|
724
|
-
mock_context: PortOceanContext,
|
|
725
|
-
monkeypatch: pytest.MonkeyPatch,
|
|
726
|
-
) -> None:
|
|
727
|
-
# Mock ocean.app.is_saas()
|
|
728
|
-
monkeypatch.setattr(mock_context.app, "is_saas", lambda: True)
|
|
729
|
-
|
|
730
|
-
# Mock dependencies
|
|
731
|
-
entity = Entity(identifier="1", blueprint="service")
|
|
732
|
-
mock_sync_raw_mixin._calculate_raw = AsyncMock(return_value=[CalculationResult(entity_selector_diff=EntitySelectorDiff(passed=[entity], failed=[]), errors=[], misconfigurations=[], misonfigured_entity_keys=[])]) # type: ignore
|
|
733
|
-
mock_sync_raw_mixin._map_entities_compared_with_port = AsyncMock(return_value=([])) # type: ignore
|
|
734
|
-
mock_sync_raw_mixin.entities_state_applier.upsert = AsyncMock() # type: ignore
|
|
735
|
-
|
|
736
|
-
async with event_context(EventType.RESYNC, trigger_type="machine") as event:
|
|
737
|
-
event.port_app_config = mock_port_app_config
|
|
738
|
-
|
|
739
|
-
# Test execution
|
|
740
|
-
result = await mock_sync_raw_mixin._register_resource_raw(
|
|
741
|
-
mock_port_app_config.resources[0], # Use the first resource from the config
|
|
742
|
-
[{"some": "data"}],
|
|
743
|
-
UserAgentType.exporter,
|
|
744
|
-
)
|
|
745
|
-
|
|
746
|
-
# Assertions
|
|
747
|
-
assert len(result.entity_selector_diff.passed) == 1
|
|
748
|
-
mock_sync_raw_mixin._calculate_raw.assert_called_once()
|
|
749
|
-
mock_sync_raw_mixin.entities_state_applier.upsert.assert_not_called()
|
|
750
|
-
mock_sync_raw_mixin._map_entities_compared_with_port.assert_called_once()
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
@pytest.mark.asyncio
|
|
754
|
-
async def test_register_resource_raw_saas_with_changes_upsert_called_and_entities_are_mapped(
|
|
688
|
+
async def test_register_resource_raw_no_changes_upsert_not_called_entitiy_is_returned(
|
|
755
689
|
mock_sync_raw_mixin: SyncRawMixin,
|
|
756
690
|
mock_port_app_config: PortAppConfig,
|
|
757
|
-
mock_context: PortOceanContext,
|
|
758
|
-
monkeypatch: pytest.MonkeyPatch,
|
|
759
691
|
) -> None:
|
|
760
|
-
# Mock
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
692
|
+
# Mock the integration settings with skip_check_diff
|
|
693
|
+
with patch.object(ocean.config.integration, "skip_check_diff", False):
|
|
694
|
+
entity = Entity(identifier="1", blueprint="service")
|
|
695
|
+
mock_sync_raw_mixin._calculate_raw = AsyncMock(return_value=[CalculationResult(entity_selector_diff=EntitySelectorDiff(passed=[entity], failed=[]), errors=[], misconfigurations=[], misonfigured_entity_keys=[])]) # type: ignore
|
|
696
|
+
mock_sync_raw_mixin._map_entities_compared_with_port = AsyncMock(return_value=([])) # type: ignore
|
|
697
|
+
mock_sync_raw_mixin.entities_state_applier.upsert = AsyncMock() # type: ignore
|
|
698
|
+
|
|
699
|
+
async with event_context(EventType.RESYNC, trigger_type="machine") as event:
|
|
700
|
+
event.port_app_config = mock_port_app_config
|
|
701
|
+
|
|
702
|
+
# Test execution
|
|
703
|
+
result = await mock_sync_raw_mixin._register_resource_raw(
|
|
704
|
+
mock_port_app_config.resources[
|
|
705
|
+
0
|
|
706
|
+
], # Use the first resource from the config
|
|
707
|
+
[{"some": "data"}],
|
|
708
|
+
UserAgentType.exporter,
|
|
709
|
+
)
|
|
778
710
|
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
711
|
+
# Assertions
|
|
712
|
+
assert len(result.entity_selector_diff.passed) == 1
|
|
713
|
+
mock_sync_raw_mixin._calculate_raw.assert_called_once()
|
|
714
|
+
mock_sync_raw_mixin.entities_state_applier.upsert.assert_not_called()
|
|
715
|
+
mock_sync_raw_mixin._map_entities_compared_with_port.assert_called_once()
|
|
784
716
|
|
|
785
717
|
|
|
786
718
|
@pytest.mark.asyncio
|
|
787
|
-
async def
|
|
719
|
+
async def test_register_resource_raw_with_changes_upsert_called_and_entities_are_mapped(
|
|
788
720
|
mock_sync_raw_mixin: SyncRawMixin,
|
|
789
721
|
mock_port_app_config: PortAppConfig,
|
|
790
|
-
mock_context: PortOceanContext,
|
|
791
|
-
monkeypatch: pytest.MonkeyPatch,
|
|
792
722
|
) -> None:
|
|
793
|
-
# Mock
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
event.port_app_config = mock_port_app_config
|
|
810
|
-
|
|
811
|
-
# Test execution
|
|
812
|
-
result = await mock_sync_raw_mixin._register_resource_raw(
|
|
813
|
-
mock_port_app_config.resources[0],
|
|
814
|
-
[{"some": "data"}],
|
|
815
|
-
UserAgentType.exporter,
|
|
816
|
-
)
|
|
723
|
+
# Mock the integration settings with skip_check_diff
|
|
724
|
+
with patch.object(ocean.config.integration, "skip_check_diff", False):
|
|
725
|
+
entity = Entity(identifier="1", blueprint="service")
|
|
726
|
+
mock_sync_raw_mixin._calculate_raw = AsyncMock(return_value=[CalculationResult(entity_selector_diff=EntitySelectorDiff(passed=[entity], failed=[]), errors=[], misconfigurations=[], misonfigured_entity_keys=[])]) # type: ignore
|
|
727
|
+
mock_sync_raw_mixin._map_entities_compared_with_port = AsyncMock(return_value=([entity])) # type: ignore
|
|
728
|
+
mock_sync_raw_mixin.entities_state_applier.upsert = AsyncMock(return_value=[entity]) # type: ignore
|
|
729
|
+
|
|
730
|
+
async with event_context(EventType.RESYNC, trigger_type="machine") as event:
|
|
731
|
+
event.port_app_config = mock_port_app_config
|
|
732
|
+
|
|
733
|
+
# Test execution
|
|
734
|
+
result = await mock_sync_raw_mixin._register_resource_raw(
|
|
735
|
+
mock_port_app_config.resources[0],
|
|
736
|
+
[{"some": "data"}],
|
|
737
|
+
UserAgentType.exporter,
|
|
738
|
+
)
|
|
817
739
|
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
740
|
+
# Assertions
|
|
741
|
+
assert len(result.entity_selector_diff.passed) == 1
|
|
742
|
+
mock_sync_raw_mixin._calculate_raw.assert_called_once()
|
|
743
|
+
mock_sync_raw_mixin.entities_state_applier.upsert.assert_called_once()
|
|
744
|
+
mock_sync_raw_mixin._map_entities_compared_with_port.assert_called_once()
|
|
823
745
|
|
|
824
746
|
|
|
825
747
|
@pytest.mark.asyncio
|
|
826
|
-
async def
|
|
827
|
-
mock_sync_raw_mixin: SyncRawMixin,
|
|
828
|
-
mock_port_app_config: PortAppConfig,
|
|
829
|
-
mock_context: PortOceanContext,
|
|
830
|
-
monkeypatch: pytest.MonkeyPatch,
|
|
748
|
+
async def test_register_resource_raw_with_errors(
|
|
749
|
+
mock_sync_raw_mixin: SyncRawMixin, mock_port_app_config: PortAppConfig
|
|
831
750
|
) -> None:
|
|
832
|
-
# Mock
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
UserAgentType.exporter,
|
|
850
|
-
)
|
|
751
|
+
# Mock the integration settings with skip_check_diff
|
|
752
|
+
with patch.object(ocean.config.integration, "skip_check_diff", False):
|
|
753
|
+
failed_entity = Entity(identifier="1", blueprint="service")
|
|
754
|
+
error = Exception("Test error")
|
|
755
|
+
mock_sync_raw_mixin._calculate_raw = AsyncMock(return_value=[CalculationResult(entity_selector_diff=EntitySelectorDiff(passed=[], failed=[failed_entity]), errors=[error], misconfigurations=[], misonfigured_entity_keys=[])]) # type: ignore
|
|
756
|
+
mock_sync_raw_mixin._map_entities_compared_with_port = AsyncMock(return_value=([])) # type: ignore
|
|
757
|
+
mock_sync_raw_mixin.entities_state_applier.upsert = AsyncMock() # type: ignore
|
|
758
|
+
|
|
759
|
+
async with event_context(EventType.RESYNC, trigger_type="machine") as event:
|
|
760
|
+
event.port_app_config = mock_port_app_config
|
|
761
|
+
|
|
762
|
+
# Test execution
|
|
763
|
+
result = await mock_sync_raw_mixin._register_resource_raw(
|
|
764
|
+
mock_port_app_config.resources[0],
|
|
765
|
+
[{"some": "data"}],
|
|
766
|
+
UserAgentType.exporter,
|
|
767
|
+
)
|
|
851
768
|
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
769
|
+
# Assertions
|
|
770
|
+
assert len(result.entity_selector_diff.passed) == 0
|
|
771
|
+
assert len(result.entity_selector_diff.failed) == 1
|
|
772
|
+
assert len(result.errors) == 1
|
|
773
|
+
assert result.errors[0] == error
|
|
774
|
+
mock_sync_raw_mixin._calculate_raw.assert_called_once()
|
|
775
|
+
mock_sync_raw_mixin._map_entities_compared_with_port.assert_called_once()
|
|
776
|
+
mock_sync_raw_mixin.entities_state_applier.upsert.assert_not_called()
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
from unittest.mock import AsyncMock
|
|
3
|
+
|
|
4
|
+
from port_ocean.core.handlers.port_app_config.api import APIPortAppConfig
|
|
5
|
+
from port_ocean.exceptions.api import EmptyPortAppConfigError
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@pytest.fixture
|
|
9
|
+
def mock_context() -> AsyncMock:
|
|
10
|
+
context = AsyncMock()
|
|
11
|
+
context.port_client.get_current_integration = AsyncMock()
|
|
12
|
+
return context
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@pytest.fixture
|
|
16
|
+
def api_config(mock_context: AsyncMock) -> APIPortAppConfig:
|
|
17
|
+
return APIPortAppConfig(mock_context)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
async def test_get_port_app_config_valid_config_returns_config(
|
|
21
|
+
api_config: APIPortAppConfig, mock_context: AsyncMock
|
|
22
|
+
) -> None:
|
|
23
|
+
# Arrange
|
|
24
|
+
expected_config = {"key": "value"}
|
|
25
|
+
mock_context.port_client.get_current_integration.return_value = {
|
|
26
|
+
"config": expected_config
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
# Act
|
|
30
|
+
result = await api_config._get_port_app_config()
|
|
31
|
+
|
|
32
|
+
# Assert
|
|
33
|
+
assert result == expected_config
|
|
34
|
+
mock_context.port_client.get_current_integration.assert_called_once()
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
async def test_get_port_app_config_empty_config_raises_value_error(
|
|
38
|
+
api_config: APIPortAppConfig, mock_context: AsyncMock
|
|
39
|
+
) -> None:
|
|
40
|
+
# Arrange
|
|
41
|
+
mock_context.port_client.get_current_integration.return_value = {"config": {}}
|
|
42
|
+
|
|
43
|
+
# Act & Assert
|
|
44
|
+
with pytest.raises(EmptyPortAppConfigError, match="Port app config is empty"):
|
|
45
|
+
await api_config._get_port_app_config()
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
async def test_get_port_app_config_missing_config_key_raises_key_error(
|
|
49
|
+
api_config: APIPortAppConfig, mock_context: AsyncMock
|
|
50
|
+
) -> None:
|
|
51
|
+
# Arrange
|
|
52
|
+
mock_context.port_client.get_current_integration.return_value = {}
|
|
53
|
+
|
|
54
|
+
# Act & Assert
|
|
55
|
+
with pytest.raises(KeyError):
|
|
56
|
+
await api_config._get_port_app_config()
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
async def test_get_port_app_config_empty_integration_raises_key_error(
|
|
60
|
+
api_config: APIPortAppConfig, mock_context: AsyncMock
|
|
61
|
+
) -> None:
|
|
62
|
+
# Arrange
|
|
63
|
+
mock_context.port_client.get_current_integration.return_value = {}
|
|
64
|
+
|
|
65
|
+
# Act & Assert
|
|
66
|
+
with pytest.raises(KeyError):
|
|
67
|
+
await api_config._get_port_app_config()
|