From 09ef785a209a7cf5136ebd87825749e2dae4992a Mon Sep 17 00:00:00 2001 From: Escape0707 Date: Wed, 27 May 2026 22:58:58 +0900 Subject: [PATCH] test: move delete account task to container integration (#36733) Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> --- .../tasks/test_delete_account_task.py | 84 +++++++++++++ .../tasks/test_delete_account_task.py | 115 ------------------ 2 files changed, 84 insertions(+), 115 deletions(-) create mode 100644 api/tests/test_containers_integration_tests/tasks/test_delete_account_task.py delete mode 100644 api/tests/unit_tests/tasks/test_delete_account_task.py diff --git a/api/tests/test_containers_integration_tests/tasks/test_delete_account_task.py b/api/tests/test_containers_integration_tests/tasks/test_delete_account_task.py new file mode 100644 index 0000000000..68737a4ef6 --- /dev/null +++ b/api/tests/test_containers_integration_tests/tasks/test_delete_account_task.py @@ -0,0 +1,84 @@ +""" +Integration tests for delete_account_task. + +These tests keep billing and email dispatch mocked, but exercise the account +lookup through the real Testcontainers PostgreSQL session factory instead of a +patched session_factory mock. +""" + +from uuid import uuid4 + +import pytest +from sqlalchemy.orm import Session + +from models.account import Account +from tasks.delete_account_task import delete_account_task + + +def _create_account(db_session: Session, *, email: str = "user@example.com") -> Account: + account = Account( + name=f"account-{uuid4()}", + email=email, + ) + db_session.add(account) + db_session.commit() + return account + + +@pytest.fixture +def mock_external_dependencies(mocker): + billing_service = mocker.patch("tasks.delete_account_task.BillingService") + mail_task = mocker.patch("tasks.delete_account_task.send_deletion_success_task") + return billing_service, mail_task + + +def test_billing_enabled_account_exists_calls_billing_and_sends_email( + db_session_with_containers: Session, mock_external_dependencies, mocker +) -> None: + billing_service, mail_task = mock_external_dependencies + account = _create_account(db_session_with_containers, email="a@b.com") + mocker.patch("tasks.delete_account_task.dify_config.BILLING_ENABLED", True) + + delete_account_task(account.id) + + billing_service.delete_account.assert_called_once_with(account.id) + mail_task.delay.assert_called_once_with(account.email) + + +def test_billing_disabled_account_exists_sends_email_only( + db_session_with_containers: Session, mock_external_dependencies, mocker +) -> None: + billing_service, mail_task = mock_external_dependencies + account = _create_account(db_session_with_containers, email="x@y.com") + mocker.patch("tasks.delete_account_task.dify_config.BILLING_ENABLED", False) + + delete_account_task(account.id) + + billing_service.delete_account.assert_not_called() + mail_task.delay.assert_called_once_with(account.email) + + +def test_billing_enabled_account_not_found_calls_billing_no_email(mock_external_dependencies, mocker, caplog) -> None: + billing_service, mail_task = mock_external_dependencies + account_id = str(uuid4()) + mocker.patch("tasks.delete_account_task.dify_config.BILLING_ENABLED", True) + + delete_account_task(account_id) + + billing_service.delete_account.assert_called_once_with(account_id) + mail_task.delay.assert_not_called() + assert any("not found" in record.getMessage().lower() for record in caplog.records) + + +def test_billing_delete_raises_propagates_and_no_email( + db_session_with_containers: Session, mock_external_dependencies, mocker +) -> None: + billing_service, mail_task = mock_external_dependencies + account = _create_account(db_session_with_containers, email="err@example.com") + billing_service.delete_account.side_effect = RuntimeError("billing down") + mocker.patch("tasks.delete_account_task.dify_config.BILLING_ENABLED", True) + + with pytest.raises(RuntimeError, match="billing down"): + delete_account_task(account.id) + + mail_task.delay.assert_not_called() diff --git a/api/tests/unit_tests/tasks/test_delete_account_task.py b/api/tests/unit_tests/tasks/test_delete_account_task.py deleted file mode 100644 index f949c13158..0000000000 --- a/api/tests/unit_tests/tasks/test_delete_account_task.py +++ /dev/null @@ -1,115 +0,0 @@ -""" -Unit tests for delete_account_task. - -Covers: -- Billing enabled with existing account: calls billing and sends success email -- Billing disabled with existing account: skips billing, sends success email -- Account not found: still calls billing when enabled, does not send email -- Billing deletion raises: logs and re-raises, no email -""" - -from types import SimpleNamespace -from unittest.mock import MagicMock, patch - -import pytest - -from tasks.delete_account_task import delete_account_task - - -@pytest.fixture -def mock_db_session(): - """Mock session via session_factory.create_session().""" - with patch("tasks.delete_account_task.session_factory") as mock_sf: - session = MagicMock() - cm = MagicMock() - cm.__enter__.return_value = session - cm.__exit__.return_value = None - mock_sf.create_session.return_value = cm - - yield session - - -@pytest.fixture -def mock_deps(): - """Patch external dependencies: BillingService and send_deletion_success_task.""" - with ( - patch("tasks.delete_account_task.BillingService") as mock_billing, - patch("tasks.delete_account_task.send_deletion_success_task") as mock_mail_task, - ): - # ensure .delay exists on the mail task - mock_mail_task.delay = MagicMock() - yield { - "billing": mock_billing, - "mail_task": mock_mail_task, - } - - -def _set_account_found(mock_db_session, email: str = "user@example.com"): - account = SimpleNamespace(email=email) - mock_db_session.scalar.return_value = account - return account - - -def _set_account_missing(mock_db_session): - mock_db_session.scalar.return_value = None - - -class TestDeleteAccountTask: - def test_billing_enabled_account_exists_calls_billing_and_sends_email(self, mock_db_session, mock_deps): - # Arrange - account_id = "acc-123" - account = _set_account_found(mock_db_session, email="a@b.com") - - # Enable billing - with patch("tasks.delete_account_task.dify_config.BILLING_ENABLED", True): - # Act - delete_account_task(account_id) - - # Assert - mock_deps["billing"].delete_account.assert_called_once_with(account_id) - mock_deps["mail_task"].delay.assert_called_once_with(account.email) - - def test_billing_disabled_account_exists_sends_email_only(self, mock_db_session, mock_deps): - # Arrange - account_id = "acc-456" - account = _set_account_found(mock_db_session, email="x@y.com") - - # Disable billing - with patch("tasks.delete_account_task.dify_config.BILLING_ENABLED", False): - # Act - delete_account_task(account_id) - - # Assert - mock_deps["billing"].delete_account.assert_not_called() - mock_deps["mail_task"].delay.assert_called_once_with(account.email) - - def test_account_not_found_billing_enabled_calls_billing_no_email(self, mock_db_session, mock_deps, caplog): - # Arrange - account_id = "missing-id" - _set_account_missing(mock_db_session) - - # Enable billing - with patch("tasks.delete_account_task.dify_config.BILLING_ENABLED", True): - # Act - delete_account_task(account_id) - - # Assert - mock_deps["billing"].delete_account.assert_called_once_with(account_id) - mock_deps["mail_task"].delay.assert_not_called() - # Optional: verify log contains not found message - assert any("not found" in rec.getMessage().lower() for rec in caplog.records) - - def test_billing_delete_raises_propagates_and_no_email(self, mock_db_session, mock_deps): - # Arrange - account_id = "acc-err" - _set_account_found(mock_db_session, email="err@ex.com") - mock_deps["billing"].delete_account.side_effect = RuntimeError("billing down") - - # Enable billing - with patch("tasks.delete_account_task.dify_config.BILLING_ENABLED", True): - # Act & Assert - with pytest.raises(RuntimeError): - delete_account_task(account_id) - - # Ensure email was not sent - mock_deps["mail_task"].delay.assert_not_called()