diff --git a/src/backend/core/tests/conftest.py b/src/backend/core/tests/conftest.py index b39af92a7..45e0a4dbb 100644 --- a/src/backend/core/tests/conftest.py +++ b/src/backend/core/tests/conftest.py @@ -10,7 +10,7 @@ import responses from core import factories from core.services.yhub_services import YHubService -from core.tests.utils.urls import reload_urls +from core.tests.utils.urls import reload_urls, restore_urls USER = "user" TEAM = "team" @@ -23,6 +23,25 @@ def clear_cache(): cache.clear() +@pytest.fixture(autouse=True) +def restore_urlconf(): + """ + Put the URLs back after a test that reloaded them. + + Reloading is how a test makes the resource server routes appear or checks + that they are absent, but the URLconf belongs to the process: without this, + a test asserting a 404 on `/external_api/` and one asserting a 401 pass or + fail depending on which ran first in their worker. + + Autouse and asking for nothing, so it is set up before the `settings` + fixture and torn down after it: the reload then sees the settings of the + project, not the ones of the test. + """ + yield + + restore_urls() + + @pytest.fixture def mock_user_teams(): """Mock for the "teams" property on the User model.""" diff --git a/src/backend/core/tests/external_api/test_external_api_documents.py b/src/backend/core/tests/external_api/test_external_api_documents.py index b4bb8f1eb..183b092ed 100644 --- a/src/backend/core/tests/external_api/test_external_api_documents.py +++ b/src/backend/core/tests/external_api/test_external_api_documents.py @@ -581,11 +581,17 @@ def test_external_api_documents_trashbin_not_allowed( assert response.status_code == 403 -def test_external_api_documents_create_for_owner_not_allowed(): +def test_external_api_documents_create_for_owner_not_allowed( + resource_server_backend_conf, +): """ Authenticated users SHOULD NOT be allowed to call create documents on behalf of other users. This API endpoint is reserved for server-to-server calls. + + The route only exists when the resource server is enabled, hence the + fixture: the endpoint answering 401 is what this asserts, not the + `/external_api/` prefix being routed at all. """ user = factories.UserFactory() diff --git a/src/backend/core/tests/utils/urls.py b/src/backend/core/tests/utils/urls.py index 78455de1e..2da23f7ee 100644 --- a/src/backend/core/tests/utils/urls.py +++ b/src/backend/core/tests/utils/urls.py @@ -5,16 +5,47 @@ import importlib from django.urls import clear_url_caches +class _URLConf: + """ + Whether a test reloaded the URLs of this process. + + The URLconf is module-level state: a reload outlives the test that did it + and every test running after it in the same worker sees its routes — which + ones share a worker changes from one run to the next. `restore_urls` puts + the default back, and this flag keeps it to the tests that need it. + """ + + reloaded = False + + +def _reload(): + """Reload the URL modules and drop the resolver caches.""" + import core.urls # pylint:disable=import-outside-toplevel # noqa: PLC0415 + + import impress.urls # pylint:disable=import-outside-toplevel # noqa: PLC0415 + + importlib.reload(core.urls) + importlib.reload(impress.urls) + clear_url_caches() + + def reload_urls(): """ Reload the URLs. Since the URLs are loaded based on a settings value, we need to reload them to make the URL settings based condition effective. """ - import core.urls # pylint:disable=import-outside-toplevel # noqa: PLC0415 + _URLConf.reloaded = True + _reload() - import impress.urls # pylint:disable=import-outside-toplevel # noqa: PLC0415 - importlib.reload(core.urls) - importlib.reload(impress.urls) - clear_url_caches() +def restore_urls(): + """ + Reload the URLs of a test that changed them, so the next one starts clean. + + Called once the settings of the test are restored, so the routes are the + ones the settings of the project declare. + """ + if _URLConf.reloaded: + _URLConf.reloaded = False + _reload()