-
Notifications
You must be signed in to change notification settings - Fork 2k
Stabilize backend unit smoke tests on Windows #7790
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -7,6 +7,7 @@ | |
| import os | ||
| import sys | ||
| import types | ||
| import functools | ||
| from unittest.mock import MagicMock, AsyncMock, patch | ||
|
|
||
| import pytest | ||
|
|
@@ -39,6 +40,7 @@ | |
| "llm_usage", | ||
| "chat", | ||
| "goals", | ||
| "webhook_health", | ||
| ]: | ||
| mod = types.ModuleType(f"database.{submod}") | ||
| sys.modules.setdefault(f"database.{submod}", mod) | ||
|
|
@@ -65,6 +67,11 @@ | |
| sys.modules["database.notifications"].get_mentor_notification_frequency = MagicMock(return_value=0) | ||
| sys.modules["database.conversations"].get_conversations_by_id = MagicMock(return_value=[]) | ||
| sys.modules["database.goals"].get_user_goals = MagicMock(return_value=[]) | ||
| sys.modules["database.users"].get_user_language_preference = MagicMock(return_value="en") | ||
| sys.modules["database.webhook_health"].record_app_webhook_failure = MagicMock(return_value=0) | ||
| sys.modules["database.webhook_health"].record_app_webhook_success = MagicMock() | ||
| sys.modules["database.webhook_health"].is_app_webhook_disabled = MagicMock(return_value=False) | ||
| sys.modules["database.webhook_health"].disable_app_in_firestore = MagicMock() | ||
|
|
||
| for name in [ | ||
| "utils.apps", | ||
|
|
@@ -78,12 +85,14 @@ | |
| "utils.mentor_notifications", | ||
| "utils.log_sanitizer", | ||
| "utils.http_client", | ||
| "utils.subscription", | ||
| ]: | ||
| if name not in sys.modules: | ||
| sys.modules[name] = types.ModuleType(name) | ||
|
|
||
| sys.modules["utils.apps"].get_available_apps = MagicMock(return_value=[]) | ||
| sys.modules["utils.notifications"].send_notification = MagicMock() | ||
| sys.modules["utils.subscription"].is_trial_paywalled = MagicMock(return_value=False) | ||
| sys.modules["utils.llm.clients"].generate_embedding = MagicMock(return_value=[0] * 3072) | ||
| sys.modules["utils.mentor_notifications"].process_mentor_notification = MagicMock(return_value=None) | ||
| sys.modules["utils.log_sanitizer"].sanitize = MagicMock(side_effect=lambda x: x) | ||
|
|
@@ -131,6 +140,7 @@ def _noop_track(uid, feature): | |
| _mock_cb.record_failure = MagicMock() | ||
| _http_mod.get_webhook_circuit_breaker = MagicMock(return_value=_mock_cb) | ||
| _http_mod.get_webhook_semaphore = MagicMock(return_value=_asyncio.Semaphore(64)) | ||
| _http_mod.get_maps_semaphore = MagicMock(return_value=_asyncio.Semaphore(64)) | ||
| _http_mod.latest_wins_start = MagicMock(return_value=1) | ||
| _http_mod.latest_wins_check = MagicMock(return_value=True) | ||
|
|
||
|
|
@@ -140,12 +150,22 @@ def _noop_track(uid, feature): | |
|
|
||
| if "utils.executors" not in sys.modules: | ||
| sys.modules["utils.executors"] = types.ModuleType("utils.executors") | ||
| sys.modules["utils.executors"].db_executor = _TPE(max_workers=2, thread_name_prefix="test-db") | ||
| sys.modules["utils.executors"].critical_executor = _TPE(max_workers=2, thread_name_prefix="test-critical") | ||
| sys.modules["utils.executors"].storage_executor = _TPE(max_workers=2, thread_name_prefix="test-storage") | ||
|
|
||
|
|
||
| async def _run_blocking(_executor, fn, *args, **kwargs): | ||
| loop = _asyncio.get_running_loop() | ||
| return await loop.run_in_executor(_executor, functools.partial(fn, *args, **kwargs)) | ||
|
|
||
|
|
||
| sys.modules["utils.executors"].run_blocking = _run_blocking | ||
|
Comment on lines
+158
to
+163
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
The stub bypasses executor dispatch entirely. If Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Addressed in loop = _asyncio.get_running_loop()
return await loop.run_in_executor(_executor, functools.partial(fn, *args, **kwargs))It also uses real Revalidated on the Windows backend venv:
|
||
|
|
||
| import importlib | ||
|
|
||
| app_integrations = importlib.import_module("utils.app_integrations") | ||
| sys.modules["utils"].mentor_notifications = sys.modules["utils.mentor_notifications"] | ||
|
|
||
|
|
||
| def _make_app(app_id: str, webhook_url: str, triggers_realtime=False, triggers_audio=False, uid=None): | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
_zoneinfo_for_testexcept Exceptionswallows any error thatZoneInfomight raise, not just the expectedZoneInfoNotFoundError/KeyError. If someone passes a known key like"UTC"butZoneInfofails for an unrelated reason (e.g., corrupted module state), the function silently returnstimezone.utcinstead of surfacing the real problem. The fallbackraiseat the bottom only helps for unknown keys. Usingexcept (ZoneInfoNotFoundError, KeyError)(both fromzoneinfo) would constrain the catch to the specific Windows/no-tzdata scenario this helper targets.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Addressed in
fb41d75ab._zoneinfo_for_testnow importsZoneInfoNotFoundErrorand only catches(ZoneInfoNotFoundError, KeyError), so unexpectedZoneInfofailures are no longer swallowed by the Windows fallback.Revalidated on the Windows backend venv:
python -m pytest tests\unit\test_action_item_date_validation.py -q-> 26 passedpython -m black --line-length 120 --skip-string-normalization tests\unit\test_action_item_date_validation.py tests\unit\test_async_app_integrations.py --checkpython -m py_compile tests\unit\test_action_item_date_validation.py tests\unit\test_async_app_integrations.py