From e670adf2d0ec0d61ed990e04fc84456aeace7ba5 Mon Sep 17 00:00:00 2001 From: Ross Date: Wed, 10 Jun 2026 21:31:06 +0100 Subject: [PATCH] test: add smoke tests for URL endpoints with different user roles --- atlas/tests/test_url_smoke.py | 121 ++++++++++++++++++++++++++++++++++ 1 file changed, 121 insertions(+) create mode 100644 atlas/tests/test_url_smoke.py diff --git a/atlas/tests/test_url_smoke.py b/atlas/tests/test_url_smoke.py new file mode 100644 index 00000000..ddc16260 --- /dev/null +++ b/atlas/tests/test_url_smoke.py @@ -0,0 +1,121 @@ +import pytest +from django.urls import reverse +from django.contrib.auth.models import Group, User +from django.test import Client +from atlas.models import CaseCollection, Case, Series, Condition, Finding, Structure, Resource + +SAFE_STATUS_CODES = {200, 301, 302, 303, 403, 404, 405} + +# Fixtures for clients +@pytest.fixture +def candidate_client(db): + user = User.objects.create_user(username="candidate", password="password", email="candidate@test.com") + client = Client() + client.force_login(user) + return client + +@pytest.fixture +def editor_client(db): + user = User.objects.create_user(username="editor", password="password", email="editor@test.com") + g, _ = Group.objects.get_or_create(name="atlas_editor") + user.groups.add(g) + client = Client() + client.force_login(user) + return client + +@pytest.fixture +def anonymous_client(db): + return Client() + +# Fixture to prepare smoke test DB records +@pytest.fixture +def smoke_data(db, create_case, create_series, create_condition, create_finding, create_structure, create_user): + # CaseCollection + collection = CaseCollection.objects.create(name="Smoke Collection") + collection.cases.add(create_case) + collection.author.add(create_user) + + # Resource + resource = Resource.objects.create(name="Smoke Resource") + resource.author.add(create_user) + + # Make sure condition/finding/structure/series are authored/accessible + create_series.author.add(create_user) + + return { + "collection": collection, + "case": create_case, + "series": create_series, + "condition": create_condition, + "finding": create_finding, + "structure": create_structure, + "resource": resource, + } + +URL_SPECS = [ + ("atlas:index", None), + ("atlas:help", None), + ("atlas:case_view", None), + ("atlas:case_create", None), + ("atlas:case_detail", lambda d: {"pk": d["case"].pk}), + ("atlas:case_update", lambda d: {"pk": d["case"].pk}), + ("atlas:case_delete", lambda d: {"pk": d["case"].pk}), + ("atlas:collection_view", None), + ("atlas:exam_create", None), + ("atlas:collection_detail", lambda d: {"pk": d["collection"].pk}), + ("atlas:exam_update", lambda d: {"pk": d["collection"].pk}), + ("atlas:exam_deleted", lambda d: {"pk": d["collection"].pk}), + ("atlas:series_view", None), + ("atlas:series_create", None), + ("atlas:series_detail", lambda d: {"pk": d["series"].pk}), + ("atlas:series_update", lambda d: {"pk": d["series"].pk}), + ("atlas:series_delete", lambda d: {"pk": d["series"].pk}), + ("atlas:resource_view", None), + ("atlas:resource_create", None), + ("atlas:resource_detail", lambda d: {"pk": d["resource"].pk}), + ("atlas:resource_update", lambda d: {"pk": d["resource"].pk}), + ("atlas:resource_delete", lambda d: {"pk": d["resource"].pk}), + ("atlas:condition_view", None), + ("atlas:condition_create", None), + ("atlas:condition_detail", lambda d: {"pk": d["condition"].pk}), + ("atlas:condition_update", lambda d: {"pk": d["condition"].pk}), + ("atlas:condition_delete", lambda d: {"pk": d["condition"].pk}), + ("atlas:finding_view", None), + ("atlas:finding_create", None), + ("atlas:finding_detail", lambda d: {"pk": d["finding"].pk}), + ("atlas:finding_update", lambda d: {"pk": d["finding"].pk}), + ("atlas:finding_delete", lambda d: {"pk": d["finding"].pk}), + ("atlas:structure_view", None), + ("atlas:structure_create", None), + ("atlas:structure_detail", lambda d: {"pk": d["structure"].pk}), + ("atlas:structure_update", lambda d: {"pk": d["structure"].pk}), + ("atlas:structure_delete", lambda d: {"pk": d["structure"].pk}), +] + +@pytest.mark.django_db +@pytest.mark.parametrize("url_name, kwargs_lambda", URL_SPECS) +def test_url_smoke_anonymous(anonymous_client, smoke_data, url_name, kwargs_lambda): + kwargs = kwargs_lambda(smoke_data) if kwargs_lambda else None + url = reverse(url_name, kwargs=kwargs) + response = anonymous_client.get(url, follow=False) + assert response.status_code != 500, f"500 Server Error on {url_name} ({url}) for Anonymous" + assert response.status_code in {200, 302, 403, 404}, f"Unexpected status code {response.status_code} on {url_name} for Anonymous" + +@pytest.mark.django_db +@pytest.mark.parametrize("url_name, kwargs_lambda", URL_SPECS) +def test_url_smoke_candidate(candidate_client, smoke_data, url_name, kwargs_lambda): + kwargs = kwargs_lambda(smoke_data) if kwargs_lambda else None + url = reverse(url_name, kwargs=kwargs) + response = candidate_client.get(url, follow=False) + assert response.status_code != 500, f"500 Server Error on {url_name} ({url}) for Candidate" + assert response.status_code in SAFE_STATUS_CODES, f"Unexpected status code {response.status_code} on {url_name} for Candidate" + +@pytest.mark.django_db +@pytest.mark.parametrize("url_name, kwargs_lambda", URL_SPECS) +def test_url_smoke_editor(editor_client, smoke_data, url_name, kwargs_lambda): + kwargs = kwargs_lambda(smoke_data) if kwargs_lambda else None + url = reverse(url_name, kwargs=kwargs) + response = editor_client.get(url, follow=False) + assert response.status_code != 500, f"500 Server Error on {url_name} ({url}) for Editor" + # Editor should get a success status code (200 OK or 302 redirect), never forbidden or not found for these valid resources + assert response.status_code in {200, 301, 302, 303}, f"Unexpected status code {response.status_code} on {url_name} for Editor"