From 3971145bc7ae9286cef5e93f041aea82553581a2 Mon Sep 17 00:00:00 2001 From: Feanil Patel Date: Wed, 19 Aug 2026 11:16:02 -0400 Subject: [PATCH 1/8] refactor: migrate EMBARGO test overrides off FEATURES-as-dict The EMBARGO production readers (lms/urls.py, openedx/core/djangoapps/embargo/api.py) already read flat settings.EMBARGO; two verify_student view tests still set the flag via @patch.dict(settings.FEATURES, {'EMBARGO': True}). Convert them to @override_settings(EMBARGO=True) (matching the already-migrated decorator elsewhere in the file) so no settings.FEATURES usage remains here. Co-Authored-By: Claude Opus 4.8 --- lms/djangoapps/verify_student/tests/test_views.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lms/djangoapps/verify_student/tests/test_views.py b/lms/djangoapps/verify_student/tests/test_views.py index 330481ee694f..a2e0d360dfea 100644 --- a/lms/djangoapps/verify_student/tests/test_views.py +++ b/lms/djangoapps/verify_student/tests/test_views.py @@ -792,7 +792,7 @@ def test_course_mode_not_expired_verification_deadline_passed(self): self.assertContains(response, "verification deadline") self.assertContains(response, verification_deadline_in_past) - @patch.dict(settings.FEATURES, {'EMBARGO': True}) + @override_settings(EMBARGO=True) @ddt.data("verify_student_start_flow", "verify_student_begin_flow") def test_embargo_restrict(self, payment_flow): course = self._create_course("verified") @@ -802,7 +802,7 @@ def test_embargo_restrict(self, payment_flow): response = self._get_page(payment_flow, course.id, expected_status_code=302) self.assertRedirects(response, redirect_url) - @patch.dict(settings.FEATURES, {'EMBARGO': True}) + @override_settings(EMBARGO=True) @ddt.data("verify_student_start_flow", "verify_student_begin_flow") def test_embargo_allow(self, payment_flow): course = self._create_course("verified") From 0fd354b81f919e399eda0c1ab6b939fe9c00a86f Mon Sep 17 00:00:00 2001 From: Feanil Patel Date: Wed, 19 Aug 2026 11:18:26 -0400 Subject: [PATCH 2/8] refactor: migrate ENABLE_CORS_HEADERS and ENABLE_CROSS_DOMAIN_CSRF_COOKIE test overrides off FEATURES-as-dict Both flags' production readers (openedx/core/djangoapps/cors_csrf/middleware.py) already read flat settings.ENABLE_CORS_HEADERS / settings.ENABLE_CROSS_DOMAIN_CSRF_COOKIE. Two tests still enabled them via @patch.dict(settings.FEATURES, {...}) sitting next to an override_settings for the companion CORS_* settings. Fold the two flags into the adjacent override_settings so no settings.FEATURES usage remains, and drop the now-unused patch import in the cors_csrf test. Co-Authored-By: Claude Opus 4.8 --- lms/djangoapps/experiments/tests/test_views.py | 12 ++++-------- .../cors_csrf/tests/test_authentication.py | 8 ++------ 2 files changed, 6 insertions(+), 14 deletions(-) diff --git a/lms/djangoapps/experiments/tests/test_views.py b/lms/djangoapps/experiments/tests/test_views.py index e37ecd59ade6..dcf9834bef4a 100644 --- a/lms/djangoapps/experiments/tests/test_views.py +++ b/lms/djangoapps/experiments/tests/test_views.py @@ -178,11 +178,9 @@ def test_loads_valid_csrf_trusted_origins_list(self): def cross_domain_config(func): """Decorator for configuring a cross-domain request. """ - feature_flag_decorator = patch.dict(settings.FEATURES, { - 'ENABLE_CORS_HEADERS': True, - 'ENABLE_CROSS_DOMAIN_CSRF_COOKIE': True - }) settings_decorator = override_settings( + ENABLE_CORS_HEADERS=True, + ENABLE_CROSS_DOMAIN_CSRF_COOKIE=True, CORS_ORIGIN_WHITELIST=['https://ecommerce.edx.org'], CSRF_COOKIE_NAME="prod-edx-csrftoken", CROSS_DOMAIN_CSRF_COOKIE_NAME="prod-edx-csrftoken", @@ -190,10 +188,8 @@ def cross_domain_config(func): ) is_secure_decorator = patch.object(WSGIRequest, 'is_secure', return_value=True) - return feature_flag_decorator( - settings_decorator( - is_secure_decorator(func) - ) + return settings_decorator( + is_secure_decorator(func) ) diff --git a/openedx/core/djangoapps/cors_csrf/tests/test_authentication.py b/openedx/core/djangoapps/cors_csrf/tests/test_authentication.py index 237e341bcd8d..1e1c05e6f1b4 100644 --- a/openedx/core/djangoapps/cors_csrf/tests/test_authentication.py +++ b/openedx/core/djangoapps/cors_csrf/tests/test_authentication.py @@ -1,8 +1,6 @@ """Tests for the CORS CSRF version of Django Rest Framework's SessionAuthentication.""" -from unittest.mock import patch - from django.conf import settings from django.middleware.csrf import get_token from django.test import TestCase @@ -34,11 +32,9 @@ def test_perform_csrf_referer_check(self): with self.assertRaisesRegex(PermissionDenied, 'CSRF'): # noqa: PT027 self.auth.enforce_csrf(request) - @patch.dict(settings.FEATURES, { - 'ENABLE_CORS_HEADERS': True, - 'ENABLE_CROSS_DOMAIN_CSRF_COOKIE': True - }) @override_settings( + ENABLE_CORS_HEADERS=True, + ENABLE_CROSS_DOMAIN_CSRF_COOKIE=True, CORS_ORIGIN_WHITELIST=["https://www.edx.org"], CROSS_DOMAIN_CSRF_COOKIE_NAME="prod-edx-csrftoken", CROSS_DOMAIN_CSRF_COOKIE_DOMAIN=".edx.org" From 71157176a99e7b73235970d6628bac5da4e22db8 Mon Sep 17 00:00:00 2001 From: Feanil Patel Date: Wed, 19 Aug 2026 11:19:23 -0400 Subject: [PATCH 3/8] refactor: migrate ENABLE_TEXTBOOK and ENABLE_EDXNOTES test overrides off FEATURES-as-dict Both flags' production readers already read flat settings (courseware/plugins.py, courseware/tabs.py, edxnotes/decorators.py, cms course_metadata.py). One tabs test still enabled them via @patch.dict(settings.FEATURES, {...}) alongside an @override_settings(ENABLE_DISCUSSION_SERVICE=True); fold both flags into that override_settings so no settings.FEATURES usage remains. Co-Authored-By: Claude Opus 4.8 --- lms/djangoapps/courseware/tests/test_tabs.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lms/djangoapps/courseware/tests/test_tabs.py b/lms/djangoapps/courseware/tests/test_tabs.py index 1f51ede61d5c..b9b2c6f8f070 100644 --- a/lms/djangoapps/courseware/tests/test_tabs.py +++ b/lms/djangoapps/courseware/tests/test_tabs.py @@ -615,11 +615,11 @@ def test_initialize_default_without_external_link(self): assert not self.has_tab(self.course.tabs, 'external_discussion') assert self.has_tab(self.course.tabs, 'discussion') - @override_settings(ENABLE_DISCUSSION_SERVICE=True) - @patch.dict("django.conf.settings.FEATURES", { - "ENABLE_TEXTBOOK": True, - "ENABLE_EDXNOTES": True, - }) + @override_settings( + ENABLE_DISCUSSION_SERVICE=True, + ENABLE_TEXTBOOK=True, + ENABLE_EDXNOTES=True, + ) def test_iterate_displayable(self): self.course.hide_progress_tab = False From d1f4484dc681c315da0c04e2a4ebbf88bdc3e37c Mon Sep 17 00:00:00 2001 From: Feanil Patel Date: Wed, 19 Aug 2026 11:23:03 -0400 Subject: [PATCH 4/8] refactor: migrate ENABLE_THIRD_PARTY_AUTH test usages off FEATURES-as-dict The ENABLE_THIRD_PARTY_AUTH production readers already read flat settings.ENABLE_THIRD_PARTY_AUTH (lms/urls.py, oauth_dispatch/urls.py). Remaining test usages: - test_login.py / test_register.py enabled it via patch.dict(settings.FEATURES, {...}), now override_settings(ENABLE_THIRD_PARTY_AUTH=True). - third_party_auth/tests/specs/base.py gated IntegrationTest with "AUTH_FEATURES_KEY in django_settings.FEATURES"; switched to the flat-based testutil.AUTH_FEATURE_ENABLED (hasattr(settings, 'ENABLE_THIRD_PARTY_AUTH')), matching the pattern already used in third_party_auth/tests/test_views.py. Co-Authored-By: Claude Opus 4.8 --- common/djangoapps/third_party_auth/tests/specs/base.py | 2 +- openedx/core/djangoapps/user_authn/views/tests/test_login.py | 4 +--- .../core/djangoapps/user_authn/views/tests/test_register.py | 4 +--- 3 files changed, 3 insertions(+), 7 deletions(-) diff --git a/common/djangoapps/third_party_auth/tests/specs/base.py b/common/djangoapps/third_party_auth/tests/specs/base.py index 0d71479ec0ed..6efb9964d832 100644 --- a/common/djangoapps/third_party_auth/tests/specs/base.py +++ b/common/djangoapps/third_party_auth/tests/specs/base.py @@ -576,7 +576,7 @@ def complete_url(self): @unittest.skipUnless( - testutil.AUTH_FEATURES_KEY in django_settings.FEATURES, testutil.AUTH_FEATURES_KEY + " not in settings.FEATURES" + testutil.AUTH_FEATURE_ENABLED, testutil.AUTH_FEATURES_KEY + " not enabled" ) @django_utils.override_settings() # For settings reversion on a method-by-method basis. class IntegrationTest(testutil.TestCase, test.TestCase, HelperMixin): diff --git a/openedx/core/djangoapps/user_authn/views/tests/test_login.py b/openedx/core/djangoapps/user_authn/views/tests/test_login.py index 3a9979b84228..24c13a6996b0 100644 --- a/openedx/core/djangoapps/user_authn/views/tests/test_login.py +++ b/openedx/core/djangoapps/user_authn/views/tests/test_login.py @@ -111,9 +111,7 @@ def test_login_failed_with_opt_in_flag_disabled(self): mock_audit_log, 'warning', ['Login failed - Account not active for user.id: 1, resending activation'] ) - @patch.dict(settings.FEATURES, { - "ENABLE_THIRD_PARTY_AUTH": True - }) + @override_settings(ENABLE_THIRD_PARTY_AUTH=True) @patch( 'openedx.core.djangoapps.user_authn.views.login.is_require_third_party_auth_enabled', Mock(return_value=True) diff --git a/openedx/core/djangoapps/user_authn/views/tests/test_register.py b/openedx/core/djangoapps/user_authn/views/tests/test_register.py index ed95fbc39342..b74dd3a5ec3a 100644 --- a/openedx/core/djangoapps/user_authn/views/tests/test_register.py +++ b/openedx/core/djangoapps/user_authn/views/tests/test_register.py @@ -96,9 +96,7 @@ def setUp(self): # pylint: disable=arguments-differ super().setUp() self.url = reverse("user_api_registration") - @mock.patch.dict(settings.FEATURES, { - "ENABLE_THIRD_PARTY_AUTH": True, - }) + @override_settings(ENABLE_THIRD_PARTY_AUTH=True) @mock.patch( 'openedx.core.djangoapps.user_authn.views.register.is_require_third_party_auth_enabled', mock.Mock(return_value=True) From 5761f8c9f6dfa49551cc75e0a3e0bb602bc23f08 Mon Sep 17 00:00:00 2001 From: Feanil Patel Date: Wed, 19 Aug 2026 11:24:31 -0400 Subject: [PATCH 5/8] refactor: migrate ENABLE_EXPORT_GIT test override off FEATURES-as-dict The production reader is a SettingToggle('ENABLE_EXPORT_GIT') that reads the flat settings.ENABLE_EXPORT_GIT. The git-export command test still enabled it by building a FEATURES_WITH_EXPORT_GIT = settings.FEATURES.copy() and applying @override_settings(FEATURES=...). Drop the dict copy and fold ENABLE_EXPORT_GIT=True into the class-level override_settings so no settings.FEATURES usage remains; the SettingToggle picks up the flat override. Co-Authored-By: Claude Opus 4.8 --- .../management/commands/tests/test_git_export.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/cms/djangoapps/contentstore/management/commands/tests/test_git_export.py b/cms/djangoapps/contentstore/management/commands/tests/test_git_export.py index bb8aa136f72e..2dfb42a34049 100644 --- a/cms/djangoapps/contentstore/management/commands/tests/test_git_export.py +++ b/cms/djangoapps/contentstore/management/commands/tests/test_git_export.py @@ -22,14 +22,11 @@ from cms.djangoapps.contentstore.git_export_utils import GitExportError from cms.djangoapps.contentstore.tests.utils import CourseTestCase -FEATURES_WITH_EXPORT_GIT = settings.FEATURES.copy() -FEATURES_WITH_EXPORT_GIT['ENABLE_EXPORT_GIT'] = True TEST_DATA_CONTENTSTORE = copy.deepcopy(settings.CONTENTSTORE) TEST_DATA_CONTENTSTORE['DOC_STORE_CONFIG']['db'] = 'test_xcontent_%s' % uuid4().hex # noqa: UP031 -@override_settings(CONTENTSTORE=TEST_DATA_CONTENTSTORE) -@override_settings(FEATURES=FEATURES_WITH_EXPORT_GIT) +@override_settings(CONTENTSTORE=TEST_DATA_CONTENTSTORE, ENABLE_EXPORT_GIT=True) class TestGitExport(CourseTestCase): """ Excercise the git_export django management command with various inputs. From 1f82a10fee95a7ae2348acad4d6ec3cdb53c5286 Mon Sep 17 00:00:00 2001 From: Feanil Patel Date: Wed, 19 Aug 2026 11:26:21 -0400 Subject: [PATCH 6/8] refactor: migrate CERTS_HTML_VIEW_CONFIG_PATH test override off FEATURES-as-dict CERTS_HTML_VIEW_CONFIG_PATH is not read anywhere in the platform anymore, so the CertificateHtmlViewConfiguration test's FEATURES override is a no-op. It was applied via a FEATURES_INVALID_FILE_PATH = settings.FEATURES.copy() + @override_settings(FEATURES=...). Convert to the equivalent flat @override_settings(CERTS_HTML_VIEW_CONFIG_PATH=...) (still a no-op, but off the dict), drop the dict copy, and remove the now-unused settings import. Co-Authored-By: Claude Opus 4.8 --- lms/djangoapps/certificates/tests/test_models.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/lms/djangoapps/certificates/tests/test_models.py b/lms/djangoapps/certificates/tests/test_models.py index 66bccb2b843d..131e524c2f15 100644 --- a/lms/djangoapps/certificates/tests/test_models.py +++ b/lms/djangoapps/certificates/tests/test_models.py @@ -7,7 +7,6 @@ import ddt import pytest -from django.conf import settings from django.core.exceptions import ValidationError from django.core.files.uploadedfile import SimpleUploadedFile from django.test import TestCase @@ -46,9 +45,6 @@ ENROLLMENT_METHOD = 'common.djangoapps.student.models.course_enrollment.CourseEnrollment.enrollment_mode_for_user' PROFILE_METHOD = 'common.djangoapps.student.models_api.get_name' -FEATURES_INVALID_FILE_PATH = settings.FEATURES.copy() -FEATURES_INVALID_FILE_PATH['CERTS_HTML_VIEW_CONFIG_PATH'] = 'invalid/path/to/config.json' - TEST_DIR = path(__file__).dirname() TEST_DATA_DIR = 'common/test/data/' PLATFORM_ROOT = TEST_DIR.parent.parent.parent.parent @@ -175,7 +171,7 @@ def test_get_not_enabled_returns_blank(self): self.config.save() assert len(self.config.get_config()) == 0 - @override_settings(FEATURES=FEATURES_INVALID_FILE_PATH) + @override_settings(CERTS_HTML_VIEW_CONFIG_PATH='invalid/path/to/config.json') def test_get_no_database_no_file(self): """ Tests get configuration that is not enabled. From d20ed5ca421abc93cc310ad9e2a0fe413e2c5b4e Mon Sep 17 00:00:00 2001 From: Feanil Patel Date: Wed, 19 Aug 2026 11:28:29 -0400 Subject: [PATCH 7/8] docs: drop stale FEATURES-dict references from comments and docstrings These flags are now flat Django settings, but several comments/docstrings still described them as FEATURES-dict keys, and each kept a 'settings.FEATURES' reference alive in a repo-wide grep. Update them to the flat setting they now describe: - embargo/middleware.py: settings.FEATURES['EMBARGO'] -> settings.EMBARGO - git_export.py: FEATURE['ENABLE_EXPORT_GIT'] -> ENABLE_EXPORT_GIT setting - auto_auth.py: settings.FEATURES['AUTOMATIC_AUTH_FOR_TESTING'] -> settings.AUTOMATIC_AUTH_FOR_TESTING - split_mongo/split.py: reword the historical entrance-exams comment off the dict syntax - test_auto_auth.py: update the setUp comments to name the flat setting No code/behavior change; comment/docstring text only. Co-Authored-By: Claude Opus 4.8 --- .../contentstore/management/commands/git_export.py | 2 +- openedx/core/djangoapps/embargo/middleware.py | 2 +- openedx/core/djangoapps/user_authn/views/auto_auth.py | 2 +- .../djangoapps/user_authn/views/tests/test_auto_auth.py | 6 +++--- xmodule/modulestore/split_mongo/split.py | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/cms/djangoapps/contentstore/management/commands/git_export.py b/cms/djangoapps/contentstore/management/commands/git_export.py index 1ab30080f801..0f3e1cfa893d 100644 --- a/cms/djangoapps/contentstore/management/commands/git_export.py +++ b/cms/djangoapps/contentstore/management/commands/git_export.py @@ -10,7 +10,7 @@ any have taken place. This functionality is also available as an export view in studio if the giturl -attribute is set and the FEATURE['ENABLE_EXPORT_GIT'] is set. +attribute is set and the ENABLE_EXPORT_GIT setting is enabled. """ diff --git a/openedx/core/djangoapps/embargo/middleware.py b/openedx/core/djangoapps/embargo/middleware.py index e544c1c53281..5f56c8f9bbd7 100644 --- a/openedx/core/djangoapps/embargo/middleware.py +++ b/openedx/core/djangoapps/embargo/middleware.py @@ -16,7 +16,7 @@ Usage: -1) Enable embargo by setting `settings.FEATURES['EMBARGO']` to True. +1) Enable embargo by setting `settings.EMBARGO` to True. 2) In Django admin, create a new `IPFilter` model to block or whitelist an IP address from accessing the site. diff --git a/openedx/core/djangoapps/user_authn/views/auto_auth.py b/openedx/core/djangoapps/user_authn/views/auto_auth.py index 703a0c6a3c62..1c5af5c0c70c 100644 --- a/openedx/core/djangoapps/user_authn/views/auto_auth.py +++ b/openedx/core/djangoapps/user_authn/views/auto_auth.py @@ -43,7 +43,7 @@ def auto_auth(request): # pylint: disable=too-many-statements Create or configure a user account, then log in as that user. Enabled only when - settings.FEATURES['AUTOMATIC_AUTH_FOR_TESTING'] is true. + settings.AUTOMATIC_AUTH_FOR_TESTING is true. Accepts the following querystring parameters: * `username`, `email`, and `password` for the user account diff --git a/openedx/core/djangoapps/user_authn/views/tests/test_auto_auth.py b/openedx/core/djangoapps/user_authn/views/tests/test_auto_auth.py index b2eb1f371568..bd07ff4ce048 100644 --- a/openedx/core/djangoapps/user_authn/views/tests/test_auto_auth.py +++ b/openedx/core/djangoapps/user_authn/views/tests/test_auto_auth.py @@ -47,7 +47,7 @@ class AutoAuthEnabledTestCase(AutoAuthTestCase, ModuleStoreTestCase): @override_settings(AUTOMATIC_AUTH_FOR_TESTING=True) def setUp(self): - # Patching the settings.FEATURES['AUTOMATIC_AUTH_FOR_TESTING'] + # Patching the AUTOMATIC_AUTH_FOR_TESTING setting # value affects the contents of urls.py, # so we need to call super.setUp() which reloads urls.py (because # of the UrlResetMixin) @@ -305,7 +305,7 @@ class AutoAuthDisabledTestCase(AutoAuthTestCase): @override_settings(AUTOMATIC_AUTH_FOR_TESTING=False) def setUp(self): - # Patching the settings.FEATURES['AUTOMATIC_AUTH_FOR_TESTING'] + # Patching the AUTOMATIC_AUTH_FOR_TESTING setting # value affects the contents of urls.py, # so we need to call super.setUp() which reloads urls.py (because # of the UrlResetMixin) @@ -329,7 +329,7 @@ class AutoAuthRestrictedTestCase(AutoAuthTestCase): @override_settings(AUTOMATIC_AUTH_FOR_TESTING=True) def setUp(self): - # Patching the settings.FEATURES['AUTOMATIC_AUTH_FOR_TESTING'] + # Patching the AUTOMATIC_AUTH_FOR_TESTING setting # value affects the contents of urls.py, # so we need to call super.setUp() which reloads urls.py (because # of the UrlResetMixin) diff --git a/xmodule/modulestore/split_mongo/split.py b/xmodule/modulestore/split_mongo/split.py index 7496f0cf91bd..5a115dd16176 100644 --- a/xmodule/modulestore/split_mongo/split.py +++ b/xmodule/modulestore/split_mongo/split.py @@ -1720,7 +1720,7 @@ def create_child(self, user_id, parent_usage_key, block_type, block_id=None, fie parent = new_structure['blocks'][block_id] - # Originally added to support entrance exams (settings.FEATURES.get('ENTRANCE_EXAMS')) + # Originally added to support entrance exams (the ENTRANCE_EXAMS feature) if kwargs.get('position') is None: parent.fields.setdefault('children', []).append(BlockKey.from_usage_key(xblock.location)) else: From 9466a864358528275bf87ee1bf53557cdcd9c0de Mon Sep 17 00:00:00 2001 From: Feanil Patel Date: Thu, 20 Aug 2026 08:40:10 -0400 Subject: [PATCH 8/8] refactor: replace third_party_auth skip helpers with skip_unless_lms testutil.AUTH_FEATURE_ENABLED was hasattr(settings, 'ENABLE_THIRD_PARTY_AUTH'), which is true under LMS settings (the flag is defined in lms/envs/common.py, absent from cms/envs) and false under CMS, regardless of the flag's value. So both @unittest.skipUnless(AUTH_FEATURE_ENABLED, ...) and the skip_unless_thirdpartyauth() helper (whose docstring literally says "skip ... tests in CMS") were roundabout ways of saying "run only in the LMS test suite" -- but they read as if they gated on the feature being enabled, which was misleading. Replace every usage with the existing @skip_unless_lms decorator and delete AUTH_FEATURES_KEY, AUTH_FEATURE_ENABLED, and skip_unless_thirdpartyauth(). Behavior is unchanged: these tests run in the LMS suite and skip in the CMS suite (verified locally: LMS runs, CMS skips). Co-Authored-By: Claude Opus 4.8 --- .../tests/test_saml_configuration.py | 4 ++-- .../djangoapps/third_party_auth/tests/specs/base.py | 6 ++---- .../third_party_auth/tests/specs/test_generic.py | 4 ++-- .../third_party_auth/tests/specs/test_testshib.py | 7 ++++--- .../djangoapps/third_party_auth/tests/test_admin.py | 4 ++-- .../third_party_auth/tests/test_decorators.py | 4 ++-- .../third_party_auth/tests/test_identityserver3.py | 4 ++-- .../third_party_auth/tests/test_pipeline.py | 6 +++--- .../tests/test_pipeline_integration.py | 4 ++-- .../third_party_auth/tests/test_provider.py | 4 ++-- .../third_party_auth/tests/test_settings.py | 3 +-- .../djangoapps/third_party_auth/tests/test_views.py | 12 ++++++------ common/djangoapps/third_party_auth/tests/testutil.py | 4 ---- common/djangoapps/third_party_auth/tests/utils.py | 12 +----------- 14 files changed, 31 insertions(+), 47 deletions(-) diff --git a/common/djangoapps/third_party_auth/saml_configuration/tests/test_saml_configuration.py b/common/djangoapps/third_party_auth/saml_configuration/tests/test_saml_configuration.py index 341adace754d..e970f4101d4b 100644 --- a/common/djangoapps/third_party_auth/saml_configuration/tests/test_saml_configuration.py +++ b/common/djangoapps/third_party_auth/saml_configuration/tests/test_saml_configuration.py @@ -8,7 +8,7 @@ from common.djangoapps.student.tests.factories import UserFactory from common.djangoapps.third_party_auth.models import SAMLConfiguration -from common.djangoapps.third_party_auth.tests.utils import skip_unless_thirdpartyauth +from openedx.core.djangolib.testing.utils import skip_unless_lms SAML_CONFIGURATIONS = [ { @@ -43,7 +43,7 @@ TEST_PASSWORD = 'testpwd' -@skip_unless_thirdpartyauth() +@skip_unless_lms class SAMLConfigurationTests(APITestCase): """ API Tests for SAMLConfiguration objects retrieval. diff --git a/common/djangoapps/third_party_auth/tests/specs/base.py b/common/djangoapps/third_party_auth/tests/specs/base.py index 6efb9964d832..10a69340b427 100644 --- a/common/djangoapps/third_party_auth/tests/specs/base.py +++ b/common/djangoapps/third_party_auth/tests/specs/base.py @@ -3,7 +3,6 @@ """ import json -import unittest from contextlib import contextmanager from unittest import mock @@ -31,6 +30,7 @@ from openedx.core.djangoapps.user_authn.views.login import login_user from openedx.core.djangoapps.user_authn.views.login_form import login_and_registration_form from openedx.core.djangoapps.user_authn.views.register import RegistrationView +from openedx.core.djangolib.testing.utils import skip_unless_lms def create_account(request): @@ -575,9 +575,7 @@ def complete_url(self): return reverse("social:complete", kwargs={"backend": self.PROVIDER_BACKEND}) -@unittest.skipUnless( - testutil.AUTH_FEATURE_ENABLED, testutil.AUTH_FEATURES_KEY + " not enabled" -) +@skip_unless_lms @django_utils.override_settings() # For settings reversion on a method-by-method basis. class IntegrationTest(testutil.TestCase, test.TestCase, HelperMixin): """Abstract base class for provider integration tests.""" diff --git a/common/djangoapps/third_party_auth/tests/specs/test_generic.py b/common/djangoapps/third_party_auth/tests/specs/test_generic.py index cb82c780c1d9..12d167c8eee6 100644 --- a/common/djangoapps/third_party_auth/tests/specs/test_generic.py +++ b/common/djangoapps/third_party_auth/tests/specs/test_generic.py @@ -2,12 +2,12 @@ Use the 'Dummy' auth provider for generic integration tests of third_party_auth. """ from common.djangoapps.third_party_auth.tests import testutil -from common.djangoapps.third_party_auth.tests.utils import skip_unless_thirdpartyauth +from openedx.core.djangolib.testing.utils import skip_unless_lms from .base import IntegrationTestMixin -@skip_unless_thirdpartyauth() +@skip_unless_lms class GenericIntegrationTest(IntegrationTestMixin, testutil.TestCase): """ Basic integration tests of third_party_auth using Dummy provider diff --git a/common/djangoapps/third_party_auth/tests/specs/test_testshib.py b/common/djangoapps/third_party_auth/tests/specs/test_testshib.py index eddc4dd9c514..8819de5deff8 100644 --- a/common/djangoapps/third_party_auth/tests/specs/test_testshib.py +++ b/common/djangoapps/third_party_auth/tests/specs/test_testshib.py @@ -28,6 +28,7 @@ from common.djangoapps.third_party_auth.tests import testutil, utils from common.test.utils import assert_dict_contains_subset from openedx.core.djangoapps.user_authn.views.login import login_user +from openedx.core.djangolib.testing.utils import skip_unless_lms from .base import IntegrationTestMixin @@ -160,7 +161,7 @@ def do_provider_login(self, provider_redirect_url): @ddt.ddt -@utils.skip_unless_thirdpartyauth() +@skip_unless_lms class TestIndexExceptionTest(SamlIntegrationTestUtilities, IntegrationTestMixin, testutil.SAMLTestCase): """ To test SAML error handling when presented with an empty-list attribute value @@ -199,7 +200,7 @@ def get_response_data(self): @ddt.ddt -@utils.skip_unless_thirdpartyauth() +@skip_unless_lms class TestShibIntegrationTest(SamlIntegrationTestUtilities, IntegrationTestMixin, testutil.SAMLTestCase): """ TestShib provider Integration Test, to test SAML functionality @@ -404,7 +405,7 @@ def test_login_with_testshib_provider_short_session_length(self): self._test_return_login(previous_session_timed_out=True) -@utils.skip_unless_thirdpartyauth() +@skip_unless_lms class SuccessFactorsIntegrationTest(SamlIntegrationTestUtilities, IntegrationTestMixin, testutil.SAMLTestCase): """ Test basic SAML capability using the TestShib details, and then check that we're able diff --git a/common/djangoapps/third_party_auth/tests/test_admin.py b/common/djangoapps/third_party_auth/tests/test_admin.py index fdba2106244f..f3d7630b9340 100644 --- a/common/djangoapps/third_party_auth/tests/test_admin.py +++ b/common/djangoapps/third_party_auth/tests/test_admin.py @@ -11,13 +11,13 @@ from common.djangoapps.third_party_auth.admin import OAuth2ProviderConfigAdmin from common.djangoapps.third_party_auth.models import OAuth2ProviderConfig from common.djangoapps.third_party_auth.tests import testutil -from common.djangoapps.third_party_auth.tests.utils import skip_unless_thirdpartyauth +from openedx.core.djangolib.testing.utils import skip_unless_lms TEST_PASSWORD = 'Password1234' # This is necessary because cms does not implement third party auth -@skip_unless_thirdpartyauth() +@skip_unless_lms class Oauth2ProviderConfigAdminTest(testutil.TestCase): """ Tests for oauth2 provider config admin diff --git a/common/djangoapps/third_party_auth/tests/test_decorators.py b/common/djangoapps/third_party_auth/tests/test_decorators.py index f72720fc2cb8..b7c9b1a3a541 100644 --- a/common/djangoapps/third_party_auth/tests/test_decorators.py +++ b/common/djangoapps/third_party_auth/tests/test_decorators.py @@ -8,7 +8,7 @@ from common.djangoapps.third_party_auth.decorators import xframe_allow_whitelisted from common.djangoapps.third_party_auth.tests.testutil import TestCase -from common.djangoapps.third_party_auth.tests.utils import skip_unless_thirdpartyauth +from openedx.core.djangolib.testing.utils import skip_unless_lms @xframe_allow_whitelisted @@ -17,7 +17,7 @@ def mock_view(_request): return HttpResponse() -@skip_unless_thirdpartyauth() +@skip_unless_lms @ddt.ddt class TestXFrameWhitelistDecorator(TestCase): """ Test the xframe_allow_whitelisted decorator. """ diff --git a/common/djangoapps/third_party_auth/tests/test_identityserver3.py b/common/djangoapps/third_party_auth/tests/test_identityserver3.py index 53499b661978..f275d5f944ee 100644 --- a/common/djangoapps/third_party_auth/tests/test_identityserver3.py +++ b/common/djangoapps/third_party_auth/tests/test_identityserver3.py @@ -7,11 +7,11 @@ from common.djangoapps.third_party_auth.identityserver3 import IdentityServer3 from common.djangoapps.third_party_auth.tests import testutil -from common.djangoapps.third_party_auth.tests.utils import skip_unless_thirdpartyauth from common.test.utils import assert_dict_contains_subset +from openedx.core.djangolib.testing.utils import skip_unless_lms -@skip_unless_thirdpartyauth() +@skip_unless_lms @ddt.ddt class IdentityServer3Test(testutil.TestCase): """ diff --git a/common/djangoapps/third_party_auth/tests/test_pipeline.py b/common/djangoapps/third_party_auth/tests/test_pipeline.py index 51aab50bce4c..ab8b0c4a1fc0 100644 --- a/common/djangoapps/third_party_auth/tests/test_pipeline.py +++ b/common/djangoapps/third_party_auth/tests/test_pipeline.py @@ -11,10 +11,10 @@ from common.djangoapps.third_party_auth.tests.specs.base import IntegrationTestMixin from common.djangoapps.third_party_auth.tests.specs.test_testshib import SamlIntegrationTestUtilities from common.djangoapps.third_party_auth.tests.testutil import simulate_running_pipeline -from common.djangoapps.third_party_auth.tests.utils import skip_unless_thirdpartyauth +from openedx.core.djangolib.testing.utils import skip_unless_lms -@skip_unless_thirdpartyauth() +@skip_unless_lms @ddt.ddt class ProviderUserStateTestCase(testutil.TestCase): """Tests ProviderUserState behavior.""" @@ -54,7 +54,7 @@ def test_get_idp_logout_url_from_running_pipeline(self, idp_type, backend_name): assert idp_config['logout_url'] == logout_url -@skip_unless_thirdpartyauth() +@skip_unless_lms @ddt.ddt class PipelineOverridesTest(SamlIntegrationTestUtilities, IntegrationTestMixin, testutil.SAMLTestCase): """ diff --git a/common/djangoapps/third_party_auth/tests/test_pipeline_integration.py b/common/djangoapps/third_party_auth/tests/test_pipeline_integration.py index 75771b9fbfec..7aa96fa6f58f 100644 --- a/common/djangoapps/third_party_auth/tests/test_pipeline_integration.py +++ b/common/djangoapps/third_party_auth/tests/test_pipeline_integration.py @@ -15,15 +15,15 @@ from common.djangoapps.student.tests.factories import UserFactory from common.djangoapps.third_party_auth import pipeline, provider from common.djangoapps.third_party_auth.tests import testutil -from common.djangoapps.third_party_auth.tests.utils import skip_unless_thirdpartyauth from lms.djangoapps.verify_student.models import SSOVerification +from openedx.core.djangolib.testing.utils import skip_unless_lms # Get Django User model by reference from python-social-auth. Not a type # constant, pylint. User = social_models.DjangoStorage.user.user_model() # pylint: disable=invalid-name -@skip_unless_thirdpartyauth() +@skip_unless_lms class TestCase(testutil.TestCase, test.TestCase): """Base test case.""" diff --git a/common/djangoapps/third_party_auth/tests/test_provider.py b/common/djangoapps/third_party_auth/tests/test_provider.py index 7dbb79a72cd7..d2a6623f0cb2 100644 --- a/common/djangoapps/third_party_auth/tests/test_provider.py +++ b/common/djangoapps/third_party_auth/tests/test_provider.py @@ -10,17 +10,17 @@ from common.djangoapps.third_party_auth import provider from common.djangoapps.third_party_auth.tests import testutil -from common.djangoapps.third_party_auth.tests.utils import skip_unless_thirdpartyauth from openedx.core.djangoapps.site_configuration.tests.test_util import ( with_site_configuration, with_site_configuration_context, ) +from openedx.core.djangolib.testing.utils import skip_unless_lms SITE_DOMAIN_A = 'professionalx.example.com' SITE_DOMAIN_B = 'somethingelse.example.com' -@skip_unless_thirdpartyauth() +@skip_unless_lms class RegistryTest(testutil.TestCase): """Tests registry discovery and operation.""" diff --git a/common/djangoapps/third_party_auth/tests/test_settings.py b/common/djangoapps/third_party_auth/tests/test_settings.py index 3074b85621dd..d16838e7e008 100644 --- a/common/djangoapps/third_party_auth/tests/test_settings.py +++ b/common/djangoapps/third_party_auth/tests/test_settings.py @@ -4,7 +4,6 @@ from django.test import TestCase, override_settings from common.djangoapps.third_party_auth import provider -from common.djangoapps.third_party_auth.tests.utils import skip_unless_thirdpartyauth from openedx.core.djangolib.testing.utils import skip_unless_lms @@ -20,7 +19,7 @@ def test_fields_stored_in_session_defined(self): """Verify FIELDS_STORED_IN_SESSION is defined with expected values.""" assert settings.FIELDS_STORED_IN_SESSION == ['auth_entry', 'next'] - @skip_unless_thirdpartyauth() + @skip_unless_lms def test_no_providers_enabled_by_default(self): """Providers are only enabled via ConfigurationModels in the database.""" assert provider.Registry.enabled() == [] diff --git a/common/djangoapps/third_party_auth/tests/test_views.py b/common/djangoapps/third_party_auth/tests/test_views.py index 3a5f46a44d41..802536525fd0 100644 --- a/common/djangoapps/third_party_auth/tests/test_views.py +++ b/common/djangoapps/third_party_auth/tests/test_views.py @@ -3,7 +3,6 @@ """ -import unittest from unittest.mock import patch import ddt @@ -22,13 +21,14 @@ # Define some XML namespaces: from common.djangoapps.third_party_auth.utils import SAML_XML_NS from common.djangoapps.third_party_auth.views import inactive_user_view +from openedx.core.djangolib.testing.utils import skip_unless_lms -from .testutil import AUTH_FEATURE_ENABLED, AUTH_FEATURES_KEY, SAMLTestCase +from .testutil import SAMLTestCase XMLDSIG_XML_NS = 'http://www.w3.org/2000/09/xmldsig#' -@unittest.skipUnless(AUTH_FEATURE_ENABLED, AUTH_FEATURES_KEY + ' not enabled') +@skip_unless_lms @ddt.ddt class SAMLMetadataTest(SAMLTestCase): """ @@ -146,7 +146,7 @@ def check_metadata_contacts(self, xml, tech_name, tech_email, support_name, supp assert support_email_node.text == support_email -@unittest.skipUnless(AUTH_FEATURE_ENABLED, AUTH_FEATURES_KEY + ' not enabled') +@skip_unless_lms class SAMLAuthTest(SAMLTestCase): """ Test the SAML auth views @@ -166,7 +166,7 @@ def test_login_disabled(self): assert response.status_code == 404 -@unittest.skipUnless(AUTH_FEATURE_ENABLED, AUTH_FEATURES_KEY + ' not enabled') +@skip_unless_lms class IdPRedirectViewTest(SAMLTestCase): """ Test IdPRedirectView. @@ -206,7 +206,7 @@ def get_idp_redirect_url(provider_slug, next_destination=None): ) -@unittest.skipUnless(AUTH_FEATURE_ENABLED, AUTH_FEATURES_KEY + ' not enabled') +@skip_unless_lms class InactiveUserViewTests(TestCase): """Test inactive user view """ @patch('common.djangoapps.third_party_auth.views.redirect') diff --git a/common/djangoapps/third_party_auth/tests/testutil.py b/common/djangoapps/third_party_auth/tests/testutil.py index 1376cacff231..8ae516bb62dd 100644 --- a/common/djangoapps/third_party_auth/tests/testutil.py +++ b/common/djangoapps/third_party_auth/tests/testutil.py @@ -10,7 +10,6 @@ from unittest import mock import django.test -from django.conf import settings from django.contrib.auth.models import User # pylint: disable=imported-auth-user from django.contrib.sites.models import Site from mako.template import Template @@ -26,9 +25,6 @@ from openedx.core.djangolib.testing.utils import CacheIsolationMixin from openedx.core.storage import OverwriteStorage -AUTH_FEATURES_KEY = 'ENABLE_THIRD_PARTY_AUTH' -AUTH_FEATURE_ENABLED = hasattr(settings, AUTH_FEATURES_KEY) - def patch_mako_templates(): """ Patch mako so the django test client can access template context """ diff --git a/common/djangoapps/third_party_auth/tests/utils.py b/common/djangoapps/third_party_auth/tests/utils.py index e753a14ceca4..f47761386c30 100644 --- a/common/djangoapps/third_party_auth/tests/utils.py +++ b/common/djangoapps/third_party_auth/tests/utils.py @@ -3,7 +3,6 @@ import json from base64 import b64encode -from unittest import skip import httpretty from oauth2_provider.models import Application @@ -14,7 +13,7 @@ from common.djangoapps.student.tests.factories import UserFactory -from .testutil import AUTH_FEATURE_ENABLED, AUTH_FEATURES_KEY, ThirdPartyAuthTestMixin +from .testutil import ThirdPartyAuthTestMixin @httpretty.activate @@ -144,12 +143,3 @@ def prepare_saml_response_from_xml(xml, relay_state='testshib'): relay_state=OneLogin_Saml2_Utils.escape_url(relay_state), saml_response=OneLogin_Saml2_Utils.escape_url(b64encoded_xml) ) - - -def skip_unless_thirdpartyauth(): - """ - Wraps unittest.skip in consistent logic to skip certain third_party_auth tests in CMS. - """ - if AUTH_FEATURE_ENABLED: - return lambda func: func - return skip("%s not enabled" % AUTH_FEATURES_KEY) # noqa: UP031