test: move web forgot-password coverage to unit tests (#38943)

This commit is contained in:
Asuka Minato 2026-07-14 23:09:28 +09:00 committed by GitHub
parent 3adf279422
commit 141257aefb
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -1,9 +1,9 @@
"""Testcontainers integration tests for controllers.web.forgot_password endpoints."""
"""Unit tests for controllers.web.forgot_password endpoints."""
from __future__ import annotations
import base64
from types import SimpleNamespace
from collections.abc import Iterator
from unittest.mock import ANY, MagicMock, patch
import pytest
@ -14,25 +14,35 @@ from controllers.web.forgot_password import (
ForgotPasswordResetApi,
ForgotPasswordSendEmailApi,
)
from models.account import Account
from models.engine import db
from services.feature_service import SystemFeatureModel
@pytest.fixture
def database_app() -> Iterator[Flask]:
app = Flask(__name__)
app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///:memory:"
db.init_app(app)
with app.app_context():
Account.__table__.create(db.engine)
yield app
@pytest.fixture(autouse=True)
def _patch_wraps():
wraps_features = SimpleNamespace(enable_email_password_login=True)
dify_settings = SimpleNamespace(ENTERPRISE_ENABLED=True, EDITION="CLOUD")
wraps_features = SystemFeatureModel(enable_email_password_login=True)
with (
patch("controllers.console.wraps.db") as mock_db,
patch("controllers.console.wraps.dify_config", dify_settings),
patch("controllers.console.wraps.dify_config.ENTERPRISE_ENABLED", True),
patch("controllers.console.wraps.dify_config.EDITION", "CLOUD"),
patch("controllers.console.wraps.FeatureService.get_system_features", return_value=wraps_features),
):
yield
class TestForgotPasswordSendEmailApi:
@pytest.fixture
def app(self, flask_app_with_containers: Flask):
return flask_app_with_containers
@patch("controllers.web.forgot_password.AccountService.send_reset_password_email")
@patch("controllers.web.forgot_password.AccountService.get_account_by_email_with_case_fallback")
@patch("controllers.web.forgot_password.AccountService.is_email_send_ip_limit", return_value=False)
@ -64,10 +74,6 @@ class TestForgotPasswordSendEmailApi:
class TestForgotPasswordCheckApi:
@pytest.fixture
def app(self, flask_app_with_containers: Flask):
return flask_app_with_containers
@patch("controllers.web.forgot_password.AccountService.reset_forgot_password_error_rate_limit")
@patch("controllers.web.forgot_password.AccountService.generate_reset_password_token")
@patch("controllers.web.forgot_password.AccountService.revoke_reset_password_token")
@ -142,30 +148,25 @@ class TestForgotPasswordCheckApi:
class TestForgotPasswordResetApi:
@pytest.fixture
def app(self, flask_app_with_containers: Flask):
return flask_app_with_containers
@patch("controllers.web.forgot_password.ForgotPasswordResetApi._update_existing_account")
@patch("controllers.web.forgot_password.AccountService.get_account_by_email_with_case_fallback")
@patch("controllers.web.forgot_password.db")
@patch("controllers.web.forgot_password.AccountService.revoke_reset_password_token")
@patch("controllers.web.forgot_password.AccountService.get_reset_password_data")
def test_should_fetch_account_with_fallback(
self,
mock_get_reset_data,
mock_revoke_token,
mock_db,
mock_get_account,
mock_update_account,
app: Flask,
database_app: Flask,
):
mock_get_reset_data.return_value = {"phase": "reset", "email": "User@Example.com", "code": "1234"}
mock_account = MagicMock()
mock_get_account.return_value = mock_account
mock_db.session.merge.return_value = mock_account
account = Account(name="User", email="user@example.com")
db.session.add(account)
db.session.commit()
mock_get_account.return_value = account
with app.test_request_context(
with database_app.test_request_context(
"/web/forgot-password/resets",
method="POST",
json={
@ -183,7 +184,6 @@ class TestForgotPasswordResetApi:
@patch("controllers.web.forgot_password.hash_password", return_value=b"hashed-value")
@patch("controllers.web.forgot_password.secrets.token_bytes", return_value=b"0123456789abcdef")
@patch("controllers.web.forgot_password.db")
@patch("controllers.web.forgot_password.AccountService.revoke_reset_password_token")
@patch("controllers.web.forgot_password.AccountService.get_reset_password_data")
@patch("controllers.web.forgot_password.AccountService.get_account_by_email_with_case_fallback")
@ -192,17 +192,17 @@ class TestForgotPasswordResetApi:
mock_get_account,
mock_get_reset_data,
mock_revoke_token,
mock_db,
mock_token_bytes,
mock_hash_password,
app: Flask,
database_app: Flask,
):
mock_get_reset_data.return_value = {"phase": "reset", "email": "user@example.com"}
account = MagicMock()
account = Account(name="User", email="user@example.com")
db.session.add(account)
db.session.commit()
mock_get_account.return_value = account
mock_db.session.merge.return_value = account
with app.test_request_context(
with database_app.test_request_context(
"/web/forgot-password/resets",
method="POST",
json={
@ -218,7 +218,10 @@ class TestForgotPasswordResetApi:
mock_revoke_token.assert_called_once_with("reset-token")
mock_token_bytes.assert_called_once_with(16)
mock_hash_password.assert_called_once_with("StrongPass123!", b"0123456789abcdef")
db.session.expire_all()
stored_account = db.session.get(Account, account.id)
assert stored_account is not None
expected_password = base64.b64encode(b"hashed-value").decode()
assert account.password == expected_password
assert stored_account.password == expected_password
expected_salt = base64.b64encode(b"0123456789abcdef").decode()
assert account.password_salt == expected_salt
assert stored_account.password_salt == expected_salt