port-ocean 0.28.17__tar.gz → 0.28.19__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.28.17 → port_ocean-0.28.19}/PKG-INFO +1 -1
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/core/integrations/mixins/utils.py +19 -16
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/helpers/retry.py +4 -46
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/log/logger_setup.py +2 -2
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/tests/helpers/test_retry.py +13 -395
- {port_ocean-0.28.17 → port_ocean-0.28.19}/pyproject.toml +1 -1
- {port_ocean-0.28.17 → port_ocean-0.28.19}/LICENSE.md +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/README.md +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/integrations/_infra/Dockerfile.Deb +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/integrations/_infra/Dockerfile.alpine +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/integrations/_infra/Dockerfile.base.builder +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/integrations/_infra/Dockerfile.base.runner +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/integrations/_infra/Dockerfile.dockerignore +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/integrations/_infra/Dockerfile.local +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/integrations/_infra/Makefile +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/integrations/_infra/README.md +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/integrations/_infra/entry_local.sh +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/integrations/_infra/grpcio.sh +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/integrations/_infra/init.sh +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/__init__.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/bootstrap.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/cache/__init__.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/cache/base.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/cache/disk.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/cache/errors.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/cache/memory.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/cli/__init__.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/cli/cli.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/cli/commands/__init__.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/cli/commands/defaults/__init___.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/cli/commands/defaults/clean.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/cli/commands/defaults/dock.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/cli/commands/defaults/group.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/cli/commands/list_integrations.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/cli/commands/main.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/cli/commands/new.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/cli/commands/pull.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/cli/commands/sail.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/cli/commands/version.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/cli/cookiecutter/__init__.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/cli/cookiecutter/cookiecutter.json +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/cli/cookiecutter/extensions.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/cli/cookiecutter/hooks/post_gen_project.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/.env.example +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/.gitignore +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/.port/resources/.gitignore +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/.port/resources/blueprints.json +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/.port/resources/port-app-config.yml +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/.port/spec.yaml +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/CHANGELOG.md +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/CONTRIBUTING.md +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/README.md +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/changelog/.gitignore +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/debug.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/main.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/poetry.toml +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/pyproject.toml +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/sonar-project.properties +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/tests/__init__.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/tests/test_sample.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/cli/utils.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/clients/__init__.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/clients/auth/__init__.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/clients/auth/auth_client.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/clients/auth/oauth_client.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/clients/port/__init__.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/clients/port/authentication.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/clients/port/client.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/clients/port/mixins/__init__.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/clients/port/mixins/blueprints.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/clients/port/mixins/entities.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/clients/port/mixins/integrations.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/clients/port/mixins/migrations.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/clients/port/mixins/organization.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/clients/port/retry_transport.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/clients/port/types.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/clients/port/utils.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/config/__init__.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/config/base.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/config/dynamic.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/config/settings.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/consumers/__init__.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/consumers/kafka_consumer.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/context/__init__.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/context/event.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/context/metric_resource.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/context/ocean.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/context/resource.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/core/__init__.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/core/defaults/__init__.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/core/defaults/clean.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/core/defaults/common.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/core/defaults/initialize.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/core/event_listener/__init__.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/core/event_listener/base.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/core/event_listener/factory.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/core/event_listener/http.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/core/event_listener/kafka.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/core/event_listener/once.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/core/event_listener/polling.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/core/event_listener/webhooks_only.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/core/handlers/__init__.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/core/handlers/base.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/core/handlers/entities_state_applier/__init__.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/core/handlers/entities_state_applier/base.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/core/handlers/entities_state_applier/port/__init__.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/core/handlers/entities_state_applier/port/applier.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/core/handlers/entities_state_applier/port/get_related_entities.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/core/handlers/entities_state_applier/port/order_by_entities_dependencies.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/core/handlers/entity_processor/__init__.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/core/handlers/entity_processor/base.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/core/handlers/entity_processor/jq_entity_processor.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/core/handlers/entity_processor/jq_input_evaluator.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/core/handlers/port_app_config/__init__.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/core/handlers/port_app_config/api.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/core/handlers/port_app_config/base.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/core/handlers/port_app_config/models.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/core/handlers/queue/__init__.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/core/handlers/queue/abstract_queue.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/core/handlers/queue/group_queue.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/core/handlers/queue/local_queue.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/core/handlers/resync_state_updater/__init__.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/core/handlers/resync_state_updater/updater.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/core/handlers/webhook/__init__.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/core/handlers/webhook/abstract_webhook_processor.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/core/handlers/webhook/processor_manager.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/core/handlers/webhook/webhook_event.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/core/integrations/__init__.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/core/integrations/base.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/core/integrations/mixins/__init__.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/core/integrations/mixins/events.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/core/integrations/mixins/handler.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/core/integrations/mixins/live_events.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/core/integrations/mixins/sync.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/core/integrations/mixins/sync_raw.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/core/models.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/core/ocean_types.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/core/utils/entity_topological_sorter.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/core/utils/utils.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/debug_cli.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/exceptions/__init__.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/exceptions/api.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/exceptions/base.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/exceptions/clients.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/exceptions/context.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/exceptions/core.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/exceptions/port_defaults.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/exceptions/utils.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/exceptions/webhook_processor.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/helpers/__init__.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/helpers/async_client.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/helpers/metric/metric.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/helpers/metric/utils.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/helpers/stream.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/log/__init__.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/log/handlers.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/log/sensetive.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/middlewares.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/ocean.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/py.typed +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/run.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/sonar-project.properties +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/tests/__init__.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/tests/cache/__init__.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/tests/cache/test_disk_cache.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/tests/cache/test_memory_cache.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/tests/clients/__init__.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/tests/clients/oauth/__init__.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/tests/clients/oauth/test_oauth_client.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/tests/clients/port/mixins/test_entities.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/tests/clients/port/mixins/test_integrations.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/tests/clients/port/mixins/test_organization_mixin.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/tests/config/test_config.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/tests/conftest.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/tests/core/conftest.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/tests/core/defaults/test_common.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/tests/core/event_listener/test_kafka.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/tests/core/handlers/entities_state_applier/test_applier.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/tests/core/handlers/entity_processor/test_jq_entity_processor.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/tests/core/handlers/entity_processor/test_jq_input_evaluator.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/tests/core/handlers/mixins/test_live_events.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/tests/core/handlers/mixins/test_sync_raw.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/tests/core/handlers/port_app_config/test_api.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/tests/core/handlers/port_app_config/test_base.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/tests/core/handlers/queue/test_group_queue.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/tests/core/handlers/queue/test_local_queue.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/tests/core/handlers/webhook/test_abstract_webhook_processor.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/tests/core/handlers/webhook/test_processor_manager.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/tests/core/handlers/webhook/test_webhook_event.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/tests/core/test_utils.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/tests/core/utils/test_entity_topological_sorter.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/tests/core/utils/test_get_port_diff.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/tests/core/utils/test_resolve_entities_diff.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/tests/helpers/__init__.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/tests/helpers/fake_port_api.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/tests/helpers/fixtures.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/tests/helpers/integration.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/tests/helpers/ocean_app.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/tests/helpers/port_client.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/tests/helpers/smoke_test.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/tests/log/test_handlers.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/tests/test_metric.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/tests/test_ocean.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/tests/test_smoke.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/tests/utils/test_async_iterators.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/tests/utils/test_cache.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/utils/__init__.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/utils/async_http.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/utils/async_iterators.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/utils/cache.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/utils/ipc.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/utils/misc.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/utils/queue_utils.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/utils/repeat.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/utils/signal.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/utils/time.py +0 -0
- {port_ocean-0.28.17 → port_ocean-0.28.19}/port_ocean/version.py +0 -0
|
@@ -1,11 +1,20 @@
|
|
|
1
|
-
from contextlib import contextmanager
|
|
2
|
-
from typing import Awaitable, Generator, Callable, cast
|
|
3
|
-
|
|
4
|
-
from loguru import logger
|
|
5
1
|
import asyncio
|
|
2
|
+
import json
|
|
6
3
|
import multiprocessing
|
|
4
|
+
import os
|
|
7
5
|
import re
|
|
8
|
-
import
|
|
6
|
+
import shutil
|
|
7
|
+
import stat
|
|
8
|
+
import subprocess
|
|
9
|
+
import tempfile
|
|
10
|
+
from contextlib import contextmanager
|
|
11
|
+
from typing import Any, AsyncGenerator, Awaitable, Callable, Generator, cast
|
|
12
|
+
|
|
13
|
+
import ijson
|
|
14
|
+
from loguru import logger
|
|
15
|
+
|
|
16
|
+
from port_ocean.clients.port.utils import _http_client as _port_http_client
|
|
17
|
+
from port_ocean.context.ocean import ocean
|
|
9
18
|
from port_ocean.core.handlers.entity_processor.jq_entity_processor import JQEntityProcessor
|
|
10
19
|
from port_ocean.core.ocean_types import (
|
|
11
20
|
ASYNC_GENERATOR_RESYNC_TYPE,
|
|
@@ -19,16 +28,8 @@ from port_ocean.exceptions.core import (
|
|
|
19
28
|
OceanAbortException,
|
|
20
29
|
KindNotImplementedException,
|
|
21
30
|
)
|
|
22
|
-
import os
|
|
23
|
-
from port_ocean.utils.async_http import _http_client
|
|
24
|
-
from port_ocean.clients.port.utils import _http_client as _port_http_client
|
|
25
31
|
from port_ocean.helpers.metric.metric import MetricType, MetricPhase
|
|
26
|
-
from port_ocean.
|
|
27
|
-
import subprocess
|
|
28
|
-
import tempfile
|
|
29
|
-
import stat
|
|
30
|
-
import ijson
|
|
31
|
-
from typing import Any, AsyncGenerator
|
|
32
|
+
from port_ocean.utils.async_http import _http_client
|
|
32
33
|
|
|
33
34
|
def _process_path_type_items(
|
|
34
35
|
result: RAW_RESULT, items_to_parse: str | None = None
|
|
@@ -216,7 +217,9 @@ async def get_items_to_parse_bulks(raw_data: dict[Any, Any], data_path: str, ite
|
|
|
216
217
|
| map({{{items_to_parse_name}: ., {base_jq_object_string}}})"""
|
|
217
218
|
|
|
218
219
|
# Use subprocess with list arguments instead of shell=True
|
|
219
|
-
|
|
220
|
+
|
|
221
|
+
jq_path = shutil.which("jq") or "/bin/jq"
|
|
222
|
+
jq_args = [jq_path, jq_expression, data_path]
|
|
220
223
|
|
|
221
224
|
with open(temp_output_path, "w") as output_file:
|
|
222
225
|
result = subprocess.run(
|
|
@@ -271,7 +274,7 @@ def get_events_as_a_stream(
|
|
|
271
274
|
max_buffer_size_mb: int = 1
|
|
272
275
|
) -> Generator[list[dict[str, Any]], None, None]:
|
|
273
276
|
events = ijson.sendable_list()
|
|
274
|
-
coro = ijson.items_coro(events, target_items)
|
|
277
|
+
coro = ijson.items_coro(events, target_items, use_float=True)
|
|
275
278
|
|
|
276
279
|
# Convert MB to bytes for the buffer size
|
|
277
280
|
buffer_size = max_buffer_size_mb * 1024 * 1024
|
|
@@ -257,7 +257,7 @@ class RetryTransport(httpx.AsyncBaseTransport, httpx.BaseTransport):
|
|
|
257
257
|
else:
|
|
258
258
|
response = await transport.handle_async_request(request)
|
|
259
259
|
|
|
260
|
-
|
|
260
|
+
self._log_response_size(request, response)
|
|
261
261
|
|
|
262
262
|
return response
|
|
263
263
|
except Exception as e:
|
|
@@ -345,35 +345,6 @@ class RetryTransport(httpx.AsyncBaseTransport, httpx.BaseTransport):
|
|
|
345
345
|
return int(content_length)
|
|
346
346
|
return None
|
|
347
347
|
|
|
348
|
-
async def _log_response_size_async(
|
|
349
|
-
self, request: httpx.Request, response: httpx.Response
|
|
350
|
-
) -> None:
|
|
351
|
-
"""Log the size of the response."""
|
|
352
|
-
if not self._should_log_response_size(request):
|
|
353
|
-
return
|
|
354
|
-
|
|
355
|
-
# Try to get content length from headers first
|
|
356
|
-
content_length = self._get_content_length(response)
|
|
357
|
-
if content_length is not None:
|
|
358
|
-
size_info = content_length
|
|
359
|
-
else:
|
|
360
|
-
# If no Content-Length header, try to get actual content size
|
|
361
|
-
try:
|
|
362
|
-
content = await response.aread()
|
|
363
|
-
actual_size = len(content)
|
|
364
|
-
size_info = actual_size
|
|
365
|
-
# Restore the cached body so downstream code can still use .json()/.text/.content
|
|
366
|
-
response._content = content # httpx convention
|
|
367
|
-
except Exception as e:
|
|
368
|
-
cast(logging.Logger, self._logger).error(
|
|
369
|
-
f"Error getting response size: {e}"
|
|
370
|
-
)
|
|
371
|
-
return
|
|
372
|
-
|
|
373
|
-
cast(logging.Logger, self._logger).info(
|
|
374
|
-
f"Response for {request.method} {request.url} - Size: {size_info} bytes"
|
|
375
|
-
)
|
|
376
|
-
|
|
377
348
|
def _log_response_size(
|
|
378
349
|
self, request: httpx.Request, response: httpx.Response
|
|
379
350
|
) -> None:
|
|
@@ -381,24 +352,11 @@ class RetryTransport(httpx.AsyncBaseTransport, httpx.BaseTransport):
|
|
|
381
352
|
return
|
|
382
353
|
|
|
383
354
|
content_length = self._get_content_length(response)
|
|
384
|
-
if content_length is
|
|
385
|
-
|
|
386
|
-
else:
|
|
387
|
-
# If no Content-Length header, try to get actual content size
|
|
388
|
-
try:
|
|
389
|
-
content = response.read()
|
|
390
|
-
actual_size = len(content)
|
|
391
|
-
size_info = actual_size
|
|
392
|
-
# Restore the cached body so downstream code can still use .json()/.text/.content
|
|
393
|
-
response._content = content # httpx convention
|
|
394
|
-
except Exception as e:
|
|
395
|
-
cast(logging.Logger, self._logger).error(
|
|
396
|
-
f"Error getting response size: {e}"
|
|
397
|
-
)
|
|
398
|
-
return
|
|
355
|
+
if content_length is None:
|
|
356
|
+
return
|
|
399
357
|
|
|
400
358
|
cast(logging.Logger, self._logger).info(
|
|
401
|
-
f"Response for {request.method} {request.url} - Size: {
|
|
359
|
+
f"Response for {request.method} {request.url} - Size: {content_length} bytes"
|
|
402
360
|
)
|
|
403
361
|
|
|
404
362
|
async def _should_retry_async(self, response: httpx.Response) -> bool:
|
|
@@ -61,9 +61,9 @@ def _http_loguru_handler(level: LogLevelType) -> None:
|
|
|
61
61
|
|
|
62
62
|
http_memory_handler = HTTPMemoryHandler()
|
|
63
63
|
signal_handler.register(
|
|
64
|
-
http_memory_handler.wait_for_lingering_threads, priority=-
|
|
64
|
+
http_memory_handler.wait_for_lingering_threads, priority=-900
|
|
65
65
|
)
|
|
66
|
-
signal_handler.register(http_memory_handler.flush, priority=-
|
|
66
|
+
signal_handler.register(http_memory_handler.flush, priority=-899)
|
|
67
67
|
|
|
68
68
|
queue_listener = QueueListener(queue, http_memory_handler)
|
|
69
69
|
queue_listener.start()
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import pytest
|
|
2
|
-
from unittest.mock import Mock,
|
|
2
|
+
from unittest.mock import Mock, patch
|
|
3
3
|
from http import HTTPStatus
|
|
4
4
|
import httpx
|
|
5
5
|
|
|
@@ -417,7 +417,7 @@ class TestResponseSizeLogging:
|
|
|
417
417
|
|
|
418
418
|
@patch("port_ocean.helpers.retry.cast")
|
|
419
419
|
def test_log_response_size_without_content_length(self, mock_cast: Mock) -> None:
|
|
420
|
-
"""Test _log_response_size
|
|
420
|
+
"""Test _log_response_size does nothing when no Content-Length header."""
|
|
421
421
|
mock_transport = Mock()
|
|
422
422
|
mock_logger = Mock()
|
|
423
423
|
mock_cast.return_value = mock_logger
|
|
@@ -432,38 +432,14 @@ class TestResponseSizeLogging:
|
|
|
432
432
|
|
|
433
433
|
mock_response = Mock()
|
|
434
434
|
mock_response.headers = {}
|
|
435
|
-
mock_response.read.return_value = b"test content"
|
|
436
435
|
|
|
437
436
|
transport._log_response_size(mock_request, mock_response)
|
|
438
437
|
|
|
439
|
-
mock_response.read.
|
|
440
|
-
mock_logger.info.assert_called_once_with(
|
|
441
|
-
"Response for POST https://api.example.com/create - Size: 12 bytes"
|
|
442
|
-
)
|
|
443
|
-
|
|
444
|
-
@patch("port_ocean.helpers.retry.cast")
|
|
445
|
-
def test_log_response_size_read_error(self, mock_cast: Mock) -> None:
|
|
446
|
-
"""Test _log_response_size handles read errors gracefully."""
|
|
447
|
-
mock_transport = Mock()
|
|
448
|
-
mock_logger = Mock()
|
|
449
|
-
mock_cast.return_value = mock_logger
|
|
450
|
-
transport = RetryTransport(wrapped_transport=mock_transport, logger=mock_logger)
|
|
451
|
-
|
|
452
|
-
mock_request = Mock()
|
|
453
|
-
mock_request.method = "GET"
|
|
454
|
-
mock_request.url.host = "api.example.com"
|
|
455
|
-
|
|
456
|
-
mock_response = Mock()
|
|
457
|
-
mock_response.headers = {}
|
|
458
|
-
mock_response.read.side_effect = Exception("Read error")
|
|
459
|
-
|
|
460
|
-
transport._log_response_size(mock_request, mock_response)
|
|
461
|
-
|
|
462
|
-
mock_logger.error.assert_called_once_with(
|
|
463
|
-
"Error getting response size: Read error"
|
|
464
|
-
)
|
|
438
|
+
mock_response.read.assert_not_called()
|
|
465
439
|
mock_logger.info.assert_not_called()
|
|
466
440
|
|
|
441
|
+
# Read error path removed since _log_response_size no longer reads body
|
|
442
|
+
|
|
467
443
|
@patch("port_ocean.helpers.retry.cast")
|
|
468
444
|
def test_log_response_size_skips_when_should_not_log(self, mock_cast: Mock) -> None:
|
|
469
445
|
"""Test _log_response_size skips logging when _should_log_response_size returns False."""
|
|
@@ -482,166 +458,6 @@ class TestResponseSizeLogging:
|
|
|
482
458
|
|
|
483
459
|
mock_logger.info.assert_not_called()
|
|
484
460
|
|
|
485
|
-
@pytest.mark.asyncio
|
|
486
|
-
@patch("port_ocean.helpers.retry.cast")
|
|
487
|
-
async def test_log_response_size_async_with_content_length(
|
|
488
|
-
self, mock_cast: Mock
|
|
489
|
-
) -> None:
|
|
490
|
-
"""Test _log_response_size_async logs when Content-Length header is present."""
|
|
491
|
-
mock_transport = Mock()
|
|
492
|
-
mock_logger = Mock()
|
|
493
|
-
mock_cast.return_value = mock_logger
|
|
494
|
-
transport = RetryTransport(wrapped_transport=mock_transport, logger=mock_logger)
|
|
495
|
-
|
|
496
|
-
mock_request = Mock()
|
|
497
|
-
mock_request.method = "GET"
|
|
498
|
-
mock_url = Mock()
|
|
499
|
-
mock_url.host = "api.example.com"
|
|
500
|
-
mock_url.configure_mock(__str__=lambda self: "https://api.example.com/data")
|
|
501
|
-
mock_request.url = mock_url
|
|
502
|
-
|
|
503
|
-
mock_response = Mock()
|
|
504
|
-
mock_response.headers = {"Content-Length": "1024"}
|
|
505
|
-
|
|
506
|
-
await transport._log_response_size_async(mock_request, mock_response)
|
|
507
|
-
|
|
508
|
-
mock_logger.info.assert_called_once_with(
|
|
509
|
-
"Response for GET https://api.example.com/data - Size: 1024 bytes"
|
|
510
|
-
)
|
|
511
|
-
|
|
512
|
-
@pytest.mark.asyncio
|
|
513
|
-
@patch("port_ocean.helpers.retry.cast")
|
|
514
|
-
async def test_log_response_size_async_without_content_length(
|
|
515
|
-
self, mock_cast: Mock
|
|
516
|
-
) -> None:
|
|
517
|
-
"""Test _log_response_size_async reads content when no Content-Length header."""
|
|
518
|
-
mock_transport = Mock()
|
|
519
|
-
mock_logger = Mock()
|
|
520
|
-
mock_cast.return_value = mock_logger
|
|
521
|
-
transport = RetryTransport(wrapped_transport=mock_transport, logger=mock_logger)
|
|
522
|
-
|
|
523
|
-
mock_request = Mock()
|
|
524
|
-
mock_request.method = "POST"
|
|
525
|
-
mock_url = Mock()
|
|
526
|
-
mock_url.host = "api.example.com"
|
|
527
|
-
mock_url.configure_mock(__str__=lambda self: "https://api.example.com/create")
|
|
528
|
-
mock_request.url = mock_url
|
|
529
|
-
|
|
530
|
-
mock_response = Mock()
|
|
531
|
-
mock_response.headers = {}
|
|
532
|
-
mock_response.aread = AsyncMock(return_value=b"test content")
|
|
533
|
-
|
|
534
|
-
await transport._log_response_size_async(mock_request, mock_response)
|
|
535
|
-
|
|
536
|
-
mock_response.aread.assert_called_once()
|
|
537
|
-
mock_logger.info.assert_called_once_with(
|
|
538
|
-
"Response for POST https://api.example.com/create - Size: 12 bytes"
|
|
539
|
-
)
|
|
540
|
-
|
|
541
|
-
@pytest.mark.asyncio
|
|
542
|
-
@patch("port_ocean.helpers.retry.cast")
|
|
543
|
-
async def test_log_response_size_async_read_error(self, mock_cast: Mock) -> None:
|
|
544
|
-
"""Test _log_response_size_async handles read errors gracefully."""
|
|
545
|
-
mock_transport = Mock()
|
|
546
|
-
mock_logger = Mock()
|
|
547
|
-
mock_cast.return_value = mock_logger
|
|
548
|
-
transport = RetryTransport(wrapped_transport=mock_transport, logger=mock_logger)
|
|
549
|
-
|
|
550
|
-
mock_request = Mock()
|
|
551
|
-
mock_request.method = "GET"
|
|
552
|
-
mock_request.url.host = "api.example.com"
|
|
553
|
-
|
|
554
|
-
mock_response = Mock()
|
|
555
|
-
mock_response.headers = {}
|
|
556
|
-
mock_response.aread = AsyncMock(side_effect=Exception("Async read error"))
|
|
557
|
-
|
|
558
|
-
await transport._log_response_size_async(mock_request, mock_response)
|
|
559
|
-
|
|
560
|
-
mock_logger.error.assert_called_once_with(
|
|
561
|
-
"Error getting response size: Async read error"
|
|
562
|
-
)
|
|
563
|
-
mock_logger.info.assert_not_called()
|
|
564
|
-
|
|
565
|
-
@pytest.mark.asyncio
|
|
566
|
-
@patch("port_ocean.helpers.retry.cast")
|
|
567
|
-
async def test_log_response_size_async_skips_when_should_not_log(
|
|
568
|
-
self, mock_cast: Mock
|
|
569
|
-
) -> None:
|
|
570
|
-
"""Test _log_response_size_async skips logging when _should_log_response_size returns False."""
|
|
571
|
-
mock_transport = Mock()
|
|
572
|
-
mock_logger = Mock()
|
|
573
|
-
mock_cast.return_value = mock_logger
|
|
574
|
-
transport = RetryTransport(wrapped_transport=mock_transport, logger=mock_logger)
|
|
575
|
-
|
|
576
|
-
mock_request = Mock()
|
|
577
|
-
mock_request.url.host = "api.getport.io" # This should skip logging
|
|
578
|
-
|
|
579
|
-
mock_response = Mock()
|
|
580
|
-
mock_response.headers = {"Content-Length": "1024"}
|
|
581
|
-
|
|
582
|
-
await transport._log_response_size_async(mock_request, mock_response)
|
|
583
|
-
|
|
584
|
-
mock_logger.info.assert_not_called()
|
|
585
|
-
|
|
586
|
-
@pytest.mark.asyncio
|
|
587
|
-
@patch("port_ocean.helpers.retry.cast")
|
|
588
|
-
async def test_log_response_size_async_restores_content(
|
|
589
|
-
self, mock_cast: Mock
|
|
590
|
-
) -> None:
|
|
591
|
-
"""Test _log_response_size_async restores response content after reading."""
|
|
592
|
-
mock_transport = Mock()
|
|
593
|
-
mock_logger = Mock()
|
|
594
|
-
mock_cast.return_value = mock_logger
|
|
595
|
-
transport = RetryTransport(wrapped_transport=mock_transport, logger=mock_logger)
|
|
596
|
-
|
|
597
|
-
mock_request = Mock()
|
|
598
|
-
mock_request.method = "GET"
|
|
599
|
-
mock_url = Mock()
|
|
600
|
-
mock_url.host = "api.example.com"
|
|
601
|
-
mock_url.configure_mock(__str__=lambda self: "https://api.example.com/data")
|
|
602
|
-
mock_request.url = mock_url
|
|
603
|
-
|
|
604
|
-
test_content = b"test response content"
|
|
605
|
-
mock_response = Mock()
|
|
606
|
-
mock_response.headers = {}
|
|
607
|
-
mock_response.aread = AsyncMock(return_value=test_content)
|
|
608
|
-
|
|
609
|
-
await transport._log_response_size_async(mock_request, mock_response)
|
|
610
|
-
|
|
611
|
-
# Verify that the content was restored to the response
|
|
612
|
-
assert mock_response._content == test_content
|
|
613
|
-
mock_logger.info.assert_called_once_with(
|
|
614
|
-
"Response for GET https://api.example.com/data - Size: 21 bytes"
|
|
615
|
-
)
|
|
616
|
-
|
|
617
|
-
@patch("port_ocean.helpers.retry.cast")
|
|
618
|
-
def test_log_response_size_restores_content(self, mock_cast: Mock) -> None:
|
|
619
|
-
"""Test _log_response_size restores response content after reading."""
|
|
620
|
-
mock_transport = Mock()
|
|
621
|
-
mock_logger = Mock()
|
|
622
|
-
mock_cast.return_value = mock_logger
|
|
623
|
-
transport = RetryTransport(wrapped_transport=mock_transport, logger=mock_logger)
|
|
624
|
-
|
|
625
|
-
mock_request = Mock()
|
|
626
|
-
mock_request.method = "GET"
|
|
627
|
-
mock_url = Mock()
|
|
628
|
-
mock_url.host = "api.example.com"
|
|
629
|
-
mock_url.configure_mock(__str__=lambda self: "https://api.example.com/data")
|
|
630
|
-
mock_request.url = mock_url
|
|
631
|
-
|
|
632
|
-
test_content = b"test response content"
|
|
633
|
-
mock_response = Mock()
|
|
634
|
-
mock_response.headers = {}
|
|
635
|
-
mock_response.read.return_value = test_content
|
|
636
|
-
|
|
637
|
-
transport._log_response_size(mock_request, mock_response)
|
|
638
|
-
|
|
639
|
-
# Verify that the content was restored to the response
|
|
640
|
-
assert mock_response._content == test_content
|
|
641
|
-
mock_logger.info.assert_called_once_with(
|
|
642
|
-
"Response for GET https://api.example.com/data - Size: 21 bytes"
|
|
643
|
-
)
|
|
644
|
-
|
|
645
461
|
|
|
646
462
|
class TestResponseSizeLoggingIntegration:
|
|
647
463
|
"""Integration tests to verify response consumption works after size logging."""
|
|
@@ -655,7 +471,7 @@ class TestResponseSizeLoggingIntegration:
|
|
|
655
471
|
def test_log_response_size_preserves_json_consumption(
|
|
656
472
|
self, mock_cast: Mock
|
|
657
473
|
) -> None:
|
|
658
|
-
"""
|
|
474
|
+
"""When no Content-Length, no logging/reading occurs; response usable."""
|
|
659
475
|
mock_transport = Mock()
|
|
660
476
|
mock_logger = Mock()
|
|
661
477
|
mock_cast.return_value = mock_logger
|
|
@@ -665,26 +481,16 @@ class TestResponseSizeLoggingIntegration:
|
|
|
665
481
|
mock_request.method = "GET"
|
|
666
482
|
mock_request.url.host = "api.example.com"
|
|
667
483
|
|
|
668
|
-
# Create a mock response with JSON content
|
|
669
|
-
json_content = b'{"message": "test", "data": [1, 2, 3]}'
|
|
670
484
|
mock_response = Mock()
|
|
671
|
-
mock_response.headers = {}
|
|
672
|
-
mock_response.read.return_value = json_content
|
|
485
|
+
mock_response.headers = {}
|
|
673
486
|
mock_response.json.return_value = {"message": "test", "data": [1, 2, 3]}
|
|
674
487
|
|
|
675
|
-
# Call the logging function
|
|
676
488
|
transport._log_response_size(mock_request, mock_response)
|
|
677
489
|
|
|
678
|
-
|
|
679
|
-
mock_logger.info.assert_called_once()
|
|
680
|
-
|
|
681
|
-
# Verify that response.json() can still be called without StreamConsumed error
|
|
490
|
+
mock_logger.info.assert_not_called()
|
|
682
491
|
result = mock_response.json()
|
|
683
492
|
assert result == {"message": "test", "data": [1, 2, 3]}
|
|
684
|
-
|
|
685
|
-
# Verify that read was called and content was restored
|
|
686
|
-
mock_response.read.assert_called_once()
|
|
687
|
-
assert mock_response._content == json_content
|
|
493
|
+
mock_response.read.assert_not_called()
|
|
688
494
|
|
|
689
495
|
@patch("port_ocean.helpers.retry.cast")
|
|
690
496
|
def test_log_response_size_with_content_length_preserves_json(
|
|
@@ -718,83 +524,11 @@ class TestResponseSizeLoggingIntegration:
|
|
|
718
524
|
# Verify that read was NOT called since we had Content-Length
|
|
719
525
|
mock_response.read.assert_not_called()
|
|
720
526
|
|
|
721
|
-
@pytest.mark.asyncio
|
|
722
|
-
@patch("port_ocean.helpers.retry.cast")
|
|
723
|
-
async def test_log_response_size_async_preserves_json_consumption(
|
|
724
|
-
self, mock_cast: Mock
|
|
725
|
-
) -> None:
|
|
726
|
-
"""Test that _log_response_size_async preserves response for .json() consumption."""
|
|
727
|
-
mock_transport = Mock()
|
|
728
|
-
mock_logger = Mock()
|
|
729
|
-
mock_cast.return_value = mock_logger
|
|
730
|
-
transport = RetryTransport(wrapped_transport=mock_transport, logger=mock_logger)
|
|
731
|
-
|
|
732
|
-
mock_request = Mock()
|
|
733
|
-
mock_request.method = "GET"
|
|
734
|
-
mock_request.url.host = "api.example.com"
|
|
735
|
-
|
|
736
|
-
# Create a mock response with JSON content
|
|
737
|
-
json_content = b'{"users": [{"name": "John", "age": 30}]}'
|
|
738
|
-
mock_response = Mock()
|
|
739
|
-
mock_response.headers = {} # No Content-Length header to force content reading
|
|
740
|
-
mock_response.aread = AsyncMock(return_value=json_content)
|
|
741
|
-
mock_response.json.return_value = {"users": [{"name": "John", "age": 30}]}
|
|
742
|
-
|
|
743
|
-
# Call the async logging function
|
|
744
|
-
await transport._log_response_size_async(mock_request, mock_response)
|
|
745
|
-
|
|
746
|
-
# Verify logging occurred
|
|
747
|
-
mock_logger.info.assert_called_once()
|
|
748
|
-
|
|
749
|
-
# Verify that response.json() can still be called without StreamConsumed error
|
|
750
|
-
result = mock_response.json()
|
|
751
|
-
assert result == {"users": [{"name": "John", "age": 30}]}
|
|
752
|
-
|
|
753
|
-
# Verify that aread was called and content was restored
|
|
754
|
-
mock_response.aread.assert_called_once()
|
|
755
|
-
assert mock_response._content == json_content
|
|
756
|
-
|
|
757
|
-
@pytest.mark.asyncio
|
|
758
|
-
@patch("port_ocean.helpers.retry.cast")
|
|
759
|
-
async def test_log_response_size_async_with_content_length_preserves_json(
|
|
760
|
-
self, mock_cast: Mock
|
|
761
|
-
) -> None:
|
|
762
|
-
"""Test that _log_response_size_async with Content-Length header preserves JSON consumption."""
|
|
763
|
-
mock_transport = Mock()
|
|
764
|
-
mock_logger = Mock()
|
|
765
|
-
mock_cast.return_value = mock_logger
|
|
766
|
-
transport = RetryTransport(wrapped_transport=mock_transport, logger=mock_logger)
|
|
767
|
-
|
|
768
|
-
mock_request = Mock()
|
|
769
|
-
mock_request.method = "PUT"
|
|
770
|
-
mock_request.url.host = "api.example.com"
|
|
771
|
-
|
|
772
|
-
# Create a mock response with Content-Length header
|
|
773
|
-
mock_response = Mock()
|
|
774
|
-
mock_response.headers = {"Content-Length": "2048"}
|
|
775
|
-
mock_response.json.return_value = {
|
|
776
|
-
"updated": True,
|
|
777
|
-
"timestamp": "2023-12-01T12:00:00Z",
|
|
778
|
-
}
|
|
779
|
-
|
|
780
|
-
# Call the async logging function
|
|
781
|
-
await transport._log_response_size_async(mock_request, mock_response)
|
|
782
|
-
|
|
783
|
-
# Verify logging occurred
|
|
784
|
-
mock_logger.info.assert_called_once()
|
|
785
|
-
|
|
786
|
-
# Verify that response.json() can still be called
|
|
787
|
-
result = mock_response.json()
|
|
788
|
-
assert result == {"updated": True, "timestamp": "2023-12-01T12:00:00Z"}
|
|
789
|
-
|
|
790
|
-
# Verify that aread was NOT called since we had Content-Length
|
|
791
|
-
mock_response.aread.assert_not_called()
|
|
792
|
-
|
|
793
527
|
@patch("port_ocean.helpers.retry.cast")
|
|
794
528
|
def test_log_response_size_preserves_text_consumption(
|
|
795
529
|
self, mock_cast: Mock
|
|
796
530
|
) -> None:
|
|
797
|
-
"""
|
|
531
|
+
"""When no Content-Length, no logging/reading; response.text still accessible."""
|
|
798
532
|
mock_transport = Mock()
|
|
799
533
|
mock_logger = Mock()
|
|
800
534
|
mock_cast.return_value = mock_logger
|
|
@@ -804,128 +538,12 @@ class TestResponseSizeLoggingIntegration:
|
|
|
804
538
|
mock_request.method = "GET"
|
|
805
539
|
mock_request.url.host = "api.example.com"
|
|
806
540
|
|
|
807
|
-
# Create a mock response with text content
|
|
808
|
-
text_content = b"Hello, World! This is a test response."
|
|
809
541
|
mock_response = Mock()
|
|
810
|
-
mock_response.headers = {}
|
|
811
|
-
mock_response.read.return_value = text_content
|
|
542
|
+
mock_response.headers = {}
|
|
812
543
|
mock_response.text = "Hello, World! This is a test response."
|
|
813
544
|
|
|
814
|
-
# Call the logging function
|
|
815
545
|
transport._log_response_size(mock_request, mock_response)
|
|
816
546
|
|
|
817
|
-
|
|
818
|
-
mock_logger.info.assert_called_once()
|
|
819
|
-
|
|
820
|
-
# Verify that response.text can still be accessed
|
|
547
|
+
mock_logger.info.assert_not_called()
|
|
821
548
|
assert mock_response.text == "Hello, World! This is a test response."
|
|
822
|
-
|
|
823
|
-
# Verify that read was called and content was restored
|
|
824
|
-
mock_response.read.assert_called_once()
|
|
825
|
-
assert mock_response._content == text_content
|
|
826
|
-
|
|
827
|
-
@pytest.mark.asyncio
|
|
828
|
-
@patch("port_ocean.helpers.retry.cast")
|
|
829
|
-
async def test_log_response_size_async_preserves_content_consumption(
|
|
830
|
-
self, mock_cast: Mock
|
|
831
|
-
) -> None:
|
|
832
|
-
"""Test that _log_response_size_async preserves response for .content consumption."""
|
|
833
|
-
mock_transport = Mock()
|
|
834
|
-
mock_logger = Mock()
|
|
835
|
-
mock_cast.return_value = mock_logger
|
|
836
|
-
transport = RetryTransport(wrapped_transport=mock_transport, logger=mock_logger)
|
|
837
|
-
|
|
838
|
-
mock_request = Mock()
|
|
839
|
-
mock_request.method = "GET"
|
|
840
|
-
mock_request.url.host = "api.example.com"
|
|
841
|
-
|
|
842
|
-
# Create a mock response with binary content
|
|
843
|
-
binary_content = b"\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x01"
|
|
844
|
-
mock_response = Mock()
|
|
845
|
-
mock_response.headers = {} # No Content-Length header to force content reading
|
|
846
|
-
mock_response.aread = AsyncMock(return_value=binary_content)
|
|
847
|
-
mock_response.content = binary_content
|
|
848
|
-
|
|
849
|
-
# Call the async logging function
|
|
850
|
-
await transport._log_response_size_async(mock_request, mock_response)
|
|
851
|
-
|
|
852
|
-
# Verify logging occurred
|
|
853
|
-
mock_logger.info.assert_called_once()
|
|
854
|
-
|
|
855
|
-
# Verify that response.content can still be accessed
|
|
856
|
-
assert mock_response.content == binary_content
|
|
857
|
-
|
|
858
|
-
# Verify that aread was called and content was restored
|
|
859
|
-
mock_response.aread.assert_called_once()
|
|
860
|
-
assert mock_response._content == binary_content
|
|
861
|
-
|
|
862
|
-
@patch("port_ocean.helpers.retry.cast")
|
|
863
|
-
def test_log_response_size_error_handling_preserves_response(
|
|
864
|
-
self, mock_cast: Mock
|
|
865
|
-
) -> None:
|
|
866
|
-
"""Test that _log_response_size error handling doesn't break response consumption."""
|
|
867
|
-
mock_transport = Mock()
|
|
868
|
-
mock_logger = Mock()
|
|
869
|
-
mock_cast.return_value = mock_logger
|
|
870
|
-
transport = RetryTransport(wrapped_transport=mock_transport, logger=mock_logger)
|
|
871
|
-
|
|
872
|
-
mock_request = Mock()
|
|
873
|
-
mock_request.method = "GET"
|
|
874
|
-
mock_request.url.host = "api.example.com"
|
|
875
|
-
|
|
876
|
-
# Create a mock response that will fail on read
|
|
877
|
-
mock_response = Mock()
|
|
878
|
-
mock_response.headers = {} # No Content-Length header to force content reading
|
|
879
|
-
mock_response.read.side_effect = Exception("Network error")
|
|
880
|
-
mock_response.json.return_value = {"error": "handled gracefully"}
|
|
881
|
-
|
|
882
|
-
# Call the logging function
|
|
883
|
-
transport._log_response_size(mock_request, mock_response)
|
|
884
|
-
|
|
885
|
-
# Verify error was logged
|
|
886
|
-
mock_logger.error.assert_called_once_with(
|
|
887
|
-
"Error getting response size: Network error"
|
|
888
|
-
)
|
|
889
|
-
|
|
890
|
-
# Verify that response.json() can still be called despite the error
|
|
891
|
-
result = mock_response.json()
|
|
892
|
-
assert result == {"error": "handled gracefully"}
|
|
893
|
-
|
|
894
|
-
# Verify that read was attempted
|
|
895
|
-
mock_response.read.assert_called_once()
|
|
896
|
-
|
|
897
|
-
@pytest.mark.asyncio
|
|
898
|
-
@patch("port_ocean.helpers.retry.cast")
|
|
899
|
-
async def test_log_response_size_async_error_handling_preserves_response(
|
|
900
|
-
self, mock_cast: Mock
|
|
901
|
-
) -> None:
|
|
902
|
-
"""Test that _log_response_size_async error handling doesn't break response consumption."""
|
|
903
|
-
mock_transport = Mock()
|
|
904
|
-
mock_logger = Mock()
|
|
905
|
-
mock_cast.return_value = mock_logger
|
|
906
|
-
transport = RetryTransport(wrapped_transport=mock_transport, logger=mock_logger)
|
|
907
|
-
|
|
908
|
-
mock_request = Mock()
|
|
909
|
-
mock_request.method = "GET"
|
|
910
|
-
mock_request.url.host = "api.example.com"
|
|
911
|
-
|
|
912
|
-
# Create a mock response that will fail on aread
|
|
913
|
-
mock_response = Mock()
|
|
914
|
-
mock_response.headers = {} # No Content-Length header to force content reading
|
|
915
|
-
mock_response.aread = AsyncMock(side_effect=Exception("Async network error"))
|
|
916
|
-
mock_response.json.return_value = {"error": "handled gracefully"}
|
|
917
|
-
|
|
918
|
-
# Call the async logging function
|
|
919
|
-
await transport._log_response_size_async(mock_request, mock_response)
|
|
920
|
-
|
|
921
|
-
# Verify error was logged
|
|
922
|
-
mock_logger.error.assert_called_once_with(
|
|
923
|
-
"Error getting response size: Async network error"
|
|
924
|
-
)
|
|
925
|
-
|
|
926
|
-
# Verify that response.json() can still be called despite the error
|
|
927
|
-
result = mock_response.json()
|
|
928
|
-
assert result == {"error": "handled gracefully"}
|
|
929
|
-
|
|
930
|
-
# Verify that aread was attempted
|
|
931
|
-
mock_response.aread.assert_called_once()
|
|
549
|
+
mock_response.read.assert_not_called()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|