您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

test_flask_utils.py 4.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. import contextvars
  2. import threading
  3. import pytest
  4. from flask import Flask
  5. from flask_login import LoginManager, UserMixin, current_user, login_user
  6. from libs.flask_utils import preserve_flask_contexts
  7. class User(UserMixin):
  8. """Simple User class for testing."""
  9. def __init__(self, id: str):
  10. self.id = id
  11. def get_id(self) -> str:
  12. return self.id
  13. @pytest.fixture
  14. def login_app(app: Flask) -> Flask:
  15. """Set up a Flask app with flask-login."""
  16. # Set a secret key for the app
  17. app.config["SECRET_KEY"] = "test-secret-key"
  18. login_manager = LoginManager()
  19. login_manager.init_app(app)
  20. @login_manager.user_loader
  21. def load_user(user_id: str) -> User | None:
  22. if user_id == "test_user":
  23. return User("test_user")
  24. return None
  25. return app
  26. @pytest.fixture
  27. def test_user() -> User:
  28. """Create a test user."""
  29. return User("test_user")
  30. def test_current_user_not_accessible_across_threads(login_app: Flask, test_user: User):
  31. """
  32. Test that current_user is not accessible in a different thread without preserve_flask_contexts.
  33. This test demonstrates that without the preserve_flask_contexts, we cannot access
  34. current_user in a different thread, even with app_context.
  35. """
  36. # Log in the user in the main thread
  37. with login_app.test_request_context():
  38. login_user(test_user)
  39. assert current_user.is_authenticated
  40. assert current_user.id == "test_user"
  41. # Store the result of the thread execution
  42. result = {"user_accessible": True, "error": None}
  43. # Define a function to run in a separate thread
  44. def check_user_in_thread():
  45. try:
  46. # Try to access current_user in a different thread with app_context
  47. with login_app.app_context():
  48. # This should fail because current_user is not accessible across threads
  49. # without preserve_flask_contexts
  50. result["user_accessible"] = current_user.is_authenticated
  51. except Exception as e:
  52. result["error"] = str(e) # type: ignore
  53. # Run the function in a separate thread
  54. thread = threading.Thread(target=check_user_in_thread)
  55. thread.start()
  56. thread.join()
  57. # Verify that we got an error or current_user is not authenticated
  58. assert result["error"] is not None or (result["user_accessible"] is not None and not result["user_accessible"])
  59. def test_current_user_accessible_with_preserve_flask_contexts(login_app: Flask, test_user: User):
  60. """
  61. Test that current_user is accessible in a different thread with preserve_flask_contexts.
  62. This test demonstrates that with the preserve_flask_contexts, we can access
  63. current_user in a different thread.
  64. """
  65. # Log in the user in the main thread
  66. with login_app.test_request_context():
  67. login_user(test_user)
  68. assert current_user.is_authenticated
  69. assert current_user.id == "test_user"
  70. # Save the context variables
  71. context_vars = contextvars.copy_context()
  72. # Store the result of the thread execution
  73. result = {"user_accessible": False, "user_id": None, "error": None}
  74. # Define a function to run in a separate thread
  75. def check_user_in_thread_with_manager():
  76. try:
  77. # Use preserve_flask_contexts to access current_user in a different thread
  78. with preserve_flask_contexts(login_app, context_vars):
  79. from flask_login import current_user
  80. if current_user:
  81. result["user_accessible"] = True
  82. result["user_id"] = current_user.id
  83. else:
  84. result["user_accessible"] = False
  85. except Exception as e:
  86. result["error"] = str(e) # type: ignore
  87. # Run the function in a separate thread
  88. thread = threading.Thread(target=check_user_in_thread_with_manager)
  89. thread.start()
  90. thread.join()
  91. # Verify that current_user is accessible and has the correct ID
  92. assert result["error"] is None
  93. assert result["user_accessible"] is True
  94. assert result["user_id"] == "test_user"