Skip to content

Commit

Permalink
[Core] Fix event handling when using register_raw and `unregister_r…
Browse files Browse the repository at this point in the history
…aw` (#1303)
  • Loading branch information
Tankilevitch authored Jan 8, 2025
1 parent 9ec5975 commit fdd6b88
Show file tree
Hide file tree
Showing 4 changed files with 165 additions and 3 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,13 @@ this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm

<!-- towncrier release notes start -->

## 0.17.6 (2025-01-08)

### Bug Fixes

- Fixed a bug where the `unregister_raw` and `register_raw` were not handling right the errors and misconfigured entity keys


## 0.17.5 (2025-01-07)


Expand Down
7 changes: 5 additions & 2 deletions port_ocean/core/integrations/mixins/sync_raw.py
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ async def _register_resource_raw(
return CalculationResult(
objects_diff[0].entity_selector_diff._replace(passed=modified_objects),
errors=objects_diff[0].errors,
misonfigured_entity_keys=objects_diff[0].misonfigured_entity_keys,
)

async def _unregister_resource_raw(
Expand All @@ -162,7 +163,7 @@ async def _unregister_resource_raw(
return [], []

objects_diff = await self._calculate_raw([(resource, results)])
entities_selector_diff, errors = objects_diff[0]
entities_selector_diff, errors, _ = objects_diff[0]

await self.entities_state_applier.delete(
entities_selector_diff.passed, user_agent_type
Expand Down Expand Up @@ -245,7 +246,7 @@ async def register_raw(
if not resource_mappings:
return []

diffs, errors = zip(
diffs, errors, misconfigured_entity_keys = zip(
*await asyncio.gather(
*(
self._register_resource_raw(
Expand All @@ -258,6 +259,8 @@ async def register_raw(

diffs = list(diffs)
errors = sum(errors, [])
misconfigured_entity_keys = list(misconfigured_entity_keys)


if errors:
message = f"Failed to register {len(errors)} entities. Skipping delete phase due to incomplete state"
Expand Down
152 changes: 152 additions & 0 deletions port_ocean/tests/core/handlers/mixins/test_sync_raw.py
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,14 @@ def mock_sync_raw_mixin(
return sync_raw_mixin


@pytest.fixture
def mock_sync_raw_mixin_with_jq_processor(
mock_sync_raw_mixin: SyncRawMixin,
) -> SyncRawMixin:
mock_sync_raw_mixin._entity_processor = JQEntityProcessor(mock_context) # type: ignore
return mock_sync_raw_mixin


@asynccontextmanager
async def no_op_event_context(
existing_event: EventContext,
Expand Down Expand Up @@ -398,3 +406,147 @@ def get_entities_wrapper(*args: Any, **kwargs: Any) -> Any:
"entity_3-entity_1-entity_4-entity_2-entity_5",
"entity_3-entity_1-entity_4-entity_5-entity_2",
)


@pytest.mark.asyncio
async def test_register_raw(
mock_sync_raw_mixin_with_jq_processor: SyncRawMixin, mock_ocean: Ocean
) -> None:
kind = "service"
user_agent_type = UserAgentType.exporter
raw_entity = [
{"id": "entity_1", "name": "entity_1", "web_url": "https://example.com"},
]
expected_result = [
{
"identifier": "entity_1",
"blueprint": "service",
"name": "entity_1",
"properties": {"url": "https://example.com"},
},
]

async with event_context(EventType.HTTP_REQUEST, trigger_type="machine") as event:
# Use patch to mock the method instead of direct assignment
with patch.object(
mock_sync_raw_mixin_with_jq_processor.port_app_config_handler,
"get_port_app_config",
return_value=PortAppConfig(
enable_merge_entity=True,
delete_dependent_entities=True,
create_missing_related_entities=False,
resources=[
ResourceConfig(
kind=kind,
selector=Selector(query="true"),
port=PortResourceConfig(
entity=MappingsConfig(
mappings=EntityMapping(
identifier=".id | tostring",
title=".name",
blueprint='"service"',
properties={"url": ".web_url"},
relations={},
)
)
),
)
],
),
):
# Ensure the event.port_app_config is set correctly
event.port_app_config = await mock_sync_raw_mixin_with_jq_processor.port_app_config_handler.get_port_app_config(
use_cache=False
)

def upsert_side_effect(
entities: list[Entity], user_agent_type: UserAgentType
) -> list[Entity]:
# Simulate returning the passed entities
return entities

# Patch the upsert method with the side effect
with patch.object(
mock_sync_raw_mixin_with_jq_processor.entities_state_applier,
"upsert",
side_effect=upsert_side_effect,
):
# Call the register_raw method
registered_entities = (
await mock_sync_raw_mixin_with_jq_processor.register_raw(
kind, raw_entity, user_agent_type
)
)

# Assert that the registered entities match the expected results
assert len(registered_entities) == len(expected_result)
for entity, result in zip(registered_entities, expected_result):
assert entity.identifier == result["identifier"]
assert entity.blueprint == result["blueprint"]
assert entity.properties == result["properties"]


@pytest.mark.asyncio
async def test_unregister_raw(
mock_sync_raw_mixin_with_jq_processor: SyncRawMixin, mock_ocean: Ocean
) -> None:
kind = "service"
user_agent_type = UserAgentType.exporter
raw_entity = [
{"id": "entity_1", "name": "entity_1", "web_url": "https://example.com"},
]
expected_result = [
{
"identifier": "entity_1",
"blueprint": "service",
"name": "entity_1",
"properties": {"url": "https://example.com"},
},
]

async with event_context(EventType.HTTP_REQUEST, trigger_type="machine") as event:
# Use patch to mock the method instead of direct assignment
with patch.object(
mock_sync_raw_mixin_with_jq_processor.port_app_config_handler,
"get_port_app_config",
return_value=PortAppConfig(
enable_merge_entity=True,
delete_dependent_entities=True,
create_missing_related_entities=False,
resources=[
ResourceConfig(
kind=kind,
selector=Selector(query="true"),
port=PortResourceConfig(
entity=MappingsConfig(
mappings=EntityMapping(
identifier=".id | tostring",
title=".name",
blueprint='"service"',
properties={"url": ".web_url"},
relations={},
)
)
),
)
],
),
):
# Ensure the event.port_app_config is set correctly
event.port_app_config = await mock_sync_raw_mixin_with_jq_processor.port_app_config_handler.get_port_app_config(
use_cache=False
)

# Call the unregister_raw method
unregistered_entities = (
await mock_sync_raw_mixin_with_jq_processor.unregister_raw(
kind, raw_entity, user_agent_type
)
)

# Assert that the unregistered entities match the expected results
assert len(unregistered_entities) == len(expected_result)
for entity, result in zip(unregistered_entities, expected_result):
assert entity.identifier == result["identifier"]
assert entity.blueprint == result["blueprint"]
assert entity.properties == result["properties"]
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "port-ocean"
version = "0.17.5"
version = "0.17.6"
description = "Port Ocean is a CLI tool for managing your Port projects."
readme = "README.md"
homepage = "https://app.getport.io"
Expand Down

0 comments on commit fdd6b88

Please sign in to comment.