ocean icon indicating copy to clipboard operation
ocean copied to clipboard

Use the upsert bulk routes in re-syncs

Open itamar-smirra-port opened this issue 7 months ago • 4 comments

User description

Description

What:

  • Use the upsert bulk routes in re-syncs - only is ocean saas and under a feature flag
  • Add tests
  • Fix the tests to use async mock

Why - To reduce re-sync time and reduce load on Port

How - Split the entities into batches and upsert them by the upsert batch api route

Type of change

Please leave one option from the following and delete the rest:

  • [ ] Bug fix (non-breaking change which fixes an issue)
  • [ ] New feature (non-breaking change which adds functionality)
  • [ ] New Integration (non-breaking change which adds a new integration)
  • [x] Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • [ ] Non-breaking change (fix of existing functionality that will not change current behavior)
  • [ ] Documentation (added/updated documentation)

All tests should be run against the port production environment(using a testing org).

Core testing checklist

  • [ ] Integration able to create all default resources from scratch
  • [ ] Resync finishes successfully
  • [ ] Resync able to create entities
  • [ ] Resync able to update entities
  • [ ] Resync able to detect and delete entities
  • [ ] Scheduled resync able to abort existing resync and start a new one
  • [ ] Tested with at least 2 integrations from scratch
  • [ ] Tested with Kafka and Polling event listeners
  • [ ] Tested deletion of entities that don't pass the selector

PR Type

Enhancement


Description

  • Implement batch upsert of entities using new bulk API route

    • Add upsert_entities_batch and upsert_entities_in_batches methods
    • Use batch size from configuration for upserts
  • Update tests to use async mocks and cover new batch upsert logic

    • Add tests for exception handling and batch processing
  • Add batch size configuration to settings

  • Update pre-commit hooks to use local virtual environment for formatters/linters


Changes walkthrough 📝

Relevant files
Enhancement
entities.py
Implement batch and bulk upsert methods for entities         

