Skip to content

Commit 07ad6b6

Browse files
committed
Handle redirect reloading and restore more robustly
1 parent 97d8b23 commit 07ad6b6

File tree

2 files changed

+58
-48
lines changed

2 files changed

+58
-48
lines changed

bedrock/firefox/tests/test_redirects.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
import pytest
1111

1212
from bedrock.firefox.redirects import mobile_app, validate_param_value
13-
from tests.utils import reload_redirects_with_settings
13+
from tests.utils import enable_fxc_redirects
1414

1515

1616
@pytest.mark.parametrize(
@@ -94,7 +94,7 @@ def test_mobile_app():
9494
EXPECTED_REDIRECT_QS = "?redirect_source=mozilla-org"
9595

9696

97-
@reload_redirects_with_settings("bedrock.firefox.redirects", ENABLE_FIREFOX_COM_REDIRECTS=True)
97+
@enable_fxc_redirects()
9898
@pytest.mark.django_db
9999
@pytest.mark.parametrize(
100100
"path,expected_location,expected_status,follow_redirects",
@@ -468,7 +468,7 @@ def test_springfield_redirect_patterns(
468468
assert response.headers["Location"] == expected_location
469469

470470

471-
@reload_redirects_with_settings("bedrock.firefox.redirects", ENABLE_FIREFOX_COM_REDIRECTS=True)
471+
@enable_fxc_redirects()
472472
@pytest.mark.django_db
473473
@pytest.mark.parametrize(
474474
"path,expected_location,expected_status,follow_redirects",
@@ -505,7 +505,7 @@ def test_springfield_redirects_carry_over_querystrings_and_add_redirect_source(
505505
assert response.headers["Location"] == expected_location
506506

507507

508-
@reload_redirects_with_settings("bedrock.firefox.redirects", ENABLE_FIREFOX_COM_REDIRECTS=True)
508+
@enable_fxc_redirects()
509509
@pytest.mark.django_db
510510
@pytest.mark.parametrize(
511511
"path",
@@ -529,7 +529,7 @@ def test_mobile_app_redirector_does_not_go_to_springfield(client):
529529
assert resp.headers["Location"] == "https://apps.apple.com/app/apple-store/id989804926"
530530

531531

532-
@reload_redirects_with_settings("bedrock.firefox.redirects", ENABLE_FIREFOX_COM_REDIRECTS=True)
532+
@enable_fxc_redirects()
533533
@pytest.mark.django_db
534534
@pytest.mark.parametrize(
535535
"path",
@@ -562,7 +562,7 @@ def test_releasenotes_generic_urls_not_rediected_to_springfield(client, path):
562562
("/en-US/firefox/installer-help/", f"{settings.FXC_BASE_URL}/en-US/download/installer-help/{EXPECTED_REDIRECT_QS}"),
563563
),
564564
)
565-
@reload_redirects_with_settings("bedrock.firefox.redirects", ENABLE_FIREFOX_COM_REDIRECTS=True)
565+
@enable_fxc_redirects()
566566
def test_subsequent_redirects_do_not_carry_querystrings_from_earlier_requests(
567567
client,
568568
path,
@@ -585,7 +585,7 @@ def test_subsequent_redirects_do_not_carry_querystrings_from_earlier_requests(
585585
("/firefox/browsers/incognito-browser/", f"{settings.FXC_BASE_URL}/more/incognito-browser/{EXPECTED_REDIRECT_QS}"),
586586
),
587587
)
588-
@reload_redirects_with_settings("bedrock.firefox.redirects", ENABLE_FIREFOX_COM_REDIRECTS=True)
588+
@enable_fxc_redirects()
589589
def test_offsite_redirects_still_work_when_locale_not_in_source_path(
590590
client,
591591
path,

tests/utils.py

Lines changed: 51 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -10,25 +10,31 @@
1010
from django.test import override_settings
1111

1212

13-
def reload_redirects_with_settings(module_path: str, **settings_kwargs):
13+
def reload_redirects_with_settings(redirects_module_path: str, middleware_module_path: str, **settings_kwargs):
1414
"""
1515
Generic decorator that enables dynamic redirect reloading for testing.
1616
1717
This decorator:
18-
1. Overrides specified settings using the same pattern as @override_settings
19-
2. Reloads the specified redirects module to pick up new patterns
20-
3. Patches the redirects middleware to use the reloaded patterns
21-
4. Restores original state after the test
18+
1. Stores the original setting values before any changes
19+
2. Overrides specified settings using the same pattern as @override_settings
20+
3. Reloads the specified redirects module to pick up new patterns
21+
4. Patches the specified middleware module to use the reloaded patterns
22+
5. Restores original settings and reloads module again after the test
2223
2324
This is needed because Django loads redirects once at startup and doesn't
2425
reload them when @override_settings is used.
2526
2627
Args:
27-
module_path: The module path to reload (e.g., 'bedrock.firefox.redirects')
28-
**settings_kwargs: Settings to override (e.g., ENABLE_FIREFOX_COM_REDIRECTS=True)
28+
redirects_module_path: The redirects module path to reload
29+
middleware_module_path: The middleware module path to patch
30+
**settings_kwargs: Settings to override
2931
3032
Usage:
31-
@reload_redirects_with_settings('bedrock.firefox.redirects', ENABLE_FIREFOX_COM_REDIRECTS=True)
33+
@reload_redirects_with_settings(
34+
'bedrock.firefox.redirects',
35+
'bedrock.redirects.middleware',
36+
ENABLE_FIREFOX_COM_REDIRECTS=True
37+
)
3238
def test_my_redirect():
3339
# Your test code here
3440
pass
@@ -37,63 +43,67 @@ def test_my_redirect():
3743
def decorator(func: Callable) -> Callable:
3844
@functools.wraps(func)
3945
def wrapper(*args: Any, **kwargs: Any) -> Any:
46+
from django.conf import settings
47+
48+
original_settings = {}
49+
for setting_name in settings_kwargs.keys():
50+
original_settings[setting_name] = getattr(settings, setting_name, None)
51+
4052
with override_settings(**settings_kwargs):
41-
original_patterns, original_resolver = _patch_redirects_middleware(module_path)
53+
original_get_resolver = _reload_module_and_patch_middleware(redirects_module_path, middleware_module_path)
4254
try:
4355
return func(*args, **kwargs)
4456
finally:
45-
_restore_redirects_middleware(module_path, original_patterns, original_resolver)
57+
restore_settings = {name: value for name, value in original_settings.items()}
58+
with override_settings(**restore_settings):
59+
_reload_module_and_patch_middleware(redirects_module_path, middleware_module_path)
60+
middleware_module = importlib.import_module(middleware_module_path)
61+
middleware_module.get_resolver = original_get_resolver
4662

4763
return wrapper
4864

4965
return decorator
5066

5167

52-
def _patch_redirects_middleware(module_path: str) -> tuple[Any, Any]:
68+
def _reload_module_and_patch_middleware(redirects_module_path: str, middleware_module_path: str) -> Any:
5369
"""
54-
Patch the redirects middleware to use reloaded patterns from the specified module.
70+
Import, reload the specified module, and patch the redirects middleware.
5571
5672
Args:
57-
module_path: The module path to reload
73+
redirects_module_path: The redirects module path to reload
74+
middleware_module_path: The middleware module path to patch
5875
5976
Returns:
60-
Tuple of (original_patterns, original_resolver) for restoration
77+
The original get_resolver function for restoration
6178
"""
62-
import bedrock.redirects.middleware
63-
64-
# Import and reload the specified module
65-
module = importlib.import_module(module_path)
66-
importlib.reload(module) # type: ignore
79+
middleware_module = importlib.import_module(middleware_module_path)
6780

68-
# Store original state
69-
original_patterns = module.redirectpatterns # type: ignore
70-
original_resolver = bedrock.redirects.middleware.get_resolver
81+
redirects_module = importlib.import_module(redirects_module_path)
82+
importlib.reload(redirects_module) # type: ignore
83+
original_get_resolver = middleware_module.get_resolver
7184

72-
# Patch the resolver to use the reloaded patterns
7385
def patched_get_resolver(patterns=None):
7486
if patterns is None:
75-
patterns = module.redirectpatterns # type: ignore
76-
return original_resolver(patterns)
87+
patterns = redirects_module.redirectpatterns # type: ignore
88+
return original_get_resolver(patterns)
7789

78-
bedrock.redirects.middleware.get_resolver = patched_get_resolver
90+
middleware_module.get_resolver = patched_get_resolver
7991

80-
return original_patterns, original_resolver
92+
return original_get_resolver
8193

8294

83-
def _restore_redirects_middleware(module_path: str, original_patterns: Any, original_resolver: Any) -> None:
84-
"""
85-
Restore the original redirects middleware state.
86-
87-
Args:
88-
module_path: The module path that was reloaded
89-
original_patterns: The original redirectpatterns to restore
90-
original_resolver: The original get_resolver function to restore
95+
def enable_fxc_redirects():
9196
"""
92-
import bedrock.redirects.middleware
97+
Convenience decorator for Firefox.com redirect testing.
9398
94-
# Restore original patterns
95-
module = importlib.import_module(module_path)
96-
module.redirectpatterns = original_patterns # type: ignore
99+
This is a wrapper around reload_redirects_with_settings that enables
100+
Firefox.com redirects for the duration of the test regardless of the
101+
ENABLE_FIREFOX_COM_REDIRECTS environment variable.
97102
98-
# Restore original resolver
99-
bedrock.redirects.middleware.get_resolver = original_resolver
103+
Usage:
104+
@enable_fxc_redirects()
105+
def test_my_redirect():
106+
# Your test code here
107+
pass
108+
"""
109+
return reload_redirects_with_settings("bedrock.firefox.redirects", "bedrock.redirects.middleware", ENABLE_FIREFOX_COM_REDIRECTS=True)

0 commit comments

Comments
 (0)