quadkit-testing 0.0.41__tar.gz → 0.0.43__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.
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/PKG-INFO +4 -4
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/README.md +3 -3
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/pyproject.toml +4 -1
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/fakes/redis.py +1 -1
- quadkit_testing-0.0.43/src/quadkit/testing/fixtures/db.py +279 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/generators_contract.py +33 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/integration/probes.py +15 -11
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/memory/cqrs.py +1 -1
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/memory/event_bus.py +21 -7
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/memory/outbox.py +1 -1
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/memory/repository.py +3 -3
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/memory/uow.py +1 -1
- quadkit_testing-0.0.43/tests/unit/test_db_transaction_fixture.py +211 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/test_subpackage_exports.py +31 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/.gitignore +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/LICENSE +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/NOTICE +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/py.typed +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/README.md +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/__init__.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/_lazy_exports.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/clients/ai/__init__.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/clients/ai/bed.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/clients/ai/client.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/clients/ai/data.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/clients/db/__init__.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/clients/db/bed.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/clients/db/client.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/clients/web/__init__.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/clients/web/bed.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/clients/web/client.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/clients/web/py.typed +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/clock.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/compliance/__init__.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/compliance/audit.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/compliance/blob_store.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/compliance/cache.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/compliance/database.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/compliance/distributed_lock.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/compliance/event_bus.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/compliance/flags.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/compliance/middleware.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/compliance/notification.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/compliance/queue_backend.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/compliance/repository.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/compliance/search.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/compliance/secrets.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/compliance/task_queue.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/compliance/vector_store.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/compliance/webhook.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/config.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/constants.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/decorators.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/di/__init__.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/events.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/exceptions.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/fakes/__init__.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/fakes/audit.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/fakes/buses.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/fakes/cache.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/fakes/clock.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/fakes/config.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/fakes/events.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/fakes/governance.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/fakes/lifecycle.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/fakes/logging.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/fakes/monitoring.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/fakes/tracing.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/fixtures/__init__.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/fixtures/bed.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/fixtures/container.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/fixtures/containers.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/fixtures/core.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/fixtures/py.typed +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/fixtures/web.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/generators.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/harness/__init__.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/harness/container.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/harness/decorators.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/harness/overrides.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/harness/testbed.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/hooks.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/integration/__init__.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/integration/cleanup.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/integration/config.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/integration/fixtures.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/integration/markers.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/lib/__init__.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/lib/admin_helpers.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/lib/assertions.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/lib/async_helper.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/lib/factory.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/lib/smoke.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/lib/snapshots.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/lib/stubs.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/memory/__init__.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/memory/audit.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/memory/blob_store.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/memory/cache.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/memory/config/__init__.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/memory/config/models.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/memory/constants.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/memory/di/__init__.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/memory/di/provider.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/memory/exceptions.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/memory/lock.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/memory/notification.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/memory/queue.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/memory/search.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/mocks/__init__.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/mocks/base.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/mocks/test_provider.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/module.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/plugins/__init__.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/plugins/pytest/__init__.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/plugins/pytest/plugin.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/protocols.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/py.typed +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/testkit/__init__.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/testkit/assertions.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/testkit/environment.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/testkit/fakes.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/testkit/fixtures.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/types.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/websocket/__init__.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/websocket/client.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/workflow/__init__.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/workflow/harness.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/__snapshots__/test_snapshot_function.json +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/conftest.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/integration/test_web_client.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/test_package_structure_p1.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/__snapshots__/test_snapshot_function.json +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/_integration_helpers.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/conftest.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/test_ai_client_budget.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/test_ai_clients.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/test_app_testbed.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/test_app_testbed_from_factory_overrides.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/test_assertion_helpers.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/test_async_helper.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/test_container.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/test_container_bind.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/test_container_factory_auto_registration.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/test_container_try_resolve.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/test_db_clients.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/test_environment_lifecycle.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/test_exceptions.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/test_factory.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/test_fake_audit.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/test_fake_event_bus_ordering.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/test_fake_tracer.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/test_fakes.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/test_fakes_cluster.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/test_fakes_lifecycle.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/test_generators_util.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/test_harness_testkit.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/test_integration_cleanup.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/test_integration_cluster.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/test_integration_fixtures.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/test_integration_probes.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/test_lib_admin_client.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/test_lib_async_helpers.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/test_lib_helpers.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/test_memory_backends.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/test_memory_cqrs.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/test_memory_event_bus.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/test_memory_lock.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/test_memory_outbox.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/test_memory_repository.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/test_mocks.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/test_mocks_cluster.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/test_override_context_manager_revert.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/test_plugin.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/test_public_exports.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/test_pytest_plugin_fixtures.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/test_service_probe_connectivity.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/test_small_modules.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/test_smoke.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/test_snapshot_asserter_create_compare.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/test_snapshots.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/test_stubs.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/test_test_environment.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/test_test_environment_facade.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/test_test_environment_overrides.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/test_testing_constants.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/test_testing_module.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/test_testing_utils.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/test_testkit_surface.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/test_utilities.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/test_web_clients.py +0 -0
- {quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/tests/unit/test_workflow_websocket_plugins.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: quadkit-testing
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.43
|
|
4
4
|
Summary: Centralized testing infrastructure for Quadkit Framework - Fixtures, factories, and utilities
|
|
5
5
|
Project-URL: Homepage, https://dbtinoy-.github.io/quadkit/
|
|
6
6
|
Project-URL: Repository, https://github.com/dbtinoy-/quadkit
|
|
@@ -234,10 +234,10 @@ vulnerabilities privately per [SECURITY.md](https://github.com/dbtinoy-/quadkit/
|
|
|
234
234
|
|
|
235
235
|
## Stability
|
|
236
236
|
|
|
237
|
-
Version `0.0.
|
|
237
|
+
Version `0.0.43` in the `0.x` series, released in lockstep with the
|
|
238
238
|
other four distributions; APIs may change between minor versions until
|
|
239
|
-
1.0 — pin an exact version (`quadkit-testing==0.0.
|
|
240
|
-
(`>=0.0.
|
|
239
|
+
1.0 — pin an exact version (`quadkit-testing==0.0.43`) or a tight range
|
|
240
|
+
(`>=0.0.43,<0.1.0`). Full policy:
|
|
241
241
|
[stability and compatibility](https://dbtinoy-.github.io/quadkit/reference/stability/).
|
|
242
242
|
|
|
243
243
|
## Links
|
|
@@ -178,10 +178,10 @@ vulnerabilities privately per [SECURITY.md](https://github.com/dbtinoy-/quadkit/
|
|
|
178
178
|
|
|
179
179
|
## Stability
|
|
180
180
|
|
|
181
|
-
Version `0.0.
|
|
181
|
+
Version `0.0.43` in the `0.x` series, released in lockstep with the
|
|
182
182
|
other four distributions; APIs may change between minor versions until
|
|
183
|
-
1.0 — pin an exact version (`quadkit-testing==0.0.
|
|
184
|
-
(`>=0.0.
|
|
183
|
+
1.0 — pin an exact version (`quadkit-testing==0.0.43`) or a tight range
|
|
184
|
+
(`>=0.0.43,<0.1.0`). Full policy:
|
|
185
185
|
[stability and compatibility](https://dbtinoy-.github.io/quadkit/reference/stability/).
|
|
186
186
|
|
|
187
187
|
## Links
|
|
@@ -6,7 +6,7 @@ build-backend = "hatchling.build"
|
|
|
6
6
|
|
|
7
7
|
[project]
|
|
8
8
|
name = "quadkit-testing"
|
|
9
|
-
version = "0.0.
|
|
9
|
+
version = "0.0.43"
|
|
10
10
|
description = "Centralized testing infrastructure for Quadkit Framework - Fixtures, factories, and utilities"
|
|
11
11
|
readme = "README.md"
|
|
12
12
|
requires-python = ">=3.11"
|
|
@@ -164,6 +164,9 @@ workspace = true
|
|
|
164
164
|
[tool.uv.sources.quadkit-contracts]
|
|
165
165
|
workspace = true
|
|
166
166
|
|
|
167
|
+
[tool.uv.sources.quadkit-sql]
|
|
168
|
+
workspace = true
|
|
169
|
+
|
|
167
170
|
[tool.pytest.ini_options]
|
|
168
171
|
asyncio_mode = "auto"
|
|
169
172
|
addopts = ["--cov=quadkit.testing", "--cov-report=html", "--cov-report=term", "--cov-fail-under=66"]
|
|
@@ -11,7 +11,7 @@ __all__ = ["FakeRedisClient"]
|
|
|
11
11
|
class FakeRedisClient:
|
|
12
12
|
"""In-memory async client compatible with the ``redis.asyncio`` surface used by tests.
|
|
13
13
|
|
|
14
|
-
Supports the subset of Redis commands exercised by
|
|
14
|
+
Supports the subset of Redis commands exercised by quadkit-cache tests:
|
|
15
15
|
``ping``, ``set`` (with ``ex``/``px``/``nx``/``xx``), ``get``, ``delete``,
|
|
16
16
|
``exists``, ``expire``, ``ttl``, ``flushdb``, and ``close``. All data is
|
|
17
17
|
kept in process, so tests never touch the network or a pre-started
|
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
"""Database-specific test fixtures"""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from collections.abc import AsyncGenerator
|
|
6
|
+
from typing import Any
|
|
7
|
+
from unittest.mock import AsyncMock, Mock
|
|
8
|
+
|
|
9
|
+
import pytest
|
|
10
|
+
|
|
11
|
+
pytest_asyncio: Any | None = None
|
|
12
|
+
try:
|
|
13
|
+
import pytest_asyncio
|
|
14
|
+
except ImportError:
|
|
15
|
+
pytest_asyncio = None
|
|
16
|
+
|
|
17
|
+
from collections.abc import Callable
|
|
18
|
+
from typing import Any as _Any
|
|
19
|
+
|
|
20
|
+
# Explicitly type the chosen fixture decorator so mypy treats decorated functions as typed
|
|
21
|
+
fixture_decorator: Callable[..., _Any] = (
|
|
22
|
+
pytest.fixture if pytest_asyncio is None else pytest_asyncio.fixture
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
try:
|
|
26
|
+
from quadkit.sql.abstractions.connection import ( # type: ignore[attr-defined]
|
|
27
|
+
ConnectionPool,
|
|
28
|
+
DatabaseConnection,
|
|
29
|
+
)
|
|
30
|
+
except ImportError:
|
|
31
|
+
# Fallback if quadkit-sql is not available
|
|
32
|
+
ConnectionPool: Any = Any # type: ignore[no-redef]
|
|
33
|
+
DatabaseConnection: Any = Any # type: ignore[no-redef]
|
|
34
|
+
from quadkit.testing.clients.db import (
|
|
35
|
+
DatabaseTestBed,
|
|
36
|
+
DatabaseTestClient,
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
@fixture_decorator
|
|
41
|
+
async def db_test_bed() -> AsyncGenerator[DatabaseTestBed, None]:
|
|
42
|
+
"""Fixture for DatabaseTestBed with automatic cleanup"""
|
|
43
|
+
test_bed = DatabaseTestBed()
|
|
44
|
+
async with test_bed as tb:
|
|
45
|
+
yield tb
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
@fixture_decorator
|
|
49
|
+
async def test_database_client() -> AsyncGenerator[DatabaseTestClient, None]:
|
|
50
|
+
"""Fixture for DatabaseTestClient"""
|
|
51
|
+
client = DatabaseTestClient()
|
|
52
|
+
async with client as c:
|
|
53
|
+
yield c
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
@pytest.fixture
|
|
57
|
+
def mock_connection() -> DatabaseConnection:
|
|
58
|
+
"""Fixture for mock database connection"""
|
|
59
|
+
mock_conn = Mock(spec=DatabaseConnection)
|
|
60
|
+
|
|
61
|
+
# Mock async methods
|
|
62
|
+
mock_conn.execute = AsyncMock()
|
|
63
|
+
mock_conn.execute_many = AsyncMock()
|
|
64
|
+
mock_conn.fetch_one = AsyncMock()
|
|
65
|
+
mock_conn.fetch_all = AsyncMock()
|
|
66
|
+
mock_conn.close = AsyncMock()
|
|
67
|
+
|
|
68
|
+
# Additional methods expected by tests
|
|
69
|
+
mock_conn.fetchone = AsyncMock()
|
|
70
|
+
mock_conn.fetchall = AsyncMock()
|
|
71
|
+
|
|
72
|
+
# Mock transaction context manager
|
|
73
|
+
mock_transaction = AsyncMock()
|
|
74
|
+
mock_transaction.__aenter__ = AsyncMock(return_value=mock_conn)
|
|
75
|
+
mock_transaction.__aexit__ = AsyncMock(return_value=None)
|
|
76
|
+
mock_conn.transaction = Mock(return_value=mock_transaction)
|
|
77
|
+
|
|
78
|
+
return mock_conn
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
@pytest.fixture
|
|
82
|
+
def mock_connection_pool() -> ConnectionPool:
|
|
83
|
+
"""Fixture for mock connection pool"""
|
|
84
|
+
mock_pool = Mock(spec=ConnectionPool)
|
|
85
|
+
|
|
86
|
+
# Mock async methods
|
|
87
|
+
mock_pool.get_connection = AsyncMock()
|
|
88
|
+
mock_pool.close = AsyncMock()
|
|
89
|
+
mock_pool.health_check = Mock(return_value={"status": "healthy"})
|
|
90
|
+
mock_pool.get_stats = Mock(return_value={"connections": 5})
|
|
91
|
+
|
|
92
|
+
# Additional methods expected by tests
|
|
93
|
+
mock_pool.acquire = AsyncMock()
|
|
94
|
+
mock_pool.release = AsyncMock()
|
|
95
|
+
|
|
96
|
+
return mock_pool
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
@fixture_decorator
|
|
100
|
+
async def seeded_database(
|
|
101
|
+
db_test_bed: DatabaseTestBed,
|
|
102
|
+
sample_user_data: list[dict[str, Any]],
|
|
103
|
+
sample_order_data: list[dict[str, Any]],
|
|
104
|
+
sample_product_data: list[dict[str, Any]],
|
|
105
|
+
) -> DatabaseTestBed:
|
|
106
|
+
"""Fixture for database with sample data"""
|
|
107
|
+
# Create users table
|
|
108
|
+
await db_test_bed.create_test_table(
|
|
109
|
+
"users",
|
|
110
|
+
"id INTEGER PRIMARY KEY, name TEXT, email TEXT, role TEXT",
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
# Create orders table
|
|
114
|
+
await db_test_bed.create_test_table(
|
|
115
|
+
"orders",
|
|
116
|
+
"id INTEGER PRIMARY KEY, user_id INTEGER, total REAL, status TEXT, items TEXT",
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
# Create products table
|
|
120
|
+
await db_test_bed.create_test_table(
|
|
121
|
+
"products",
|
|
122
|
+
"id INTEGER PRIMARY KEY, name TEXT, price REAL, category TEXT",
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
# Seed sample data
|
|
126
|
+
await db_test_bed.seed_test_data("users", sample_user_data)
|
|
127
|
+
await db_test_bed.seed_test_data("orders", sample_order_data)
|
|
128
|
+
await db_test_bed.seed_test_data("products", sample_product_data)
|
|
129
|
+
|
|
130
|
+
return db_test_bed
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
@fixture_decorator
|
|
134
|
+
async def clean_database(db_test_bed: DatabaseTestBed) -> DatabaseTestBed:
|
|
135
|
+
"""Fixture for clean database with tables but no data"""
|
|
136
|
+
# Create users table
|
|
137
|
+
await db_test_bed.create_test_table(
|
|
138
|
+
"users",
|
|
139
|
+
"id INTEGER PRIMARY KEY, name TEXT NOT NULL, email TEXT",
|
|
140
|
+
)
|
|
141
|
+
|
|
142
|
+
# Create orders table
|
|
143
|
+
await db_test_bed.create_test_table(
|
|
144
|
+
"orders",
|
|
145
|
+
"id INTEGER PRIMARY KEY, user_id INTEGER, total REAL, status TEXT",
|
|
146
|
+
)
|
|
147
|
+
|
|
148
|
+
return db_test_bed
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
@pytest.fixture
|
|
152
|
+
def sample_user_data() -> list[dict[str, Any]]:
|
|
153
|
+
"""Sample user data for testing"""
|
|
154
|
+
return [
|
|
155
|
+
{
|
|
156
|
+
"id": 1,
|
|
157
|
+
"name": "Alice Johnson",
|
|
158
|
+
"email": "alice@example.com",
|
|
159
|
+
"role": "user",
|
|
160
|
+
},
|
|
161
|
+
{"id": 2, "name": "Bob Smith", "email": "bob@example.com", "role": "admin"},
|
|
162
|
+
{
|
|
163
|
+
"id": 3,
|
|
164
|
+
"name": "Charlie Brown",
|
|
165
|
+
"email": "charlie@example.com",
|
|
166
|
+
"role": "user",
|
|
167
|
+
},
|
|
168
|
+
]
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
@pytest.fixture
|
|
172
|
+
def sample_order_data() -> list[dict[str, Any]]:
|
|
173
|
+
"""Sample order data for testing"""
|
|
174
|
+
return [
|
|
175
|
+
{"id": 1, "user_id": 1, "total": 99.99, "status": "completed", "items": 3},
|
|
176
|
+
{"id": 2, "user_id": 2, "total": 149.50, "status": "pending", "items": 5},
|
|
177
|
+
{"id": 3, "user_id": 1, "total": 75.25, "status": "shipped", "items": 2},
|
|
178
|
+
]
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
@pytest.fixture
|
|
182
|
+
def sample_product_data() -> list[dict[str, Any]]:
|
|
183
|
+
"""Sample product data for testing"""
|
|
184
|
+
return [
|
|
185
|
+
{"id": 1, "name": "Widget A", "price": 29.99, "category": "electronics"},
|
|
186
|
+
{"id": 2, "name": "Widget B", "price": 49.99, "category": "tools"},
|
|
187
|
+
{"id": 3, "name": "Widget C", "price": 19.99, "category": "accessories"},
|
|
188
|
+
]
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
@pytest.fixture
|
|
192
|
+
def database_provider() -> Any:
|
|
193
|
+
"""Placeholder fixture for a real DatabaseProviderProtocol instance.
|
|
194
|
+
|
|
195
|
+
Returns ``None`` by default so that ``db_transaction`` skips gracefully
|
|
196
|
+
in test suites that do not configure a live database.
|
|
197
|
+
|
|
198
|
+
Override this in your ``conftest.py`` to connect ``db_transaction`` to
|
|
199
|
+
the real database provider resolved from the application container::
|
|
200
|
+
|
|
201
|
+
from quadkit.contracts.data import DatabaseProviderProtocol
|
|
202
|
+
|
|
203
|
+
@pytest.fixture
|
|
204
|
+
async def database_provider(container: Container):
|
|
205
|
+
return await container.resolve(DatabaseProviderProtocol)
|
|
206
|
+
|
|
207
|
+
Where ``container`` is whatever fixture you use to provide the booted DI
|
|
208
|
+
container for your integration tests.
|
|
209
|
+
"""
|
|
210
|
+
return None
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
@fixture_decorator
|
|
214
|
+
async def db_transaction(
|
|
215
|
+
database_provider: Any,
|
|
216
|
+
) -> AsyncGenerator[Any, None]:
|
|
217
|
+
"""Wrap an integration test in a database transaction that always rolls back.
|
|
218
|
+
|
|
219
|
+
Opens a scoped database context, begins a transaction, and yields the
|
|
220
|
+
active :class:`~quadkit.contracts.data.ConnectionProtocol` so that the
|
|
221
|
+
test can run queries. The transaction is *always* rolled back during
|
|
222
|
+
teardown regardless of test outcome, keeping the database state clean and
|
|
223
|
+
making tests fully order-independent.
|
|
224
|
+
|
|
225
|
+
Requires the ``database_provider`` fixture to be overridden in the test
|
|
226
|
+
suite's ``conftest.py`` (see :func:`database_provider` for instructions).
|
|
227
|
+
When ``database_provider`` returns ``None`` (the default), the test is
|
|
228
|
+
skipped with an informative message.
|
|
229
|
+
|
|
230
|
+
Example::
|
|
231
|
+
|
|
232
|
+
# conftest.py
|
|
233
|
+
from quadkit.contracts.data import DatabaseProviderProtocol
|
|
234
|
+
|
|
235
|
+
@pytest.fixture
|
|
236
|
+
async def database_provider(container):
|
|
237
|
+
return await container.resolve(DatabaseProviderProtocol)
|
|
238
|
+
|
|
239
|
+
# test_users.py
|
|
240
|
+
@pytest.mark.asyncio
|
|
241
|
+
async def test_create_user(db_transaction) -> None:
|
|
242
|
+
await db_transaction.execute(
|
|
243
|
+
"INSERT INTO users(name, email) VALUES($1, $2)",
|
|
244
|
+
"Alice", "alice@example.com",
|
|
245
|
+
)
|
|
246
|
+
row = await db_transaction.fetch_one(
|
|
247
|
+
"SELECT name FROM users WHERE email = $1", "alice@example.com"
|
|
248
|
+
)
|
|
249
|
+
assert row["name"] == "Alice"
|
|
250
|
+
# No teardown needed — the transaction is automatically rolled back.
|
|
251
|
+
"""
|
|
252
|
+
if database_provider is None:
|
|
253
|
+
pytest.skip(
|
|
254
|
+
"db_transaction requires a 'database_provider' fixture. "
|
|
255
|
+
"Override it in conftest.py with a real DatabaseProviderProtocol instance."
|
|
256
|
+
)
|
|
257
|
+
|
|
258
|
+
async with database_provider.scoped_context():
|
|
259
|
+
conn = await database_provider.get_scoped_connection()
|
|
260
|
+
await conn.execute("BEGIN")
|
|
261
|
+
try:
|
|
262
|
+
yield conn
|
|
263
|
+
finally:
|
|
264
|
+
await conn.execute("ROLLBACK")
|
|
265
|
+
|
|
266
|
+
|
|
267
|
+
__all__ = [
|
|
268
|
+
"clean_database",
|
|
269
|
+
"database_provider",
|
|
270
|
+
"db_test_bed",
|
|
271
|
+
"db_transaction",
|
|
272
|
+
"mock_connection",
|
|
273
|
+
"mock_connection_pool",
|
|
274
|
+
"sample_order_data",
|
|
275
|
+
"sample_product_data",
|
|
276
|
+
"sample_user_data",
|
|
277
|
+
"seeded_database",
|
|
278
|
+
"test_database_client",
|
|
279
|
+
]
|
{quadkit_testing-0.0.41 → quadkit_testing-0.0.43}/src/quadkit/testing/generators_contract.py
RENAMED
|
@@ -8,6 +8,30 @@ from pathlib import Path
|
|
|
8
8
|
from typing import Any
|
|
9
9
|
|
|
10
10
|
|
|
11
|
+
def _assert_marker_convention(py_path: Path, text: str) -> None:
|
|
12
|
+
"""Enforce the generated-stub marker convention on one rendered ``.py``.
|
|
13
|
+
|
|
14
|
+
Generated stubs pair ``# @INTENT: <goal>`` directly above ``# @TODO:
|
|
15
|
+
<action>`` and never ship a bare ``# TODO:`` (the ``@`` prefix keeps both
|
|
16
|
+
greppable). See ``docs/09-27-2026/GENERATED_CODE_MARKERS.md``.
|
|
17
|
+
"""
|
|
18
|
+
lines = text.splitlines()
|
|
19
|
+
for i, line in enumerate(lines):
|
|
20
|
+
stripped = line.strip()
|
|
21
|
+
if stripped.startswith("# TODO"):
|
|
22
|
+
raise AssertionError(
|
|
23
|
+
f"{py_path}: bare '# TODO' in generated code must be '# @TODO' "
|
|
24
|
+
f"-> {line!r}"
|
|
25
|
+
)
|
|
26
|
+
if stripped.startswith("# @TODO:"):
|
|
27
|
+
prev = lines[i - 1].strip() if i > 0 else ""
|
|
28
|
+
if not prev.startswith("# @INTENT:"):
|
|
29
|
+
raise AssertionError(
|
|
30
|
+
f"{py_path}: '# @TODO' at line {i + 1} is not preceded by "
|
|
31
|
+
f"a '# @INTENT:' line (found {prev!r})"
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
|
|
11
35
|
def assert_contributor_generators_render(
|
|
12
36
|
contributor: Any,
|
|
13
37
|
*,
|
|
@@ -77,6 +101,15 @@ def assert_contributor_generators_render(
|
|
|
77
101
|
f"(created={len(created)}, overwritten={len(overwritten)}, "
|
|
78
102
|
f"staged={len(staged)})"
|
|
79
103
|
)
|
|
104
|
+
|
|
105
|
+
# Every rendered Python stub must follow the @INTENT/@TODO marker
|
|
106
|
+
# convention — a single gate so a new generator (or a template at a
|
|
107
|
+
# deeper package nesting) cannot reintroduce a bare ``# TODO``.
|
|
108
|
+
for py_file in out.rglob("*.py"):
|
|
109
|
+
if "__pycache__" in py_file.parts:
|
|
110
|
+
continue
|
|
111
|
+
_assert_marker_convention(py_file, py_file.read_text(encoding="utf-8"))
|
|
112
|
+
|
|
80
113
|
exercised += 1
|
|
81
114
|
return exercised
|
|
82
115
|
|
|
@@ -51,7 +51,7 @@ class ServiceProbe:
|
|
|
51
51
|
await client.close()
|
|
52
52
|
return True
|
|
53
53
|
except Exception as e: # noqa: BLE001
|
|
54
|
-
logger.debug("probe_failed",
|
|
54
|
+
logger.debug("probe_failed", dependency="redis", url=url, error=str(e))
|
|
55
55
|
return False
|
|
56
56
|
|
|
57
57
|
@staticmethod
|
|
@@ -66,7 +66,7 @@ class ServiceProbe:
|
|
|
66
66
|
await conn.close()
|
|
67
67
|
return True
|
|
68
68
|
except Exception as e: # noqa: BLE001
|
|
69
|
-
logger.debug("probe_failed",
|
|
69
|
+
logger.debug("probe_failed", dependency="postgres", dsn=dsn, error=str(e))
|
|
70
70
|
return False
|
|
71
71
|
|
|
72
72
|
@staticmethod
|
|
@@ -79,7 +79,9 @@ class ServiceProbe:
|
|
|
79
79
|
response = await client.get(url)
|
|
80
80
|
return response.status_code == 200
|
|
81
81
|
except Exception as e: # noqa: BLE001
|
|
82
|
-
logger.debug(
|
|
82
|
+
logger.debug(
|
|
83
|
+
"probe_failed", dependency="elasticsearch", url=url, error=str(e)
|
|
84
|
+
)
|
|
83
85
|
return False
|
|
84
86
|
|
|
85
87
|
@staticmethod
|
|
@@ -94,7 +96,7 @@ class ServiceProbe:
|
|
|
94
96
|
await connection.close()
|
|
95
97
|
return True
|
|
96
98
|
except Exception as e: # noqa: BLE001
|
|
97
|
-
logger.debug("probe_failed",
|
|
99
|
+
logger.debug("probe_failed", dependency="rabbitmq", url=url, error=str(e))
|
|
98
100
|
return False
|
|
99
101
|
|
|
100
102
|
@staticmethod
|
|
@@ -107,7 +109,9 @@ class ServiceProbe:
|
|
|
107
109
|
response = await client.get(f"{url}/health")
|
|
108
110
|
return response.status_code == 200
|
|
109
111
|
except Exception as e: # noqa: BLE001
|
|
110
|
-
logger.debug(
|
|
112
|
+
logger.debug(
|
|
113
|
+
"probe_failed", dependency="meilisearch", url=url, error=str(e)
|
|
114
|
+
)
|
|
111
115
|
return False
|
|
112
116
|
|
|
113
117
|
@staticmethod
|
|
@@ -125,7 +129,7 @@ class ServiceProbe:
|
|
|
125
129
|
return True
|
|
126
130
|
except Exception as e: # noqa: BLE001
|
|
127
131
|
logger.debug(
|
|
128
|
-
"probe_failed",
|
|
132
|
+
"probe_failed", dependency="smtp", host=host, port=port, error=str(e)
|
|
129
133
|
)
|
|
130
134
|
return False
|
|
131
135
|
|
|
@@ -152,7 +156,7 @@ class ServiceProbe:
|
|
|
152
156
|
return True
|
|
153
157
|
except Exception as e: # noqa: BLE001
|
|
154
158
|
logger.debug(
|
|
155
|
-
"probe_failed",
|
|
159
|
+
"probe_failed", dependency="kafka", bootstrap=bootstrap, error=str(e)
|
|
156
160
|
)
|
|
157
161
|
return False
|
|
158
162
|
|
|
@@ -179,7 +183,7 @@ class ServiceProbe:
|
|
|
179
183
|
return True
|
|
180
184
|
except Exception as e: # noqa: BLE001
|
|
181
185
|
logger.debug(
|
|
182
|
-
"probe_failed",
|
|
186
|
+
"probe_failed", dependency="minio", endpoint=endpoint, error=str(e)
|
|
183
187
|
)
|
|
184
188
|
return False
|
|
185
189
|
|
|
@@ -207,7 +211,7 @@ class ServiceProbe:
|
|
|
207
211
|
await writer.wait_closed()
|
|
208
212
|
return True
|
|
209
213
|
except Exception as e: # noqa: BLE001
|
|
210
|
-
logger.debug("probe_failed",
|
|
214
|
+
logger.debug("probe_failed", dependency="mongodb", dsn=dsn, error=str(e))
|
|
211
215
|
return False
|
|
212
216
|
|
|
213
217
|
@staticmethod
|
|
@@ -234,7 +238,7 @@ class ServiceProbe:
|
|
|
234
238
|
await writer.wait_closed()
|
|
235
239
|
return True
|
|
236
240
|
except Exception as e: # noqa: BLE001
|
|
237
|
-
logger.debug("probe_failed",
|
|
241
|
+
logger.debug("probe_failed", dependency="qdrant", url=url, error=str(e))
|
|
238
242
|
return False
|
|
239
243
|
|
|
240
244
|
@staticmethod
|
|
@@ -261,5 +265,5 @@ class ServiceProbe:
|
|
|
261
265
|
await writer.wait_closed()
|
|
262
266
|
return True
|
|
263
267
|
except Exception as e: # noqa: BLE001
|
|
264
|
-
logger.debug("probe_failed",
|
|
268
|
+
logger.debug("probe_failed", dependency="neo4j", url=url, error=str(e))
|
|
265
269
|
return False
|
|
@@ -18,7 +18,7 @@ from quadkit.contracts.events import EventBusProtocol as EventBusProtocol
|
|
|
18
18
|
from quadkit.contracts.events import EventHandlerProtocol
|
|
19
19
|
|
|
20
20
|
if TYPE_CHECKING:
|
|
21
|
-
from collections.abc import Callable
|
|
21
|
+
from collections.abc import Awaitable, Callable
|
|
22
22
|
|
|
23
23
|
from quadkit.contracts.core import MiddlewarePipelineProtocol
|
|
24
24
|
from quadkit.contracts.domain.events import DomainEvent
|
|
@@ -76,11 +76,14 @@ class InMemoryEventBus(EventBusProtocol):
|
|
|
76
76
|
the originating request context.
|
|
77
77
|
"""
|
|
78
78
|
# handlers stored as (priority, handler) tuples, sorted by priority
|
|
79
|
-
self._handlers: dict[
|
|
80
|
-
|
|
81
|
-
|
|
79
|
+
self._handlers: dict[
|
|
80
|
+
type | str,
|
|
81
|
+
list[tuple[int, EventHandlerProtocol | Callable[..., Awaitable[Any]]]],
|
|
82
|
+
] = defaultdict(list)
|
|
82
83
|
# wildcard subscriptions receive every published event regardless of type
|
|
83
|
-
self._wildcard_handlers: list[
|
|
84
|
+
self._wildcard_handlers: list[
|
|
85
|
+
tuple[int, EventHandlerProtocol | Callable[..., Awaitable[Any]]]
|
|
86
|
+
] = []
|
|
84
87
|
from quadkit.app.pipeline import (
|
|
85
88
|
MiddlewarePipeline as _MiddlewarePipeline,
|
|
86
89
|
)
|
|
@@ -98,7 +101,7 @@ class InMemoryEventBus(EventBusProtocol):
|
|
|
98
101
|
def subscribe(
|
|
99
102
|
self,
|
|
100
103
|
event_type: type | str,
|
|
101
|
-
handler: EventHandlerProtocol,
|
|
104
|
+
handler: EventHandlerProtocol | Callable[..., Awaitable[Any]],
|
|
102
105
|
*,
|
|
103
106
|
priority: int = 0,
|
|
104
107
|
) -> None:
|
|
@@ -121,7 +124,9 @@ class InMemoryEventBus(EventBusProtocol):
|
|
|
121
124
|
self._handlers[event_type].sort(key=lambda entry: entry[0])
|
|
122
125
|
|
|
123
126
|
def unsubscribe(
|
|
124
|
-
self,
|
|
127
|
+
self,
|
|
128
|
+
event_type: type | str,
|
|
129
|
+
handler: EventHandlerProtocol | Callable[..., Awaitable[Any]],
|
|
125
130
|
) -> None:
|
|
126
131
|
"""Remove a previously registered handler for an event type.
|
|
127
132
|
|
|
@@ -141,6 +146,15 @@ class InMemoryEventBus(EventBusProtocol):
|
|
|
141
146
|
return
|
|
142
147
|
self._handlers[event_type] = [(p, h) for p, h in handlers if h is not handler]
|
|
143
148
|
|
|
149
|
+
async def flush(self) -> None:
|
|
150
|
+
"""Wait until all pending events have been dispatched.
|
|
151
|
+
|
|
152
|
+
A no-op here: ``publish`` awaits every handler before it returns, so
|
|
153
|
+
this engine never has an in-flight dispatch to drain. The member
|
|
154
|
+
exists because ``EventBusProtocol`` declares it — the flagship bus
|
|
155
|
+
dispatches in the background and does need it.
|
|
156
|
+
"""
|
|
157
|
+
|
|
144
158
|
def add_middleware(self, middleware: Any) -> None:
|
|
145
159
|
"""Add a middleware function to the event processing chain.
|
|
146
160
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Provides an in-memory Outbox for testing and local development.
|
|
4
4
|
For production with database persistence, use the OutboxEventStore
|
|
5
|
-
from the
|
|
5
|
+
from the quadkit-events extension.
|
|
6
6
|
|
|
7
7
|
The Outbox pattern ensures events are stored in the same transaction
|
|
8
8
|
as business data, then relayed asynchronously for publishing.
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
Provides a generic, async-safe in-memory implementation of the RepositoryProtocol
|
|
4
4
|
pattern backed by :class:`~quadkit.data.repository.base.AbstractRepository`.
|
|
5
5
|
Intended as a zero-infrastructure drop-in for unit tests and local development.
|
|
6
|
-
For production, replace with ``
|
|
6
|
+
For production, replace with ``quadkit-sql``'s SQLRepository or a
|
|
7
7
|
domain-specific storage backend.
|
|
8
8
|
"""
|
|
9
9
|
|
|
@@ -26,7 +26,7 @@ class InMemoryRepository(AbstractRepository[T, Any], Generic[T]):
|
|
|
26
26
|
This class lives in ``quadkit-testing`` intentionally — it is not exported
|
|
27
27
|
from ``quadkit`` core. Production code should depend on the
|
|
28
28
|
``RepositoryProtocol`` protocol from ``quadkit.contracts.data`` and receive a
|
|
29
|
-
concrete implementation (e.g. ``SQLRepository`` from ``
|
|
29
|
+
concrete implementation (e.g. ``SQLRepository`` from ``quadkit-sql``)
|
|
30
30
|
via dependency injection.
|
|
31
31
|
|
|
32
32
|
Stores entities in a plain dict keyed by their identity attribute.
|
|
@@ -36,7 +36,7 @@ class InMemoryRepository(AbstractRepository[T, Any], Generic[T]):
|
|
|
36
36
|
|
|
37
37
|
Extends :class:`~quadkit.data.repository.base.AbstractRepository` and
|
|
38
38
|
implements all required primitives. For production persistence, use
|
|
39
|
-
``
|
|
39
|
+
``quadkit-sql``'s ``SQLRepository`` or any other storage backend.
|
|
40
40
|
|
|
41
41
|
Args:
|
|
42
42
|
id_attr: Name of the entity attribute that holds the primary key.
|
|
@@ -6,7 +6,7 @@ Provides a concrete :class:`InMemoryUnitOfWork` that extends
|
|
|
6
6
|
database persistence is required.
|
|
7
7
|
|
|
8
8
|
For production, use a backend that overrides :meth:`_flush` to write to a
|
|
9
|
-
database (e.g. ``
|
|
9
|
+
database (e.g. ``quadkit-sql``'s ``SQLUnitOfWork``).
|
|
10
10
|
"""
|
|
11
11
|
|
|
12
12
|
from __future__ import annotations
|