port_ocean/clients/port/mixins/entities.py

  • Add upsert_entities_batch for bulk upsert via API
  • Add upsert_entities_in_batches to process entities in configurable
    batches
  • Use batch size from config via ocean context
  • Refactor previous batch upsert logic to new methods
  • +137/-20
    applier.py
    Use new batch upsert method in entity applier                       

    port_ocean/core/handlers/entities_state_applier/port/applier.py

  • Switch from old batch upsert to new upsert_entities_in_batches method
  • +1/-1     
    Configuration changes
    settings.py
    Add batch size configuration for entity upserts                   

    port_ocean/config/settings.py

    • Add upsert_entities_batch_size config option with default 20
    +2/-0     
    .pre-commit-config.yaml
    Use local venv for pre-commit formatters/linters                 

    .pre-commit-config.yaml

  • Update hooks to use .venv/bin/black and .venv/bin/ruff
  • Remove generic lint/fix hook
  • +11/-4   
    Tests
    test_entities.py
    Update and extend tests for batch upsert logic                     

    port_ocean/tests/clients/port/mixins/test_entities.py

  • Refactor tests to use async mocks for batch upsert
  • Add tests for exception handling in batch upsert
  • Add fixture for mocking ocean context and batch size
  • +62/-14 

    Need help?
  • Type /help how to ... in the comments thread for any questions about Qodo Merge usage.
  • Check out the documentation for more information.
  • itamar-smirra-port avatar Apr 27 '25 14:04 itamar-smirra-port

    CI Feedback 🧐

    (Feedback updated until commit https://github.com/port-labs/ocean/commit/3ce37eb61f4fa9a0bfc1df375267497caf837211)

    A test triggered by this PR failed. Here is an AI-generated analysis of the failure:

    Action: 🌊 Ocean Core Tests

    Failed stage: Unit Test Core [❌]

    Failed test name: test_applier_with_mock_context

    Failure summary:

    The action failed because 4 tests in the
    port_ocean/tests/core/handlers/entities_state_applier/test_applier.py file failed with the same
    error: "AssertionError: Expected 'mock' to have been called once. Called 0 times."

    The failing tests are:

  • test_applier_with_mock_context
  • test_applier_one_not_upserted
  • test_applier_error_upserting
  • test_using_create_entity_helper

    In each test, a mock function mock_upsert was created and set as the upsert_entities_batch method on
    the port_client object, but this mock was never called during test execution when it was expected to
    be called exactly once.
  • Relevant error logs:
    1:  ##[group]Runner Image Provisioner
    2:  Hosted Compute Agent
    ...
    
    1107:  [gw0][36m [  1%] [0m[32mPASSED[0m port_ocean/tests/cache/test_disk_cache.py::test_disk_cache_clear 
    1108:  [gw1][36m [  1%] [0m[32mPASSED[0m port_ocean/tests/core/defaults/test_common.py::test_custom_defaults_dir_used_if_valid 
    1109:  port_ocean/tests/core/defaults/test_common.py::test_fallback_to_default_dir_if_custom_dir_invalid 
    1110:  port_ocean/tests/cache/test_disk_cache.py::test_disk_cache_nonexistent_key 
    1111:  [gw0][36m [  2%] [0m[32mPASSED[0m port_ocean/tests/cache/test_disk_cache.py::test_disk_cache_nonexistent_key 
    1112:  port_ocean/tests/cache/test_disk_cache.py::test_disk_cache_corrupted_file 
    1113:  [gw1][36m [  2%] [0m[32mPASSED[0m port_ocean/tests/core/defaults/test_common.py::test_fallback_to_default_dir_if_custom_dir_invalid 
    1114:  port_ocean/tests/core/defaults/test_common.py::test_default_resources_path_does_not_exist 
    1115:  [gw1][36m [  3%] [0m[32mPASSED[0m port_ocean/tests/core/defaults/test_common.py::test_default_resources_path_does_not_exist 
    1116:  port_ocean/tests/core/handlers/entities_state_applier/test_applier.py::test_delete_diff_no_deleted_entities 
    1117:  [gw1][36m [  4%] [0m[32mPASSED[0m port_ocean/tests/core/handlers/entities_state_applier/test_applier.py::test_delete_diff_no_deleted_entities 
    1118:  port_ocean/tests/core/handlers/entities_state_applier/test_applier.py::test_delete_diff_below_threshold 
    1119:  [gw1][36m [  4%] [0m[32mPASSED[0m port_ocean/tests/core/handlers/entities_state_applier/test_applier.py::test_delete_diff_below_threshold 
    1120:  port_ocean/tests/core/handlers/entities_state_applier/test_applier.py::test_delete_diff_above_default_threshold 
    1121:  [gw0][36m [  5%] [0m[32mPASSED[0m port_ocean/tests/cache/test_disk_cache.py::test_disk_cache_corrupted_file 
    1122:  port_ocean/tests/cache/test_disk_cache.py::test_disk_cache_write_error 
    1123:  [gw0][36m [  5%] [0m[32mPASSED[0m port_ocean/tests/cache/test_disk_cache.py::test_disk_cache_write_error 
    1124:  port_ocean/tests/cache/test_memory_cache.py::test_memory_cache_set_get 
    ...
    
    1147:  [gw0][36m [ 12%] [0m[32mPASSED[0m port_ocean/tests/clients/port/mixins/test_entities.py::test_calculate_entities_batch_size_small_entities 
    1148:  port_ocean/tests/clients/port/mixins/test_entities.py::test_calculate_entities_batch_size_large_entities 
    1149:  [gw0][36m [ 13%] [0m[32mPASSED[0m port_ocean/tests/clients/port/mixins/test_entities.py::test_calculate_entities_batch_size_large_entities 
    1150:  port_ocean/tests/clients/port/mixins/test_entities.py::test_calculate_entities_batch_size_mixed_entities 
    1151:  [gw0][36m [ 13%] [0m[32mPASSED[0m port_ocean/tests/clients/port/mixins/test_entities.py::test_calculate_entities_batch_size_mixed_entities 
    1152:  port_ocean/tests/clients/port/mixins/test_entities.py::test_calculate_entities_batch_size_single_large_entity 
    1153:  [gw0][36m [ 14%] [0m[32mPASSED[0m port_ocean/tests/clients/port/mixins/test_entities.py::test_calculate_entities_batch_size_single_large_entity 
    1154:  port_ocean/tests/clients/port/mixins/test_entities.py::test_batch_upsert_entities_read_timeout_should_raise_false 
    1155:  [gw0][36m [ 14%] [0m[32mPASSED[0m port_ocean/tests/clients/port/mixins/test_entities.py::test_batch_upsert_entities_read_timeout_should_raise_false 
    1156:  port_ocean/tests/clients/port/mixins/test_entities.py::test_batch_upsert_entities_read_timeout_should_raise_false_with_exception 
    1157:  [gw0][36m [ 15%] [0m[32mPASSED[0m port_ocean/tests/clients/port/mixins/test_entities.py::test_batch_upsert_entities_read_timeout_should_raise_false_with_exception 
    1158:  port_ocean/tests/clients/port/mixins/test_entities.py::test_batch_upsert_entities_read_timeout_should_raise_true 
    1159:  [gw0][36m [ 16%] [0m[32mPASSED[0m port_ocean/tests/clients/port/mixins/test_entities.py::test_batch_upsert_entities_read_timeout_should_raise_true 
    1160:  port_ocean/tests/clients/port/mixins/test_organization_mixin.py::test_org_feature_flags_should_fetch_proper_json_path 
    1161:  [gw0][36m [ 16%] [0m[32mPASSED[0m port_ocean/tests/clients/port/mixins/test_organization_mixin.py::test_org_feature_flags_should_fetch_proper_json_path 
    1162:  port_ocean/tests/core/handlers/entity_processor/test_jq_entity_processor.py::TestJQEntityProcessor::test_search_as_object_failure 
    1163:  [gw0][36m [ 17%] [0m[32mPASSED[0m port_ocean/tests/core/handlers/entity_processor/test_jq_entity_processor.py::TestJQEntityProcessor::test_search_as_object_failure 
    1164:  port_ocean/tests/core/handlers/entity_processor/test_jq_entity_processor.py::TestJQEntityProcessor::test_double_quotes_in_jq_expression 
    1165:  [gw0][36m [ 17%] [0m[32mPASSED[0m port_ocean/tests/core/handlers/entity_processor/test_jq_entity_processor.py::TestJQEntityProcessor::test_double_quotes_in_jq_expression 
    1166:  port_ocean/tests/core/handlers/entity_processor/test_jq_entity_processor.py::TestJQEntityProcessor::test_search_as_bool_failure 
    1167:  [gw0][36m [ 18%] [0m[32mPASSED[0m port_ocean/tests/core/handlers/entity_processor/test_jq_entity_processor.py::TestJQEntityProcessor::test_search_as_bool_failure 
    1168:  port_ocean/tests/core/handlers/entity_processor/test_jq_entity_processor.py::TestJQEntityProcessor::test_search_fails_on_stop_iteration[.parameters[] | select(.name == "not_exists") | .value-None] 
    1169:  [gw0][36m [ 18%] [0m[32mPASSED[0m port_ocean/tests/core/handlers/entity_processor/test_jq_entity_processor.py::TestJQEntityProcessor::test_search_fails_on_stop_iteration[.parameters[] | select(.name == "not_exists") | .value-None] 
    1170:  port_ocean/tests/core/handlers/entity_processor/test_jq_entity_processor.py::TestJQEntityProcessor::test_search_fails_on_stop_iteration[.parameters[] | select(.name == "parameter_name") | .value-parameter_value] 
    1171:  [gw1][36m [ 19%] [0m[31mFAILED[0m port_ocean/tests/core/handlers/entities_state_applier/test_applier.py::test_applier_with_mock_context 
    1172:  [gw0][36m [ 20%] [0m[32mPASSED[0m port_ocean/tests/core/handlers/entity_processor/test_jq_entity_processor.py::TestJQEntityProcessor::test_search_fails_on_stop_iteration[.parameters[] | select(.name == "parameter_name") | .value-parameter_value] 
    1173:  port_ocean/tests/core/handlers/entities_state_applier/test_applier.py::test_applier_one_not_upserted 
    1174:  port_ocean/tests/core/handlers/entity_processor/test_jq_entity_processor.py::TestJQEntityProcessor::test_search_fails_on_stop_iteration[.parameters[] | select(.name == "another_parameter") | .value-another_value] 
    1175:  [gw0][36m [ 20%] [0m[32mPASSED[0m port_ocean/tests/core/handlers/entity_processor/test_jq_entity_processor.py::TestJQEntityProcessor::test_search_fails_on_stop_iteration[.parameters[] | select(.name == "another_parameter") | .value-another_value] 
    1176:  port_ocean/tests/core/handlers/entity_processor/test_jq_entity_processor.py::TestJQEntityProcessor::test_return_a_list_of_values 
    1177:  [gw0][36m [ 21%] [0m[32mPASSED[0m port_ocean/tests/core/handlers/entity_processor/test_jq_entity_processor.py::TestJQEntityProcessor::test_return_a_list_of_values 
    1178:  port_ocean/tests/core/handlers/entity_processor/test_jq_entity_processor.py::TestJQEntityProcessor::test_search_performance_10000 
    1179:  [gw1][36m [ 21%] [0m[31mFAILED[0m port_ocean/tests/core/handlers/entities_state_applier/test_applier.py::test_applier_one_not_upserted 
    1180:  port_ocean/tests/core/handlers/entities_state_applier/test_applier.py::test_applier_error_upserting 
    1181:  [gw1][36m [ 22%] [0m[31mFAILED[0m port_ocean/tests/core/handlers/entities_state_applier/test_applier.py::test_applier_error_upserting 
    1182:  port_ocean/tests/core/handlers/entities_state_applier/test_applier.py::test_using_create_entity_helper 
    1183:  [gw1][36m [ 22%] [0m[31mFAILED[0m port_ocean/tests/core/handlers/entities_state_applier/test_applier.py::test_using_create_entity_helper 
    1184:  port_ocean/tests/core/handlers/entity_processor/test_jq_entity_processor.py::TestJQEntityProcessor::test_compile 
    1185:  [gw1][36m [ 23%] [0m[32mPASSED[0m port_ocean/tests/core/handlers/entity_processor/test_jq_entity_processor.py::TestJQEntityProcessor::test_compile 
    1186:  port_ocean/tests/core/handlers/entity_processor/test_jq_entity_processor.py::TestJQEntityProcessor::test_search 
    1187:  [gw1][36m [ 24%] [0m[32mPASSED[0m port_ocean/tests/core/handlers/entity_processor/test_jq_entity_processor.py::TestJQEntityProcessor::test_search 
    1188:  port_ocean/tests/core/handlers/entity_processor/test_jq_entity_processor.py::TestJQEntityProcessor::test_search_as_bool 
    1189:  [gw1][36m [ 24%] [0m[32mPASSED[0m port_ocean/tests/core/handlers/entity_processor/test_jq_entity_processor.py::TestJQEntityProcessor::test_search_as_bool 
    1190:  port_ocean/tests/core/handlers/entity_processor/test_jq_entity_processor.py::TestJQEntityProcessor::test_search_as_object 
    1191:  [gw1][36m [ 25%] [0m[32mPASSED[0m port_ocean/tests/core/handlers/entity_processor/test_jq_entity_processor.py::TestJQEntityProcessor::test_search_as_object 
    1192:  port_ocean/tests/core/handlers/entity_processor/test_jq_entity_processor.py::TestJQEntityProcessor::test_get_mapped_entity 
    1193:  [gw1][36m [ 25%] [0m[32mPASSED[0m port_ocean/tests/core/handlers/entity_processor/test_jq_entity_processor.py::TestJQEntityProcessor::test_get_mapped_entity 
    1194:  port_ocean/tests/core/handlers/entity_processor/test_jq_entity_processor.py::TestJQEntityProcessor::test_calculate_entity 
    1195:  [gw1][36m [ 26%] [0m[32mPASSED[0m port_ocean/tests/core/handlers/entity_processor/test_jq_entity_processor.py::TestJQEntityProcessor::test_calculate_entity 
    1196:  port_ocean/tests/core/handlers/entity_processor/test_jq_entity_processor.py::TestJQEntityProcessor::test_parse_items 
    1197:  [gw1][36m [ 27%] [0m[32mPASSED[0m port_ocean/tests/core/handlers/entity_processor/test_jq_entity_processor.py::TestJQEntityProcessor::test_parse_items 
    1198:  port_ocean/tests/core/handlers/entity_processor/test_jq_entity_processor.py::TestJQEntityProcessor::test_in_operator 
    1199:  [gw1][36m [ 27%] [0m[32mPASSED[0m port_ocean/tests/core/handlers/entity_processor/test_jq_entity_processor.py::TestJQEntityProcessor::test_in_operator 
    1200:  port_ocean/tests/core/handlers/entity_processor/test_jq_entity_processor.py::TestJQEntityProcessor::test_failure_of_jq_expression 
    1201:  [gw1][36m [ 28%] [0m[32mPASSED[0m port_ocean/tests/core/handlers/entity_processor/test_jq_entity_processor.py::TestJQEntityProcessor::test_failure_of_jq_expression 
    1202:  port_ocean/tests/core/handlers/mixins/test_sync_raw.py::test_unregister_raw 
    1203:  [gw1][36m [ 28%] [0m[32mPASSED[0m port_ocean/tests/core/handlers/mixins/test_sync_raw.py::test_unregister_raw 
    1204:  port_ocean/tests/core/handlers/mixins/test_sync_raw.py::test_map_entities_compared_with_port_no_port_entities_all_entities_are_mapped 
    1205:  [gw1][36m [ 29%] [0m[32mPASSED[0m port_ocean/tests/core/handlers/mixins/test_sync_raw.py::test_map_entities_compared_with_port_no_port_entities_all_entities_are_mapped 
    1206:  port_ocean/tests/core/handlers/mixins/test_sync_raw.py::test_map_entities_compared_with_port_returns_original_entities_when_using_team_search_query 
    1207:  [gw1][36m [ 29%] [0m[32mPASSED[0m port_ocean/tests/core/handlers/mixins/test_sync_raw.py::test_map_entities_compared_with_port_returns_original_entities_when_using_team_search_query 
    1208:  port_ocean/tests/core/handlers/mixins/test_sync_raw.py::test_map_entities_compared_with_port_with_existing_entities_only_changed_third_party_entities_are_mapped 
    1209:  [gw1][36m [ 30%] [0m[32mPASSED[0m port_ocean/tests/core/handlers/mixins/test_sync_raw.py::test_map_entities_compared_with_port_with_existing_entities_only_changed_third_party_entities_are_mapped 
    1210:  port_ocean/tests/core/handlers/mixins/test_sync_raw.py::test_map_entities_compared_with_port_with_multiple_batches_all_batches_are_being_proccessed_to_map 
    1211:  [gw1][36m [ 31%] [0m[32mPASSED[0m port_ocean/tests/core/handlers/mixins/test_sync_raw.py::test_map_entities_compared_with_port_with_multiple_batches_all_batches_are_being_proccessed_to_map 
    1212:  port_ocean/tests/core/handlers/mixins/test_sync_raw.py::test_register_resource_raw_no_changes_upsert_not_called_entitiy_is_returned 
    1213:  [gw1][36m [ 31%] [0m[32mPASSED[0m port_ocean/tests/core/handlers/mixins/test_sync_raw.py::test_register_resource_raw_no_changes_upsert_not_called_entitiy_is_returned 
    1214:  port_ocean/tests/core/handlers/mixins/test_sync_raw.py::test_register_resource_raw_with_changes_upsert_called_and_entities_are_mapped 
    1215:  [gw1][36m [ 32%] [0m[32mPASSED[0m port_ocean/tests/core/handlers/mixins/test_sync_raw.py::test_register_resource_raw_with_changes_upsert_called_and_entities_are_mapped 
    1216:  port_ocean/tests/core/handlers/mixins/test_sync_raw.py::test_register_resource_raw_with_errors 
    1217:  [gw1][36m [ 32%] [0m[32mPASSED[0m port_ocean/tests/core/handlers/mixins/test_sync_raw.py::test_register_resource_raw_with_errors 
    1218:  port_ocean/tests/core/handlers/mixins/test_sync_raw.py::test_register_resource_raw_skip_event_type_http_request_upsert_called_and_no_entitites_diff_calculation 
    1219:  [gw1][36m [ 33%] [0m[32mPASSED[0m port_ocean/tests/core/handlers/mixins/test_sync_raw.py::test_register_resource_raw_skip_event_type_http_request_upsert_called_and_no_entitites_diff_calculation 
    1220:  port_ocean/tests/core/handlers/mixins/test_sync_raw.py::test_on_resync_start_hooks_are_called 
    1221:  [gw1][36m [ 33%] [0m[32mPASSED[0m port_ocean/tests/core/handlers/mixins/test_sync_raw.py::test_on_resync_start_hooks_are_called 
    1222:  port_ocean/tests/core/handlers/mixins/test_sync_raw.py::test_on_resync_complete_hooks_are_called_on_success 
    1223:  [gw1][36m [ 34%] [0m[32mPASSED[0m port_ocean/tests/core/handlers/mixins/test_sync_raw.py::test_on_resync_complete_hooks_are_called_on_success 
    1224:  port_ocean/tests/core/handlers/mixins/test_sync_raw.py::test_on_resync_complete_hooks_not_called_on_error 
    1225:  [gw1][36m [ 35%] [0m[32mPASSED[0m port_ocean/tests/core/handlers/mixins/test_sync_raw.py::test_on_resync_complete_hooks_not_called_on_error 
    1226:  port_ocean/tests/core/handlers/mixins/test_sync_raw.py::test_multiple_on_resync_start_on_resync_complete_hooks_called_in_order 
    1227:  [gw1][36m [ 35%] [0m[32mPASSED[0m port_ocean/tests/core/handlers/mixins/test_sync_raw.py::test_multiple_on_resync_start_on_resync_complete_hooks_called_in_order 
    1228:  port_ocean/tests/core/handlers/mixins/test_sync_raw.py::test_on_resync_start_hook_error_prevents_resync 
    1229:  [gw1][36m [ 36%] [0m[32mPASSED[0m port_ocean/tests/core/handlers/mixins/test_sync_raw.py::test_on_resync_start_hook_error_prevents_resync 
    1230:  port_ocean/tests/core/handlers/port_app_config/test_api.py::test_get_port_app_config_valid_config_returns_config 
    1231:  [gw1][36m [ 36%] [0m[32mPASSED[0m port_ocean/tests/core/handlers/port_app_config/test_api.py::test_get_port_app_config_valid_config_returns_config 
    1232:  port_ocean/tests/core/handlers/webhook/test_abstract_webhook_processor.py::test_init_finishedSuccessfully 
    1233:  [gw1][36m [ 37%] [0m[32mPASSED[0m port_ocean/tests/core/handlers/webhook/test_abstract_webhook_processor.py::test_init_finishedSuccessfully 
    1234:  port_ocean/tests/core/handlers/webhook/test_abstract_webhook_processor.py::test_calculateRetryDelay_delayCalculatedCorrectly 
    1235:  [gw1][36m [ 37%] [0m[32mPASSED[0m port_ocean/tests/core/handlers/webhook/test_abstract_webhook_processor.py::test_calculateRetryDelay_delayCalculatedCorrectly 
    1236:  port_ocean/tests/core/handlers/webhook/test_abstract_webhook_processor.py::test_shouldRetry_returnsTrueOnRetryableError 
    1237:  [gw1][36m [ 38%] [0m[32mPASSED[0m port_ocean/tests/core/handlers/webhook/test_abstract_webhook_processor.py::test_shouldRetry_returnsTrueOnRetryableError 
    1238:  port_ocean/tests/core/handlers/webhook/test_abstract_webhook_processor.py::test_lifecycleHooks_callsCorrectly 
    1239:  [gw1][36m [ 39%] [0m[32mPASSED[0m port_ocean/tests/core/handlers/webhook/test_abstract_webhook_processor.py::test_lifecycleHooks_callsCorrectly 
    1240:  port_ocean/tests/core/handlers/webhook/test_processor_manager.py::test_extractMatchingProcessors_processorMatch 
    1241:  [gw1][36m [ 39%] [0m[32mPASSED[0m port_ocean/tests/core/handlers/webhook/test_processor_manager.py::test_extractMatchingProcessors_processorMatch 
    1242:  port_ocean/tests/core/handlers/webhook/test_processor_manager.py::test_extractMatchingProcessors_noMatch 
    1243:  [gw1][36m [ 40%] [0m[32mPASSED[0m port_ocean/tests/core/handlers/webhook/test_processor_manager.py::test_extractMatchingProcessors_noMatch 
    1244:  port_ocean/tests/core/handlers/webhook/test_processor_manager.py::test_extractMatchingProcessors_multipleMatches 
    1245:  [gw1][36m [ 40%] [0m[32mPASSED[0m port_ocean/tests/core/handlers/webhook/test_processor_manager.py::test_extractMatchingProcessors_multipleMatches 
    1246:  port_ocean/tests/core/handlers/webhook/test_processor_manager.py::test_extractMatchingProcessors_onlyOneMatches 
    1247:  [gw1][36m [ 41%] [0m[32mPASSED[0m port_ocean/tests/core/handlers/webhook/test_processor_manager.py::test_extractMatchingProcessors_onlyOneMatches 
    1248:  port_ocean/tests/core/handlers/webhook/test_processor_manager.py::test_registerProcessor_registrationWorks 
    1249:  [gw1][36m [ 41%] [0m[32mPASSED[0m port_ocean/tests/core/handlers/webhook/test_processor_manager.py::test_registerProcessor_registrationWorks 
    1250:  port_ocean/tests/core/handlers/webhook/test_processor_manager.py::test_registerProcessor_multipleHandlers_allRegistered 
    1251:  [gw1][36m [ 42%] [0m[32mPASSED[0m port_ocean/tests/core/handlers/webhook/test_processor_manager.py::test_registerProcessor_multipleHandlers_allRegistered 
    1252:  port_ocean/tests/core/handlers/webhook/test_processor_manager.py::test_registerProcessor_invalidHandlerRegistration_throwsError 
    1253:  [gw1][36m [ 43%] [0m[32mPASSED[0m port_ocean/tests/core/handlers/webhook/test_processor_manager.py::test_registerProcessor_invalidHandlerRegistration_throwsError 
    1254:  port_ocean/tests/core/handlers/webhook/test_processor_manager.py::test_processWebhookRequest_successfulProcessing 
    ...
    
    1277:  [gw0][36m [ 50%] [0m[32mPASSED[0m port_ocean/tests/core/handlers/entity_processor/test_jq_entity_processor.py::TestJQEntityProcessor::test_parse_items_empty_required 
    1278:  port_ocean/tests/core/handlers/mixins/test_live_events.py::test_parse_raw_event_results_to_entities_creation 
    1279:  [gw0][36m [ 50%] [0m[32mPASSED[0m port_ocean/tests/core/handlers/mixins/test_live_events.py::test_parse_raw_event_results_to_entities_creation 
    1280:  port_ocean/tests/core/handlers/mixins/test_live_events.py::test_parse_raw_event_results_to_entities_deletion 
    1281:  [gw0][36m [ 51%] [0m[32mPASSED[0m port_ocean/tests/core/handlers/mixins/test_live_events.py::test_parse_raw_event_results_to_entities_deletion 
    1282:  port_ocean/tests/core/handlers/mixins/test_live_events.py::test_sync_raw_results_one_raw_result_entity_upserted 
    1283:  [gw0][36m [ 51%] [0m[32mPASSED[0m port_ocean/tests/core/handlers/mixins/test_live_events.py::test_sync_raw_results_one_raw_result_entity_upserted 
    1284:  port_ocean/tests/core/handlers/mixins/test_sync_raw.py::test_sync_raw_mixin_self_dependency 
    1285:  [gw0][36m [ 52%] [0m[32mPASSED[0m port_ocean/tests/core/handlers/mixins/test_sync_raw.py::test_sync_raw_mixin_self_dependency 
    1286:  port_ocean/tests/core/handlers/mixins/test_sync_raw.py::test_sync_raw_mixin_circular_dependency 
    1287:  [gw0][36m [ 52%] [0m[32mPASSED[0m port_ocean/tests/core/handlers/mixins/test_sync_raw.py::test_sync_raw_mixin_circular_dependency 
    1288:  port_ocean/tests/core/handlers/mixins/test_sync_raw.py::test_sync_raw_mixin_dependency 
    1289:  [gw0][36m [ 53%] [0m[32mPASSED[0m port_ocean/tests/core/handlers/mixins/test_sync_raw.py::test_sync_raw_mixin_dependency 
    1290:  port_ocean/tests/core/handlers/mixins/test_sync_raw.py::test_register_raw 
    1291:  [gw0][36m [ 54%] [0m[32mPASSED[0m port_ocean/tests/core/handlers/mixins/test_sync_raw.py::test_register_raw 
    1292:  port_ocean/tests/core/handlers/port_app_config/test_api.py::test_get_port_app_config_empty_config_raises_value_error 
    1293:  [gw0][36m [ 54%] [0m[32mPASSED[0m port_ocean/tests/core/handlers/port_app_config/test_api.py::test_get_port_app_config_empty_config_raises_value_error 
    1294:  port_ocean/tests/core/handlers/port_app_config/test_api.py::test_get_port_app_config_missing_config_key_raises_key_error 
    1295:  [gw0][36m [ 55%] [0m[32mPASSED[0m port_ocean/tests/core/handlers/port_app_config/test_api.py::test_get_port_app_config_missing_config_key_raises_key_error 
    1296:  port_ocean/tests/core/handlers/port_app_config/test_api.py::test_get_port_app_config_empty_integration_raises_key_error 
    1297:  [gw0][36m [ 55%] [0m[32mPASSED[0m port_ocean/tests/core/handlers/port_app_config/test_api.py::test_get_port_app_config_empty_integration_raises_key_error 
    1298:  port_ocean/tests/core/handlers/port_app_config/test_base.py::test_get_port_app_config_success 
    1299:  [gw0][36m [ 56%] [0m[32mPASSED[0m port_ocean/tests/core/handlers/port_app_config/test_base.py::test_get_port_app_config_success 
    1300:  port_ocean/tests/core/handlers/port_app_config/test_base.py::test_get_port_app_config_get_entity_deletion_threshold_with_flag_defined 
    1301:  [gw0][36m [ 56%] [0m[32mPASSED[0m port_ocean/tests/core/handlers/port_app_config/test_base.py::test_get_port_app_config_get_entity_deletion_threshold_with_flag_defined 
    1302:  port_ocean/tests/core/handlers/port_app_config/test_base.py::test_get_port_app_config_get_entity_deletion_threshold_with_flag_not_defined 
    1303:  [gw0][36m [ 57%] [0m[32mPASSED[0m port_ocean/tests/core/handlers/port_app_config/test_base.py::test_get_port_app_config_get_entity_deletion_threshold_with_flag_not_defined 
    1304:  port_ocean/tests/core/handlers/port_app_config/test_base.py::test_get_port_app_config_uses_cache 
    1305:  [gw0][36m [ 58%] [0m[32mPASSED[0m port_ocean/tests/core/handlers/port_app_config/test_base.py::test_get_port_app_config_uses_cache 
    1306:  port_ocean/tests/core/handlers/port_app_config/test_base.py::test_get_port_app_config_bypass_cache 
    1307:  [gw0][36m [ 58%] [0m[32mPASSED[0m port_ocean/tests/core/handlers/port_app_config/test_base.py::test_get_port_app_config_bypass_cache 
    1308:  port_ocean/tests/core/handlers/port_app_config/test_base.py::test_get_port_app_config_validation_error 
    1309:  [gw0][36m [ 59%] [0m[32mPASSED[0m port_ocean/tests/core/handlers/port_app_config/test_base.py::test_get_port_app_config_validation_error 
    1310:  port_ocean/tests/core/handlers/port_app_config/test_base.py::test_get_port_app_config_fetch_error 
    1311:  [gw0][36m [ 59%] [0m[32mPASSED[0m port_ocean/tests/core/handlers/port_app_config/test_base.py::test_get_port_app_config_fetch_error 
    1312:  port_ocean/tests/core/handlers/queue/test_local_queue.py::TestLocalQueue::test_basic_queue_operations 
    1313:  [gw0][36m [ 60%] [0m[32mPASSED[0m port_ocean/tests/core/handlers/queue/test_local_queue.py::TestLocalQueue::test_basic_queue_operations 
    1314:  port_ocean/tests/core/handlers/queue/test_local_queue.py::TestLocalQueue::test_fifo_order 
    1315:  [gw0][36m [ 60%] [0m[32mPASSED[0m port_ocean/tests/core/handlers/queue/test_local_queue.py::TestLocalQueue::test_fifo_order 
    1316:  port_ocean/tests/core/handlers/queue/test_local_queue.py::TestLocalQueue::test_wait_for_completion 
    1317:  [gw0][36m [ 61%] [0m[32mPASSED[0m port_ocean/tests/core/handlers/queue/test_local_queue.py::TestLocalQueue::test_wait_for_completion 
    1318:  port_ocean/tests/core/test_utils.py::TestValidateIntegrationRuntime::test_runtime_installation_compatibility[Runtime.OnPrem-SaasCloud-False] 
    1319:  [gw0][36m [ 62%] [0m[32mPASSED[0m port_ocean/tests/core/test_utils.py::TestValidateIntegrationRuntime::test_runtime_installation_compatibility[Runtime.OnPrem-SaasCloud-False] 
    1320:  port_ocean/tests/core/utils/test_entity_topological_sorter.py::test_handle_failed_with_dependencies 
    1321:  [gw0][36m [ 62%] [0m[32mPASSED[0m port_ocean/tests/core/utils/test_entity_topological_sorter.py::test_handle_failed_with_dependencies 
    1322:  port_ocean/tests/core/utils/test_entity_topological_sorter.py::test_handle_failed_with_self_dependencies 
    1323:  [gw0][36m [ 63%] [0m[32mPASSED[0m port_ocean/tests/core/utils/test_entity_topological_sorter.py::test_handle_failed_with_self_dependencies 
    1324:  port_ocean/tests/core/utils/test_entity_topological_sorter.py::test_handle_failed_with_circular_dependencies 
    1325:  [gw0][36m [ 63%] [0m[32mPASSED[0m port_ocean/tests/core/utils/test_entity_topological_sorter.py::test_handle_failed_with_circular_dependencies 
    1326:  port_ocean/tests/core/utils/test_resolve_entities_diff.py::test_are_entities_fields_equal_identical_properties_should_be_true 
    ...
    
    1399:  [gw0][36m [ 85%] [0m[32mPASSED[0m port_ocean/tests/log/test_handlers.py::test_serialize_record_exc_info_group_exception 
    1400:  port_ocean/tests/test_metric.py::test_metrics 
    1401:  [gw0][36m [ 85%] [0m[33mSKIPPED[0m port_ocean/tests/test_metric.py::test_metrics 
    1402:  port_ocean/tests/test_ocean.py::test_load_external_oauth_access_token_no_file 
    1403:  [gw0][36m [ 86%] [0m[32mPASSED[0m port_ocean/tests/test_ocean.py::test_load_external_oauth_access_token_no_file 
    1404:  port_ocean/tests/test_ocean.py::test_load_external_oauth_access_token_with_file 
    1405:  [gw0][36m [ 86%] [0m[32mPASSED[0m port_ocean/tests/test_ocean.py::test_load_external_oauth_access_token_with_file 
    1406:  port_ocean/tests/test_ocean.py::test_load_external_oauth_access_token_with_empty_file 
    1407:  [gw0][36m [ 87%] [0m[32mPASSED[0m port_ocean/tests/test_ocean.py::test_load_external_oauth_access_token_with_empty_file 
    1408:  port_ocean/tests/utils/test_async_iterators.py::test_semaphore_async_iterator 
    1409:  [gw0][36m [ 87%] [0m[32mPASSED[0m port_ocean/tests/utils/test_async_iterators.py::test_semaphore_async_iterator 
    1410:  port_ocean/tests/utils/test_cache.py::test_cache_iterator_result 
    1411:  [gw0][36m [ 88%] [0m[32mPASSED[0m port_ocean/tests/utils/test_cache.py::test_cache_iterator_result 
    1412:  port_ocean/tests/utils/test_cache.py::test_cache_iterator_result_with_kwargs 
    1413:  [gw0][36m [ 89%] [0m[32mPASSED[0m port_ocean/tests/utils/test_cache.py::test_cache_iterator_result_with_kwargs 
    1414:  port_ocean/tests/utils/test_cache.py::test_cache_iterator_result_cache_errors 
    1415:  [gw0][36m [ 89%] [0m[32mPASSED[0m port_ocean/tests/utils/test_cache.py::test_cache_iterator_result_cache_errors 
    1416:  port_ocean/tests/utils/test_cache.py::test_cache_coroutine_result 
    1417:  [gw0][36m [ 90%] [0m[32mPASSED[0m port_ocean/tests/utils/test_cache.py::test_cache_coroutine_result 
    1418:  port_ocean/tests/utils/test_cache.py::test_cache_coroutine_result_with_kwargs 
    1419:  [gw0][36m [ 90%] [0m[32mPASSED[0m port_ocean/tests/utils/test_cache.py::test_cache_coroutine_result_with_kwargs 
    1420:  port_ocean/tests/utils/test_cache.py::test_cache_coroutine_result_cache_errors 
    1421:  [gw0][36m [ 91%] [0m[32mPASSED[0m port_ocean/tests/utils/test_cache.py::test_cache_coroutine_result_cache_errors 
    1422:  port_ocean/tests/utils/test_cache.py::test_cache_failures_dont_affect_execution 
    1423:  [gw0][36m [ 91%] [0m[32mPASSED[0m port_ocean/tests/utils/test_cache.py::test_cache_failures_dont_affect_execution 
    1424:  [gw1][36m [ 92%] [0m[32mPASSED[0m port_ocean/tests/core/handlers/webhook/test_processor_manager.py::test_integrationTest_postRequestSent_webhookEventRawResultProcessedwithRetry_exceededMaxRetries_entityNotUpserted 
    ...
    
    1436:  [gw1][36m [ 95%] [0m[32mPASSED[0m port_ocean/tests/core/test_utils.py::TestValidateIntegrationRuntime::test_validate_integration_runtime[Runtime.Saas-Saas-False] 
    1437:  port_ocean/tests/core/test_utils.py::TestValidateIntegrationRuntime::test_validate_integration_runtime[Runtime.Saas-SaasOauth2-False] 
    1438:  [gw1][36m [ 96%] [0m[32mPASSED[0m port_ocean/tests/core/test_utils.py::TestValidateIntegrationRuntime::test_validate_integration_runtime[Runtime.Saas-SaasOauth2-False] 
    1439:  port_ocean/tests/core/test_utils.py::TestValidateIntegrationRuntime::test_validate_integration_runtime[Runtime.Saas-OnPrem-True] 
    1440:  [gw1][36m [ 97%] [0m[32mPASSED[0m port_ocean/tests/core/test_utils.py::TestValidateIntegrationRuntime::test_validate_integration_runtime[Runtime.Saas-OnPrem-True] 
    1441:  port_ocean/tests/core/test_utils.py::TestValidateIntegrationRuntime::test_validate_integration_runtime[Runtime.OnPrem-OnPrem-False] 
    1442:  [gw1][36m [ 97%] [0m[32mPASSED[0m port_ocean/tests/core/test_utils.py::TestValidateIntegrationRuntime::test_validate_integration_runtime[Runtime.OnPrem-OnPrem-False] 
    1443:  port_ocean/tests/core/test_utils.py::TestValidateIntegrationRuntime::test_validate_integration_runtime[Runtime.OnPrem-SaasOauth2-True] 
    1444:  [gw1][36m [ 98%] [0m[32mPASSED[0m port_ocean/tests/core/test_utils.py::TestValidateIntegrationRuntime::test_validate_integration_runtime[Runtime.OnPrem-SaasOauth2-True] 
    1445:  port_ocean/tests/core/test_utils.py::TestValidateIntegrationRuntime::test_runtime_installation_compatibility[Runtime.Saas-SaasOauth2-True] 
    1446:  [gw1][36m [ 98%] [0m[32mPASSED[0m port_ocean/tests/core/test_utils.py::TestValidateIntegrationRuntime::test_runtime_installation_compatibility[Runtime.Saas-SaasOauth2-True] 
    1447:  port_ocean/tests/core/test_utils.py::TestValidateIntegrationRuntime::test_runtime_installation_compatibility[Runtime.Saas-OnPrem-False] 
    1448:  [gw1][36m [ 99%] [0m[32mPASSED[0m port_ocean/tests/core/test_utils.py::TestValidateIntegrationRuntime::test_runtime_installation_compatibility[Runtime.Saas-OnPrem-False] 
    1449:  port_ocean/tests/core/test_utils.py::TestValidateIntegrationRuntime::test_runtime_installation_compatibility[Runtime.OnPrem-OnPrem-True] 
    1450:  [gw1][36m [100%] [0m[32mPASSED[0m port_ocean/tests/core/test_utils.py::TestValidateIntegrationRuntime::test_runtime_installation_compatibility[Runtime.OnPrem-OnPrem-True] 
    1451:  =================================== FAILURES ===================================
    1452:  [31m[1m________________________ test_applier_with_mock_context ________________________[0m
    ...
    
    1480:  [96msetattr[39;49;00m(mock_ocean.port_client, [33m"[39;49;00m[33mupsert_entities_batch[39;49;00m[33m"[39;49;00m, mock_upsert)[90m[39;49;00m
    1481:  [90m[39;49;00m
    1482:  result = [94mawait[39;49;00m applier.upsert([entity], UserAgentType.exporter)[90m[39;49;00m
    1483:  >           mock_upsert.assert_called_once()[90m[39;49;00m
    1484:  [1m[31mport_ocean/tests/core/handlers/entities_state_applier/test_applier.py[0m:148: 
    1485:  _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
    1486:  self = <AsyncMock id='139744393684960'>
    1487:  [0m[94mdef[39;49;00m[90m [39;49;00m[92massert_called_once[39;49;00m([96mself[39;49;00m):[90m[39;49;00m
    1488:  [90m    [39;49;00m[33m"""assert that the mock was called only once.[39;49;00m
    1489:  [33m    """[39;49;00m[90m[39;49;00m
    1490:  [94mif[39;49;00m [95mnot[39;49;00m [96mself[39;49;00m.call_count == [94m1[39;49;00m:[90m[39;49;00m
    1491:  msg = ([33m"[39;49;00m[33mExpected [39;49;00m[33m'[39;49;00m[33m%s[39;49;00m[33m'[39;49;00m[33m to have been called once. Called [39;49;00m[33m%s[39;49;00m[33m times.[39;49;00m[33m%s[39;49;00m[33m"[39;49;00m[90m[39;49;00m
    1492:  % ([96mself[39;49;00m._mock_name [95mor[39;49;00m [33m'[39;49;00m[33mmock[39;49;00m[33m'[39;49;00m,[90m[39;49;00m
    1493:  [96mself[39;49;00m.call_count,[90m[39;49;00m
    1494:  [96mself[39;49;00m._calls_repr()))[90m[39;49;00m
    1495:  >           [94mraise[39;49;00m [96mAssertionError[39;49;00m(msg)[90m[39;49;00m
    1496:  [1m[31mE           AssertionError: Expected 'mock' to have been called once. Called 0 times.[0m
    1497:  [1m[31m/opt/hostedtoolcache/Python/3.12.10/x64/lib/python3.12/unittest/mock.py[0m:928: AssertionError
    1498:  ----------------------------- Captured stderr call -----------------------------
    1499:  2025-05-29 10:51:59.946 | INFO     | port_ocean.context.event:event_context:178 - Event started
    1500:  2025-05-29 10:51:59.947 | INFO     | port_ocean.core.handlers.entities_state_applier.port.applier:upsert:126 - Upserting 1 entities
    1501:  2025-05-29 10:51:59.947 | DEBUG    | port_ocean.clients.port.mixins.entities:upsert_entities_bulk:203 - Upserting 1 of blueprint: test_blueprint
    1502:  2025-05-29 10:51:59.949 | ERROR    | port_ocean.context.event:event_context:193 - Event failed with error: AssertionError("Expected 'mock' to have been called once. Called 0 times.")
    1503:  2025-05-29 10:51:59.949 | INFO     | port_ocean.context.event:event_context:203 - Event finished
    ...
    
    1527:  [90m[39;49;00m
    1528:  result = [94mawait[39;49;00m applier.upsert([entity], UserAgentType.exporter)[90m[39;49;00m
    1529:  [90m[39;49;00m
    1530:  >           mock_upsert.assert_called_once()[90m[39;49;00m
    1531:  [1m[31mport_ocean/tests/core/handlers/entities_state_applier/test_applier.py[0m:174: 
    1532:  _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
    1533:  self = <AsyncMock id='139744391911312'>
    1534:  [0m[94mdef[39;49;00m[90m [39;49;00m[92massert_called_once[39;49;00m([96mself[39;49;00m):[90m[39;49;00m
    1535:  [90m    [39;49;00m[33m"""assert that the mock was called only once.[39;49;00m
    1536:  [33m    """[39;49;00m[90m[39;49;00m
    1537:  [94mif[39;49;00m [95mnot[39;49;00m [96mself[39;49;00m.call_count == [94m1[39;49;00m:[90m[39;49;00m
    1538:  msg = ([33m"[39;49;00m[33mExpected [39;49;00m[33m'[39;49;00m[33m%s[39;49;00m[33m'[39;49;00m[33m to have been called once. Called [39;49;00m[33m%s[39;49;00m[33m times.[39;49;00m[33m%s[39;49;00m[33m"[39;49;00m[90m[39;49;00m
    1539:  % ([96mself[39;49;00m._mock_name [95mor[39;49;00m [33m'[39;49;00m[33mmock[39;49;00m[33m'[39;49;00m,[90m[39;49;00m
    1540:  [96mself[39;49;00m.call_count,[90m[39;49;00m
    1541:  [96mself[39;49;00m._calls_repr()))[90m[39;49;00m
    1542:  >           [94mraise[39;49;00m [96mAssertionError[39;49;00m(msg)[90m[39;49;00m
    1543:  [1m[31mE           AssertionError: Expected 'mock' to have been called once. Called 0 times.[0m
    1544:  [1m[31m/opt/hostedtoolcache/Python/3.12.10/x64/lib/python3.12/unittest/mock.py[0m:928: AssertionError
    1545:  ----------------------------- Captured stderr call -----------------------------
    1546:  2025-05-29 10:52:00.037 | INFO     | port_ocean.context.event:event_context:178 - Event started
    1547:  2025-05-29 10:52:00.038 | INFO     | port_ocean.core.handlers.entities_state_applier.port.applier:upsert:126 - Upserting 1 entities
    1548:  2025-05-29 10:52:00.039 | DEBUG    | port_ocean.clients.port.mixins.entities:upsert_entities_bulk:203 - Upserting 1 of blueprint: test_blueprint
    1549:  2025-05-29 10:52:00.040 | ERROR    | port_ocean.context.event:event_context:193 - Event failed with error: AssertionError("Expected 'mock' to have been called once. Called 0 times.")
    1550:  2025-05-29 10:52:00.040 | INFO     | port_ocean.context.event:event_context:203 - Event finished
    1551:  [31m[1m_________________________ test_applier_error_upserting _________________________[0m
    1552:  [gw1] linux -- Python 3.12.10 /home/runner/work/ocean/ocean/.venv/bin/python
    1553:  mock_ocean = <port_ocean.ocean.Ocean object at 0x7f18c6e14920>
    1554:  mock_context = <port_ocean.context.ocean.PortOceanContext object at 0x7f18c6ea23f0>
    1555:  mock_port_app_config = PortAppConfig(enable_merge_entity=True, delete_dependent_entities=True, create_missing_related_entities=False, entity_...itle='.name', blueprint='"service"', team=None, properties={'url': '.web_url'}, relations={})), items_to_parse=None))])
    1556:  [0m[37m@pytest[39;49;00m.mark.asyncio[90m[39;49;00m
    1557:  [94masync[39;49;00m [94mdef[39;49;00m[90m [39;49;00m[92mtest_applier_error_upserting[39;49;00m([90m[39;49;00m
    1558:  mock_ocean: Ocean,[90m[39;49;00m
    ...
    
    1573:  [96msetattr[39;49;00m(mock_ocean.port_client, [33m"[39;49;00m[33mupsert_entities_batch[39;49;00m[33m"[39;49;00m, mock_upsert)[90m[39;49;00m
    1574:  [90m[39;49;00m
    1575:  result = [94mawait[39;49;00m applier.upsert([entity], UserAgentType.exporter)[90m[39;49;00m
    1576:  >           mock_upsert.assert_called_once()[90m[39;49;00m
    1577:  [1m[31mport_ocean/tests/core/handlers/entities_state_applier/test_applier.py[0m:199: 
    1578:  _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
    1579:  self = <AsyncMock id='139744392607216'>
    1580:  [0m[94mdef[39;49;00m[90m [39;49;00m[92massert_called_once[39;49;00m([96mself[39;49;00m):[90m[39;49;00m
    1581:  [90m    [39;49;00m[33m"""assert that the mock was called only once.[39;49;00m
    1582:  [33m    """[39;49;00m[90m[39;49;00m
    1583:  [94mif[39;49;00m [95mnot[39;49;00m [96mself[39;49;00m.call_count == [94m1[39;49;00m:[90m[39;49;00m
    1584:  msg = ([33m"[39;49;00m[33mExpected [39;49;00m[33m'[39;49;00m[33m%s[39;49;00m[33m'[39;49;00m[33m to have been called once. Called [39;49;00m[33m%s[39;49;00m[33m times.[39;49;00m[33m%s[39;49;00m[33m"[39;49;00m[90m[39;49;00m
    1585:  % ([96mself[39;49;00m._mock_name [95mor[39;49;00m [33m'[39;49;00m[33mmock[39;49;00m[33m'[39;49;00m,[90m[39;49;00m
    1586:  [96mself[39;49;00m.call_count,[90m[39;49;00m
    1587:  [96mself[39;49;00m._calls_repr()))[90m[39;49;00m
    1588:  >           [94mraise[39;49;00m [96mAssertionError[39;49;00m(msg)[90m[39;49;00m
    1589:  [1m[31mE           AssertionError: Expected 'mock' to have been called once. Called 0 times.[0m
    1590:  [1m[31m/opt/hostedtoolcache/Python/3.12.10/x64/lib/python3.12/unittest/mock.py[0m:928: AssertionError
    1591:  ----------------------------- Captured stderr call -----------------------------
    1592:  2025-05-29 10:52:00.149 | INFO     | port_ocean.context.event:event_context:178 - Event started
    1593:  2025-05-29 10:52:00.149 | INFO     | port_ocean.core.handlers.entities_state_applier.port.applier:upsert:126 - Upserting 1 entities
    1594:  2025-05-29 10:52:00.150 | DEBUG    | port_ocean.clients.port.mixins.entities:upsert_entities_bulk:203 - Upserting 1 of blueprint: test_blueprint
    1595:  2025-05-29 10:52:00.151 | ERROR    | port_ocean.context.event:event_context:193 - Event failed with error: AssertionError("Expected 'mock' to have been called once. Called 0 times.")
    1596:  2025-05-29 10:52:00.151 | INFO     | port_ocean.context.event:event_context:203 - Event finished
    ...
    
    1599:  mock_ocean = <port_ocean.ocean.Ocean object at 0x7f18c6d3deb0>
    1600:  mock_context = <port_ocean.context.ocean.PortOceanContext object at 0x7f18c6d6c4a0>
    1601:  mock_port_app_config = PortAppConfig(enable_merge_entity=True, delete_dependent_entities=True, create_missing_related_entities=False, entity_...itle='.name', blueprint='"service"', team=None, properties={'url': '.web_url'}, relations={})), items_to_parse=None))])
    1602:  [0m[37m@pytest[39;49;00m.mark.asyncio[90m[39;49;00m
    1603:  [94masync[39;49;00m [94mdef[39;49;00m[90m [39;49;00m[92mtest_using_create_entity_helper[39;49;00m([90m[39;49;00m
    1604:  mock_ocean: Ocean,[90m[39;49;00m
    1605:  mock_context: PortOceanContext,[90m[39;49;00m
    1606:  mock_port_app_config: PortAppConfig,[90m[39;49;00m
    1607:  ) -> [94mNone[39;49;00m:[90m[39;49;00m
    1608:  applier = HttpEntitiesStateApplier(mock_context)[90m[39;49;00m
    1609:  entity1 = create_entity([33m"[39;49;00m[33mentity1[39;49;00m[33m"[39;49;00m, [33m"[39;49;00m[33mservice[39;49;00m[33m"[39;49;00m, {[33m"[39;49;00m[33mrelated_to[39;49;00m[33m"[39;49;00m: [33m"[39;49;00m[33mentity2[39;49;00m[33m"[39;49;00m}, [94mFalse[39;49;00m)[90m[39;49;00m
    1610:  [90m[39;49;00m
    1611:  [94massert[39;49;00m entity1.identifier == [33m"[39;49;00m[33mentity1[39;49;00m[33m"[39;49;00m[90m[39;49;00m
    1612:  [94massert[39;49;00m entity1.blueprint == [33m"[39;49;00m[33mservice[39;49;00m[33m"[39;49;00m[90m[39;49;00m
    1613:  [94massert[39;49;00m entity1.relations == {[33m"[39;49;00m[33mrelated_to[39;49;00m[33m"[39;49;00m: [33m"[39;49;00m[33mentity2[39;49;00m[33m"[39;49;00m}[90m[39;49;00m
    1614:  [94massert[39;49;00m entity1.properties == {[33m"[39;49;00m[33mmock_is_to_fail[39;49;00m[33m"[39;49;00m: [94mFalse[39;49;00m}[90m[39;49;00m
    1615:  [90m[39;49;00m
    ...
    
    1624:  [90m[39;49;00m
    1625:  result = [94mawait[39;49;00m applier.upsert([entity1], UserAgentType.exporter)[90m[39;49;00m
    1626:  [90m[39;49;00m
    1627:  >           mock_upsert.assert_called_once()[90m[39;49;00m
    1628:  [1m[31mport_ocean/tests/core/handlers/entities_state_applier/test_applier.py[0m:229: 
    1629:  _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
    1630:  self = <AsyncMock id='139744392039600'>
    1631:  [0m[94mdef[39;49;00m[90m [39;49;00m[92massert_called_once[39;49;00m([96mself[39;49;00m):[90m[39;49;00m
    1632:  [90m    [39;49;00m[33m"""assert that the mock was called only once.[39;49;00m
    1633:  [33m    """[39;49;00m[90m[39;49;00m
    1634:  [94mif[39;49;00m [95mnot[39;49;00m [96mself[39;49;00m.call_count == [94m1[39;49;00m:[90m[39;49;00m
    1635:  msg = ([33m"[39;49;00m[33mExpected [39;49;00m[33m'[39;49;00m[33m%s[39;49;00m[33m'[39;49;00m[33m to have been called once. Called [39;49;00m[33m%s[39;49;00m[33m times.[39;49;00m[33m%s[39;49;00m[33m"[39;49;00m[90m[39;49;00m
    1636:  % ([96mself[39;49;00m._mock_name [95mor[39;49;00m [33m'[39;49;00m[33mmock[39;49;00m[33m'[39;49;00m,[90m[39;49;00m
    1637:  [96mself[39;49;00m.call_count,[90m[39;49;00m
    1638:  [96mself[39;49;00m._calls_repr()))[90m[39;49;00m
    1639:  >           [94mraise[39;49;00m [96mAssertionError[39;49;00m(msg)[90m[39;49;00m
    1640:  [1m[31mE           AssertionError: Expected 'mock' to have been called once. Called 0 times.[0m
    1641:  [1m[31m/opt/hostedtoolcache/Python/3.12.10/x64/lib/python3.12/unittest/mock.py[0m:928: AssertionError
    1642:  ----------------------------- Captured stderr call -----------------------------
    1643:  2025-05-29 10:52:00.247 | INFO     | port_ocean.context.event:event_context:178 - Event started
    1644:  2025-05-29 10:52:00.247 | INFO     | port_ocean.core.handlers.entities_state_applier.port.applier:upsert:126 - Upserting 1 entities
    1645:  2025-05-29 10:52:00.248 | DEBUG    | port_ocean.clients.port.mixins.entities:upsert_entities_bulk:203 - Upserting 1 of blueprint: service
    1646:  2025-05-29 10:52:00.249 | ERROR    | port_ocean.context.event:event_context:193 - Event failed with error: AssertionError("Expected 'mock' to have been called once. Called 0 times.")
    1647:  2025-05-29 10:52:00.250 | INFO     | port_ocean.context.event:event_context:203 - Event finished
    ...
    
    1654:  port_ocean/tests/log/test_handlers.py::test_serialize_record_exc_info_single_exception
    1655:  port_ocean/tests/log/test_handlers.py::test_serialize_record_exc_info_group_exception
    1656:  /home/runner/work/ocean/ocean/port_ocean/log/handlers.py:26: DeprecationWarning: datetime.datetime.utcfromtimestamp() is deprecated and scheduled for removal in a future version. Use timezone-aware objects to represent datetimes in UTC: datetime.datetime.fromtimestamp(timestamp, datetime.UTC).
    1657:  "timestamp": datetime.utcfromtimestamp(record.created).strftime(
    1658:  -- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
    1659:  - generated xml file: /home/runner/work/ocean/ocean/junit/unit-test-results-ocean/core.xml -
    1660:  ============================= slowest 10 durations =============================
    1661:  19.38s call     port_ocean/tests/core/handlers/entity_processor/test_jq_entity_processor.py::TestJQEntityProcessor::test_parse_items_performance_10000
    1662:  14.03s call     port_ocean/tests/core/handlers/webhook/test_processor_manager.py::test_integrationTest_postRequestSent_webhookEventRawResultProcessedwithRetry_exceededMaxRetries_entityNotUpserted
    1663:  6.01s call     port_ocean/tests/core/handlers/webhook/test_processor_manager.py::test_processWebhookRequest_retryTwoTimesThenSuccessfulProcessing
    1664:  2.05s call     port_ocean/tests/core/handlers/webhook/test_processor_manager.py::test_integrationTest_postRequestSent_reachedTimeout_entityNotUpserted
    1665:  2.03s call     port_ocean/tests/core/handlers/webhook/test_processor_manager.py::test_integrationTest_postRequestSent_webhookEventRawResultProcessedwithRetry_entityUpserted
    1666:  2.03s call     port_ocean/tests/core/handlers/entity_processor/test_jq_entity_processor.py::TestJQEntityProcessor::test_search_performance_10000
    1667:  2.00s call     port_ocean/tests/core/handlers/webhook/test_processor_manager.py::test_processWebhookRequest_maxRetriesExceeded_exceptionRaised
    1668:  1.00s call     port_ocean/tests/utils/test_cache.py::test_cache_iterator_result_with_kwargs
    1669:  0.80s call     port_ocean/tests/utils/test_cache.py::test_cache_failures_dont_affect_execution
    1670:  0.70s call     port_ocean/tests/utils/test_cache.py::test_cache_iterator_result
    1671:  [36m[1m=========================== short test summary info ============================[0m
    1672:  [31mFAILED[0m port_ocean/tests/core/handlers/entities_state_applier/test_applier.py::[1mtest_applier_with_mock_context[0m - AssertionError: Expected 'mock' to have been called once. Called 0 times.
    1673:  [31mFAILED[0m port_ocean/tests/core/handlers/entities_state_applier/test_applier.py::[1mtest_applier_one_not_upserted[0m - AssertionError: Expected 'mock' to have been called once. Called 0 times.
    1674:  [31mFAILED[0m port_ocean/tests/core/handlers/entities_state_applier/test_applier.py::[1mtest_applier_error_upserting[0m - AssertionError: Expected 'mock' to have been called once. Called 0 times.
    1675:  [31mFAILED[0m port_ocean/tests/core/handlers/entities_state_applier/test_applier.py::[1mtest_using_create_entity_helper[0m - AssertionError: Expected 'mock' to have been called once. Called 0 times.
    1676:  [31m============ [31m[1m4 failed[0m, [32m169 passed[0m, [33m1 skipped[0m, [33m5 warnings[0m[31m in 29.89s[0m[31m =============[0m
    1677:  make: *** [Makefile:123: test] Error 1
    1678:  ##[error]Process completed with exit code 2.
    1679:  ##[group]Run make smoke/clean
    ...
    
    1686:  Python2_ROOT_DIR: /opt/hostedtoolcache/Python/3.12.10/x64
    1687:  Python3_ROOT_DIR: /opt/hostedtoolcache/Python/3.12.10/x64
    1688:  LD_LIBRARY_PATH: /opt/hostedtoolcache/Python/3.12.10/x64/lib
    1689:  PYTEST_ADDOPTS: --cov --cov-report= --cov-append --junitxml=junit/smoke-test-results-ocean/core.xml
    1690:  PORT_CLIENT_ID: ***
    1691:  PORT_CLIENT_SECRET: ***
    1692:  PORT_BASE_URL: ***
    1693:  SMOKE_TEST_SUFFIX: 15322200608
    1694:  ##[endgroup]
    1695:  /home/runner/work/ocean/ocean/./scripts/clean-smoke-test.py:10: DeprecationWarning: There is no current event loop
    1696:  asyncio.get_event_loop().run_until_complete(main())
    1697:  [32m2025-05-29 10:52:28.163[0m | [1mINFO    [0m | [36mport_ocean.tests.helpers.smoke_test[0m:[36mcleanup_smoke_test[0m:[36m56[0m - [1mCleaning up fake integration[0m
    1698:  [32m2025-05-29 10:52:28.163[0m | [1mINFO    [0m | [36mport_ocean.clients.port.mixins.blueprints[0m:[36mget_blueprint[0m:[36m20[0m - [1mFetching blueprint with id: fake-department-15322200608[0m
    1699:  [32m2025-05-29 10:52:28.187[0m | [1mINFO    [0m | [36mport_ocean.clients.port.authentication[0m:[36mtoken[0m:[36m85[0m - [1mNo token found, fetching new token[0m
    1700:  [32m2025-05-29 10:52:28.188[0m | [1mINFO    [0m | [36mport_ocean.clients.port.authentication[0m:[36m_get_token[0m:[36m49[0m - [1mFetching access token for clientId: ***[0m
    1701:  [32m2025-05-29 10:52:28.756[0m | [31m[1mERROR   [0m | [36mport_ocean.clients.port.utils[0m:[36mhandle_port_status_code[0m:[36m76[0m - [31m[1mRequest failed with status code: 404, Error: {"ok":false,"error":"not_found","message":"Blueprint with identifier \"fake-department-15322200608\" was not found","details":{"resource":"Blueprint","byField":"identifier","withValue":"fake-department-15322200608"}}[0m
    1702:  [32m2025-05-29 10:52:28.756[0m | [1mINFO    [0m | [36mport_ocean.tests.helpers.integration[0m:[36mcleanup_integration[0m:[36m21[0m - [1mSkipping missing blueprint (fake-department-15322200608): Client error '404 Not Found' for url '***/v1/blueprints/fake-department-15322200608'
    1703:  For more information check: https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/404[0m
    1704:  [32m2025-05-29 10:52:28.756[0m | [1mINFO    [0m | [36mport_ocean.clients.port.mixins.blueprints[0m:[36mget_blueprint[0m:[36m20[0m - [1mFetching blueprint with id: fake-person-15322200608[0m
    1705:  [32m2025-05-29 10:52:28.889[0m | [31m[1mERROR   [0m | [36mport_ocean.clients.port.utils[0m:[36mhandle_port_status_code[0m:[36m76[0m - [31m[1mRequest failed with status code: 404, Error: {"ok":false,"error":"not_found","message":"Blueprint with identifier \"fake-person-15322200608\" was not found","details":{"resource":"Blueprint","byField":"identifier","withValue":"fake-person-15322200608"}}[0m
    1706:  [32m2025-05-29 10:52:28.889[0m | [1mINFO    [0m | [36mport_ocean.tests.helpers.integration[0m:[36mcleanup_integration[0m:[36m21[0m - [1mSkipping missing blueprint (fake-person-15322200608): Client error '404 Not Found' for url '***/v1/blueprints/fake-person-15322200608'
    1707:  For more information check: https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/404[0m
    ...
    
    1716:  Python2_ROOT_DIR: /opt/hostedtoolcache/Python/3.12.10/x64
    1717:  Python3_ROOT_DIR: /opt/hostedtoolcache/Python/3.12.10/x64
    1718:  LD_LIBRARY_PATH: /opt/hostedtoolcache/Python/3.12.10/x64/lib
    1719:  PYTEST_ADDOPTS: --cov --cov-report= --cov-append --junitxml=junit/smoke-test-results-ocean/core.xml
    1720:  PORT_CLIENT_ID: ***
    1721:  PORT_CLIENT_SECRET: ***
    1722:  PORT_BASE_URL: ***
    1723:  SMOKE_TEST_SUFFIX: 15322200608
    1724:  ##[endgroup]
    1725:  /home/runner/work/ocean/ocean/./scripts/clean-smoke-test.py:10: DeprecationWarning: There is no current event loop
    1726:  asyncio.get_event_loop().run_until_complete(main())
    1727:  [32m2025-05-29 10:52:29.531[0m | [1mINFO    [0m | [36mport_ocean.tests.helpers.smoke_test[0m:[36mcleanup_smoke_test[0m:[36m56[0m - [1mCleaning up fake integration[0m
    1728:  [32m2025-05-29 10:52:29.531[0m | [1mINFO    [0m | [36mport_ocean.clients.port.mixins.blueprints[0m:[36mget_blueprint[0m:[36m20[0m - [1mFetching blueprint with id: fake-department-15322200608[0m
    1729:  [32m2025-05-29 10:52:29.555[0m | [1mINFO    [0m | [36mport_ocean.clients.port.authentication[0m:[36mtoken[0m:[36m85[0m - [1mNo token found, fetching new token[0m
    1730:  [32m2025-05-29 10:52:29.555[0m | [1mINFO    [0m | [36mport_ocean.clients.port.authentication[0m:[36m_get_token[0m:[36m49[0m - [1mFetching access token for clientId: ***[0m
    1731:  [32m2025-05-29 10:52:30.109[0m | [31m[1mERROR   [0m | [36mport_ocean.clients.port.utils[0m:[36mhandle_port_status_code[0m:[36m76[0m - [31m[1mRequest failed with status code: 404, Error: {"ok":false,"error":"not_found","message":"Blueprint with identifier \"fake-department-15322200608\" was not found","details":{"resource":"Blueprint","byField":"identifier","withValue":"fake-department-15322200608"}}[0m
    1732:  [32m2025-05-29 10:52:30.109[0m | [1mINFO    [0m | [36mport_ocean.tests.helpers.integration[0m:[36mcleanup_integration[0m:[36m21[0m - [1mSkipping missing blueprint (fake-department-15322200608): Client error '404 Not Found' for url '***/v1/blueprints/fake-department-15322200608'
    1733:  For more information check: https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/404[0m
    1734:  [32m2025-05-29 10:52:30.109[0m | [1mINFO    [0m | [36mport_ocean.clients.port.mixins.blueprints[0m:[36mget_blueprint[0m:[36m20[0m - [1mFetching blueprint with id: fake-person-15322200608[0m
    1735:  [32m2025-05-29 10:52:30.212[0m | [31m[1mERROR   [0m | [36mport_ocean.clients.port.utils[0m:[36mhandle_port_status_code[0m:[36m76[0m - [31m[1mRequest failed with status code: 404, Error: {"ok":false,"error":"not_found","message":"Blueprint with identifier \"fake-person-15322200608\" was not found","details":{"resource":"Blueprint","byField":"identifier","withValue":"fake-person-15322200608"}}[0m
    1736:  [32m2025-05-29 10:52:30.212[0m | [1mINFO    [0m | [36mport_ocean.tests.helpers.integration[0m:[36mcleanup_integration[0m:[36m21[0m - [1mSkipping missing blueprint (fake-person-15322200608): Client error '404 Not Found' for url '***/v1/blueprints/fake-person-15322200608'
    1737:  For more information check: https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/404[0m
    1738:  [32m2025-05-29 10:52:30.338[0m | [1mINFO    [0m | [36mport_ocean.tests.helpers.smoke_test[0m:[36mcleanup_smoke_test[0m:[36m61[0m - [1mCleaning up fake integration complete[0m
    1739:  ##[group]Run mikepenz/action-junit-report@v5
    1740:  with:
    1741:  report_paths: **/junit/**-test-results-**/*.xml
    1742:  include_passed: true
    1743:  require_tests: true
    1744:  fail_on_failure: true
    1745:  token: ***
    1746:  group_reports: true
    1747:  annotate_only: false
    1748:  check_annotations: true
    1749:  update_check: false
    1750:  check_name: JUnit Test Report
    1751:  fail_on_parse_error: false
    1752:  require_passed_tests: false
    ...
    
    1779:  LD_LIBRARY_PATH: /opt/hostedtoolcache/Python/3.12.10/x64/lib
    1780:  ##[endgroup]
    1781:  ##[group]📘 Reading input values
    1782:  ##[endgroup]
    1783:  ##[group]📦 Process test results
    1784:  Preparing 1 report as configured.
    1785:  test_common:1 | test_custom_defaults_dir_used_if_valid0.089s
    1786:  test_disk_cache:1 | test_disk_cache_set_get0.086s
    1787:  test_disk_cache:1 | test_disk_cache_clear0.005s
    1788:  test_common:1 | test_fallback_to_default_dir_if_custom_dir_invalid0.004s
    1789:  test_disk_cache:1 | test_disk_cache_nonexistent_key0.002s
    1790:  test_disk_cache:1 | test_disk_cache_corrupted_file0.003s
    1791:  test_common:1 | test_default_resources_path_does_not_exist0.001s
    1792:  test_applier:1 | test_delete_diff_no_deleted_entities0.004s
    1793:  test_applier:1 | test_delete_diff_below_threshold0.009s
    1794:  test_disk_cache:1 | test_disk_cache_write_error0.002s
    1795:  test_memory_cache:1 | test_memory_cache_set_get0.002s
    1796:  test_memory_cache:1 | test_memory_cache_clear0.001s
    1797:  test_memory_cache:1 | test_memory_cache_nonexistent_key0.001s
    1798:  test_oauth_client:1 | test_oauth_client_initialization0.002s
    1799:  test_oauth_client:1 | test_oauth_client_disabled_initialization0.001s
    1800:  test_oauth_client:1 | test_refresh_request_auth_creds0.003s
    1801:  test_oauth_client:1 | test_access_token_property0.001s
    1802:  test_applier:1 | test_delete_diff_above_default_threshold0.007s
    1803:  test_applier:1 | test_delete_diff_custom_threshold_above_threshold_not_deleted0.008s
    1804:  test_entities:1 | test_calculate_entities_batch_size_empty_list0.01s
    1805:  test_applier:1 | test_delete_diff_custom_threshold_0_not_deleted0.007s
    1806:  test_entities:1 | test_calculate_entities_batch_size_small_entities0.004s
    1807:  test_entities:1 | test_calculate_entities_batch_size_large_entities0.006s
    1808:  port_ocean/tests/core/handlers/entities_state_applier/test_applier.py:148 | AssertionError: Expected 'mock' to have been called once. Called 0 times.0.011s
    1809:  test_entities:1 | test_calculate_entities_batch_size_mixed_entities0.003s
    1810:  test_entities:1 | test_calculate_entities_batch_size_single_large_entity0.01s
    1811:  test_entities:1 | test_batch_upsert_entities_read_timeout_should_raise_false0.004s
    1812:  test_entities:1 | test_batch_upsert_entities_read_timeout_should_raise_false_with_exception0.005s
    1813:  test_entities:1 | test_batch_upsert_entities_read_timeout_should_raise_true0.005s
    1814:  test_organization_mixin:1 | test_org_feature_flags_should_fetch_proper_json_path0.005s
    1815:  TestJQEntityProcessor:1 | test_search_as_object_failure0.003s
    1816:  TestJQEntityProcessor:1 | test_double_quotes_in_jq_expression0.006s
    1817:  TestJQEntityProcessor:1 | test_search_as_bool_failure0.008s
    1818:  TestJQEntityProcessor:1 | test_search_fails_on_stop_iteration[.parameters[] | select(.name == "not_exists") | .value-None]0.005s
    1819:  TestJQEntityProcessor:1 | test_search_fails_on_stop_iteration[.parameters[] | select(.name == "parameter_name") | .value-parameter_value]0.006s
    1820:  TestJQEntityProcessor:1 | test_search_fails_on_stop_iteration[.parameters[] | select(.name == "another_parameter") | .value-another_value]0.007s
    1821:  port_ocean/tests/core/handlers/entities_state_applier/test_applier.py:174 | AssertionError: Expected 'mock' to have been called once. Called 0 times.0.013s
    1822:  TestJQEntityProcessor:1 | test_return_a_list_of_values0.007s
    1823:  TestJQEntityProcessor:1 | test_search_performance_100002.031s
    1824:  port_ocean/tests/core/handlers/entities_state_applier/test_applier.py:199 | AssertionError: Expected 'mock' to have been called once. Called 0 times.0.01s
    1825:  port_ocean/tests/core/handlers/entities_state_applier/test_applier.py:229 | AssertionError: Expected 'mock' to have been called once. Called 0 times.0.011s
    1826:  TestJQEntityProcessor:1 | test_compile0.006s
    1827:  TestJQEntityProcessor:1 | test_search0.008s
    1828:  TestJQEntityProcessor:1 | test_search_as_bool0.006s
    1829:  TestJQEntityProcessor:1 | test_search_as_object0.006s
    1830:  TestJQEntityProcessor:1 | test_get_mapped_entity0.008s
    1831:  TestJQEntityProcessor:1 | test_calculate_entity0.009s
    1832:  TestJQEntityProcessor:1 | test_parse_items0.013s
    1833:  TestJQEntityProcessor:1 | test_in_operator0.006s
    1834:  TestJQEntityProcessor:1 | test_failure_of_jq_expression0.003s
    1835:  test_sync_raw:1 | test_unregister_raw0.061s
    1836:  test_sync_raw:1 | test_map_entities_compared_with_port_no_port_entities_all_entities_are_mapped0.009s
    1837:  test_sync_raw:1 | test_map_entities_compared_with_port_returns_original_entities_when_using_team_search_query0.009s
    1838:  test_sync_raw:1 | test_map_entities_compared_with_port_with_existing_entities_only_changed_third_party_entities_are_mapped0.01s
    1839:  test_sync_raw:1 | test_map_entities_compared_with_port_with_multiple_batches_all_batches_are_being_proccessed_to_map0.012s
    1840:  test_sync_raw:1 | test_register_resource_raw_no_changes_upsert_not_called_entitiy_is_returned0.01s
    1841:  test_sync_raw:1 | test_register_resource_raw_with_changes_upsert_called_and_entities_are_mapped0.011s
    1842:  test_sync_raw:1 | test_register_resource_raw_with_errors0.01s
    1843:  test_sync_raw:1 | test_register_resource_raw_skip_event_type_http_request_upsert_called_and_no_entitites_diff_calculation0.011s
    1844:  test_sync_raw:1 | test_on_resync_start_hooks_are_called0.016s
    1845:  test_sync_raw:1 | test_on_resync_complete_hooks_are_called_on_success0.014s
    1846:  test_sync_raw:1 | test_on_resync_complete_hooks_not_called_on_error0.012s
    1847:  test_sync_raw:1 | test_multiple_on_resync_start_on_resync_complete_hooks_called_in_order0.018s
    1848:  test_sync_raw:1 | test_on_resync_start_hook_error_prevents_resync0.013s
    1849:  test_api:1 | test_get_port_app_config_valid_config_returns_config0.004s
    1850:  test_abstract_webhook_processor:1 | test_init_finishedSuccessfully0.002s
    1851:  test_abstract_webhook_processor:1 | test_calculateRetryDelay_delayCalculatedCorrectly0.002s
    1852:  test_abstract_webhook_processor:1 | test_shouldRetry_returnsTrueOnRetryableError0.002s
    1853:  test_abstract_webhook_processor:1 | test_lifecycleHooks_callsCorrectly0.002s
    1854:  test_processor_manager:1 | test_extractMatchingProcessors_processorMatch0.008s
    1855:  test_processor_manager:1 | test_extractMatchingProcessors_noMatch0.005s
    1856:  test_processor_manager:1 | test_extractMatchingProcessors_multipleMatches0.004s
    1857:  test_processor_manager:1 | test_extractMatchingProcessors_onlyOneMatches0.004s
    1858:  test_processor_manager:1 | test_registerProcessor_registrationWorks0.002s
    1859:  test_processor_manager:1 | test_registerProcessor_multipleHandlers_allRegistered0.002s
    1860:  test_processor_manager:1 | test_registerProcessor_invalidHandlerRegistration_throwsError0.001s
    1861:  test_processor_manager:1 | test_processWebhookRequest_successfulProcessing0.002s
    ...
    
    1865:  test_processor_manager:1 | test_integrationTest_postRequestSent_webhookEventRawResultProcessed_entityUpserted0.147s
    1866:  test_processor_manager:1 | test_integrationTest_postRequestSent_reachedTimeout_entityNotUpserted2.055s
    1867:  test_processor_manager:1 | test_integrationTest_postRequestSent_noMatchingHandlers_entityNotUpserted0.018s
    1868:  test_processor_manager:1 | test_integrationTest_postRequestSent_webhookEventRawResultProcessedForMultipleProcessors_entitiesUpserted0.037s
    1869:  test_processor_manager:1 | test_integrationTest_postRequestSent_webhookEventRawResultProcessedwithRetry_entityUpserted2.034s
    1870:  test_processor_manager:1 | test_integrationTest_postRequestSent_webhookEventRawResultProcessedwithRetry_exceededMaxRetries_entityNotUpserted14.038s
    1871:  TestJQEntityProcessor:1 | test_parse_items_wrong_mapping0.021s
    1872:  TestJQEntityProcessor:1 | test_parse_items_empty_required0.021s
    1873:  test_live_events:1 | test_parse_raw_event_results_to_entities_creation0.004s
    1874:  test_live_events:1 | test_parse_raw_event_results_to_entities_deletion0.004s
    1875:  test_live_events:1 | test_sync_raw_results_one_raw_result_entity_upserted0.004s
    1876:  test_sync_raw:1 | test_sync_raw_mixin_self_dependency0.017s
    1877:  test_sync_raw:1 | test_sync_raw_mixin_circular_dependency0.013s
    1878:  test_sync_raw:1 | test_sync_raw_mixin_dependency0.015s
    1879:  test_sync_raw:1 | test_register_raw0.02s
    1880:  test_api:1 | test_get_port_app_config_empty_config_raises_value_error0.004s
    1881:  test_api:1 | test_get_port_app_config_missing_config_key_raises_key_error0.003s
    1882:  test_api:1 | test_get_port_app_config_empty_integration_raises_key_error0.003s
    1883:  test_base:1 | test_get_port_app_config_success0.004s
    1884:  test_base:1 | test_get_port_app_config_get_entity_deletion_threshold_with_flag_defined0.003s
    1885:  test_base:1 | test_get_port_app_config_get_entity_deletion_threshold_with_flag_not_defined0.003s
    1886:  test_base:1 | test_get_port_app_config_uses_cache0.004s
    1887:  test_base:1 | test_get_port_app_config_bypass_cache0.003s
    1888:  test_base:1 | test_get_port_app_config_validation_error0.005s
    1889:  test_base:1 | test_get_port_app_config_fetch_error0.003s
    1890:  TestLocalQueue:1 | test_basic_queue_operations0.002s
    1891:  TestLocalQueue:1 | test_fifo_order0.002s
    1892:  TestLocalQueue:1 | test_wait_for_completion0.604s
    1893:  TestValidateIntegrationRuntime:1 | test_runtime_installation_compatibility[Runtime.OnPrem-SaasCloud-False]0.001s
    1894:  test_entity_topological_sorter:1 | test_handle_failed_with_dependencies0.002s
    1895:  test_entity_topological_sorter:1 | test_handle_failed_with_self_dependencies0.002s
    1896:  test_entity_topological_sorter:1 | test_handle_failed_with_circular_dependencies0.001s
    1897:  test_resolve_entities_diff:1 | test_are_entities_fields_equal_identical_properties_should_be_true0.001s
    ...
    
    1926:  test_resolve_entities_diff:1 | test_resolve_entities_diff_modified_properties0.001s
    1927:  test_resolve_entities_diff:1 | test_resolve_entities_diff_modified_relations0.001s
    1928:  test_resolve_en...
    

    qodo-code-review[bot] avatar Apr 27 '25 14:04 qodo-code-review[bot]

    PR Reviewer Guide 🔍

    Here are some key observations to aid the review process:

    ⏱️ Estimated effort to review: 3 🔵🔵🔵⚪⚪
    🧪 PR contains tests
    🔒 No security concerns identified
    ⚡ Recommended focus areas for review

    Error Handling

    The error handling in upsert_entities_batch doesn't properly handle the response when it's an error. The code calls handle_status_code after already accessing response.json(), which could lead to unexpected behavior if the response isn't valid JSON.

    if response.is_error:
        logger.error(
            f"Error {'Validating' if validation_only else 'Upserting'} "
            f"{len(entities)} entities of "
            f"blueprint: {blueprint}"
        )
        result = response.json()
    handle_status_code(response, should_raise)
    
    Potential Bug

    The function upsert_entities_in_batches is filtering out entities with status=None, but these might be important to track for debugging or reporting purposes. Consider if this is the intended behavior.

    for status, entity in batch_results:
        if status is not None:  # Ignore None results
            batch_result: tuple[bool, Entity] = (bool(status), entity)
            entities_results.append(batch_result)
    

    qodo-code-review[bot] avatar Apr 27 '25 14:04 qodo-code-review[bot]

    PR Code Suggestions ✨

    Explore these optional code suggestions:

    CategorySuggestion                                                                                                                                    Impact
    Possible issue
    Fix error response handling
    Suggestion Impact:The commit implemented error handling for the case where the response is an error, but with a different approach. Instead of returning a list of failed entities, it returns an HTTPStatusError object and adds proper error handling logic.

    code diff:

    -            result = response.json()
    -        handle_status_code(response, should_raise)
    +            handle_port_status_code(response, should_raise)
    +            return httpx.HTTPStatusError(
    +                f"HTTP {response.status_code}",
    +                request=response.request,
    +                response=response,
    +            )
    +        handle_port_status_code(response, should_raise)
    

    The code is missing error handling for the case where the response is an error.
    In the error case, result is assigned but never used, and the code continues to
    process a potentially invalid response structure.

    port_ocean/clients/port/mixins/entities.py [167-175]

    +if response.is_error:
    +    logger.error(
    +        f"Error {'Validating' if validation_only else 'Upserting'} "
    +        f"{len(entities)} entities of "
    +        f"blueprint: {blueprint}"
    +    )
    +    result = response.json()
    +    handle_status_code(response, should_raise)
    +    return [(False, self._reduce_entity(entity)) for entity in entities]
    +
     result = response.json()
     index_to_entity = {i: entity for i, entity in enumerate(entities)}
     
     successful_entities = {
         entity_result["index"]: entity_result
         for entity_result in result.get("entities", [])
     }
     
     error_entities = {error["index"]: error for error in result.get("errors", [])}
    
    • [ ] Apply this suggestion
    Suggestion importance[1-10]: 8

    __

    Why: The suggestion correctly identifies a flaw in the error handling logic. If response.is_error is true and should_raise is false, the code currently proceeds to parse the response body (line 167) as if it were successful, which could lead to unexpected errors or incorrect results. The proposed fix ensures correct behavior by returning early in this scenario.

    Medium
    Handle empty input list
    Suggestion Impact:The commit implemented a similar check but in a different way. Instead of adding an early return for empty entities list in the upsert_entities_batch method, the commit modified the upsert_entities_in_batches method to require a blueprint parameter instead of extracting it from entities[0], thus avoiding the potential IndexError.

    code diff:

             self,
    +        blueprint: str,
             entities: list[Entity],
             request_options: RequestOptions,
             user_agent_type: UserAgentType | None = None,
    @@ -122,6 +184,7 @@
                                 should_raise=False,
                             )
             ```
    +        :param blueprint: The blueprint of the entities to be upserted
             :param entities: A list of Entities to be upserted
             :param request_options: A dictionary specifying how to upsert the entity
             :param user_agent_type: a UserAgentType specifying who is preforming the action
    @@ -132,7 +195,6 @@
             """
             validation_only = request_options["validation_only"]
             async with self.semaphore:
    -            blueprint = entities[0].blueprint
                 logger.debug(
                     f"{'Validating' if validation_only else 'Upserting'} {len(entities)} of blueprint: {blueprint}"
                 )
    

    The method should check if the entities list is empty before processing. Without
    this check, attempting to access entities[0].blueprint will cause an IndexError
    when the list is empty.

    port_ocean/clients/port/mixins/entities.py [106-112]

     async def upsert_entities_batch(
         self,
         entities: list[Entity],
         request_options: RequestOptions,
         user_agent_type: UserAgentType | None = None,
         should_raise: bool = True,
     ) -> list[tuple[bool | None, Entity]]:
    +    if not entities:
    +        return []
    
    • [ ] Apply this suggestion
    Suggestion importance[1-10]: 7

    __

    Why: The suggestion correctly identifies that accessing entities[0] on line 135 will raise an IndexError if the input entities list is empty. Adding the check improves the robustness of the new upsert_entities_batch function.

    Medium
    • [ ] Update

    qodo-code-review[bot] avatar Apr 27 '25 14:04 qodo-code-review[bot]

    This pull request is automatically being deployed by Amplify Hosting (learn more).

    Access this pull request here: https://pr-1598.d1ftd8v2gowp8w.amplifyapp.com

    Code Coverage Artifact 📈: https://github.com/port-labs/ocean/actions/runs/15237333138/artifacts/3192842356

    Code Coverage Total Percentage: 80.69%

    github-actions[bot] avatar May 25 '25 11:05 github-actions[bot]

    Code Coverage Artifact 📈: https://github.com/port-labs/ocean/actions/runs/15238498363/artifacts/3193102410

    Code Coverage Total Percentage: 80.68%

    github-actions[bot] avatar May 25 '25 13:05 github-actions[bot]

    Code Coverage Artifact 📈: https://github.com/port-labs/ocean/actions/runs/15238773170/artifacts/3193169629

    Code Coverage Total Percentage: 80.69%

    github-actions[bot] avatar May 25 '25 14:05 github-actions[bot]

    Code Coverage Artifact 📈: https://github.com/port-labs/ocean/actions/runs/15239163737/artifacts/3193264229

    Code Coverage Total Percentage: 80.55%

    github-actions[bot] avatar May 25 '25 15:05 github-actions[bot]

    Code Coverage Artifact 📈: https://github.com/port-labs/ocean/actions/runs/15249950295/artifacts/3195945649

    Code Coverage Total Percentage: 80.59%

    github-actions[bot] avatar May 26 '25 09:05 github-actions[bot]

    Code Coverage Artifact 📈: https://github.com/port-labs/ocean/actions/runs/15296405146/artifacts/3211220256

    Code Coverage Total Percentage: 80.67%

    github-actions[bot] avatar May 28 '25 09:05 github-actions[bot]

    Code Coverage Artifact 📈: https://github.com/port-labs/ocean/actions/runs/15302285435/artifacts/3213219345

    Code Coverage Total Percentage: 80.66%

    github-actions[bot] avatar May 28 '25 14:05 github-actions[bot]

    Code Coverage Artifact 📈: https://github.com/port-labs/ocean/actions/runs/15323211996/artifacts/3220334519

    Code Coverage Total Percentage: 81.29%

    github-actions[bot] avatar May 29 '25 12:05 github-actions[bot]

    Code Coverage Artifact 📈: https://github.com/port-labs/ocean/actions/runs/15323227342/artifacts/3220346460

    Code Coverage Total Percentage: 81.31%

    github-actions[bot] avatar May 29 '25 12:05 github-actions[bot]

    Code Coverage Artifact 📈: https://github.com/port-labs/ocean/actions/runs/15326515131/artifacts/3221553724

    Code Coverage Total Percentage: 81.44%

    github-actions[bot] avatar May 29 '25 14:05 github-actions[bot]

    Code Coverage Artifact 📈: https://github.com/port-labs/ocean/actions/runs/15411059941/artifacts/3247631121

    Code Coverage Total Percentage: 81.41%

    github-actions[bot] avatar Jun 03 '25 07:06 github-actions[bot]