diff --git a/swh/web/common/exc.py b/swh/web/common/exc.py --- a/swh/web/common/exc.py +++ b/swh/web/common/exc.py @@ -142,4 +142,7 @@ if isinstance(exc, NotFoundExc): error_code = 404 - return _generate_error_page(request, error_code, error_description) + resp = _generate_error_page(request, error_code, error_description) + if get_config()["debug"]: + resp.traceback = error_description + return resp diff --git a/swh/web/settings/tests.py b/swh/web/settings/tests.py --- a/swh/web/settings/tests.py +++ b/swh/web/settings/tests.py @@ -24,7 +24,8 @@ swh_web_config.update( { - "debug": False, + # disable django debug mode when running cypress tests + "debug": "pytest" in sys.argv[0] or "PYTEST_XDIST_WORKER" in os.environ, "secret_key": "test", "history_counters_url": "", "throttling": { diff --git a/swh/web/tests/admin/test_origin_save.py b/swh/web/tests/admin/test_origin_save.py --- a/swh/web/tests/admin/test_origin_save.py +++ b/swh/web/tests/admin/test_origin_save.py @@ -20,6 +20,7 @@ ) from swh.web.common.origin_save import can_save_origin from swh.web.common.utils import reverse +from swh.web.tests.utils import check_http_get_response, check_http_post_response _user_name = "swh-web-admin" _user_mail = "admin@swh-web.org" @@ -44,9 +45,9 @@ def check_not_login(client, url): login_url = reverse("login", query_params={"next": url}) - response = client.post(url) - assert response.status_code == 302 - assert unquote(response.url) == login_url + + resp = check_http_post_response(client, url, status_code=302) + assert unquote(resp.url) == login_url def test_add_authorized_origin_url(client): @@ -62,8 +63,8 @@ assert can_save_origin(authorized_url) == SAVE_REQUEST_PENDING client.login(username=_user_name, password=_user_password) - response = client.post(url) - assert response.status_code == 200 + + check_http_post_response(client, url, status_code=200) assert can_save_origin(authorized_url) == SAVE_REQUEST_ACCEPTED @@ -80,8 +81,7 @@ assert can_save_origin(_authorized_origin_url) == SAVE_REQUEST_ACCEPTED client.login(username=_user_name, password=_user_password) - response = client.post(url) - assert response.status_code == 200 + check_http_post_response(client, url, status_code=200) assert can_save_origin(_authorized_origin_url) == SAVE_REQUEST_PENDING @@ -99,8 +99,7 @@ assert can_save_origin(unauthorized_url) == SAVE_REQUEST_PENDING client.login(username=_user_name, password=_user_password) - response = client.post(url) - assert response.status_code == 200 + check_http_post_response(client, url, status_code=200) assert can_save_origin(unauthorized_url) == SAVE_REQUEST_REJECTED @@ -117,8 +116,7 @@ assert can_save_origin(_unauthorized_origin_url) == SAVE_REQUEST_REJECTED client.login(username=_user_name, password=_user_password) - response = client.post(url) - assert response.status_code == 200 + check_http_post_response(client, url, status_code=200) assert can_save_origin(_unauthorized_origin_url) == SAVE_REQUEST_PENDING @@ -130,10 +128,7 @@ "api-1-save-origin", url_args={"visit_type": visit_type, "origin_url": origin_url}, ) - response = client.post( - save_request_url, data={}, content_type="application/x-www-form-urlencoded" - ) - assert response.status_code == 200 + response = check_http_post_response(client, save_request_url, status_code=200) assert response.data["save_request_status"] == SAVE_REQUEST_PENDING accept_request_url = reverse( @@ -158,11 +153,9 @@ mock_scheduler.get_tasks.return_value = tasks_data client.login(username=_user_name, password=_user_password) - response = client.post(accept_request_url) - assert response.status_code == 200 + response = check_http_post_response(client, accept_request_url, status_code=200) - response = client.get(save_request_url) - assert response.status_code == 200 + response = check_http_get_response(client, save_request_url, status_code=200) assert response.data[0]["save_request_status"] == SAVE_REQUEST_ACCEPTED assert response.data[0]["save_task_status"] == SAVE_TASK_NOT_YET_SCHEDULED @@ -175,10 +168,8 @@ "api-1-save-origin", url_args={"visit_type": visit_type, "origin_url": origin_url}, ) - response = client.post( - save_request_url, data={}, content_type="application/x-www-form-urlencoded" - ) - assert response.status_code == 200 + + response = check_http_post_response(client, save_request_url, status_code=200) assert response.data["save_request_status"] == SAVE_REQUEST_PENDING reject_request_url = reverse( @@ -189,8 +180,7 @@ check_not_login(client, reject_request_url) client.login(username=_user_name, password=_user_password) - response = client.post(reject_request_url) - assert response.status_code == 200 + response = check_http_post_response(client, reject_request_url, status_code=200) tasks_data = [ { @@ -206,8 +196,7 @@ mock_scheduler.create_tasks.return_value = tasks_data mock_scheduler.get_tasks.return_value = tasks_data - response = client.get(save_request_url) - assert response.status_code == 200 + response = check_http_get_response(client, save_request_url, status_code=200) assert response.data[0]["save_request_status"] == SAVE_REQUEST_REJECTED @@ -226,6 +215,5 @@ check_not_login(client, remove_request_url) client.login(username=_user_name, password=_user_password) - response = client.post(remove_request_url) - assert response.status_code == 200 + check_http_post_response(client, remove_request_url, status_code=200) assert SaveOriginRequest.objects.count() == 0 diff --git a/swh/web/tests/api/test_apidoc.py b/swh/web/tests/api/test_apidoc.py --- a/swh/web/tests/api/test_apidoc.py +++ b/swh/web/tests/api/test_apidoc.py @@ -14,7 +14,7 @@ from swh.web.api.apiurls import api_route from swh.web.common.exc import BadInputExc, ForbiddenExc, NotFoundExc from swh.web.common.utils import prettify_html, reverse -from swh.web.tests.django_asserts import assert_template_used +from swh.web.tests.utils import check_api_get_responses, check_html_get_response _httpdomain_doc = """ .. http:get:: /api/1/revision/(sha1_git)/ @@ -98,16 +98,14 @@ def test_apidoc_route_doc(client): url = reverse("api-1-some-doc-route-doc") - rv = client.get(url, HTTP_ACCEPT="text/html") - - assert rv.status_code == 200, rv.content - assert_template_used(rv, "api/apidoc.html") + check_html_get_response( + client, url, status_code=200, template_used="api/apidoc.html" + ) def test_apidoc_route_fn(api_client): url = reverse("api-1-some-doc-route", url_args={"myarg": 1, "myotherarg": 1}) - rv = api_client.get(url) - assert rv.status_code == 200, rv.data + check_api_get_responses(api_client, url, status_code=200) @api_route(r"/test/error/(?P.+)/", "api-1-test-error") @@ -124,9 +122,7 @@ def test_apidoc_error(api_client): for exc, code in _exception_http_code.items(): url = reverse("api-1-test-error", url_args={"exc_name": exc.__name__}) - rv = api_client.get(url) - - assert rv.status_code == code, rv.data + check_api_get_responses(api_client, url, status_code=code) @api_route( @@ -143,18 +139,16 @@ def test_apidoc_full_stack_doc(client): url = reverse("api-1-some-complete-doc-route-doc") - rv = client.get(url, HTTP_ACCEPT="text/html") - assert rv.status_code == 200, rv.content - assert_template_used(rv, "api/apidoc.html") + check_html_get_response( + client, url, status_code=200, template_used="api/apidoc.html" + ) def test_apidoc_full_stack_fn(api_client): url = reverse( "api-1-some-complete-doc-route", url_args={"myarg": 1, "myotherarg": 1} ) - rv = api_client.get(url) - - assert rv.status_code == 200, rv.data + check_api_get_responses(api_client, url, status_code=200) @api_route(r"/test/post/only/", "api-1-test-post-only", methods=["POST"]) @@ -170,9 +164,9 @@ # a dedicated view accepting GET requests should have # been created to display the HTML documentation url = reverse("api-1-test-post-only-doc") - rv = client.get(url, HTTP_ACCEPT="text/html") - assert rv.status_code == 200, rv.content - assert_template_used(rv, "api/apidoc.html") + check_html_get_response( + client, url, status_code=200, template_used="api/apidoc.html" + ) def test_api_doc_parse_httpdomain(): @@ -370,9 +364,9 @@ def test_apidoc_input_output_doc(client): url = reverse("api-1-post-endpoint-doc") - rv = client.get(url, HTTP_ACCEPT="text/html") - assert rv.status_code == 200, rv.content - assert_template_used(rv, "api/apidoc.html") + rv = check_html_get_response( + client, url, status_code=200, template_used="api/apidoc.html" + ) input_html_doc = textwrap.indent( ( @@ -455,9 +449,9 @@ def test_apidoc_with_links(client): url = reverse("api-1-endpoint-links-in-doc") - rv = client.get(url, HTTP_ACCEPT="text/html") - assert rv.status_code == 200, rv.content - assert_template_used(rv, "api/apidoc.html") + rv = check_html_get_response( + client, url, status_code=200, template_used="api/apidoc.html" + ) html = prettify_html(rv.content) diff --git a/swh/web/tests/api/test_apiresponse.py b/swh/web/tests/api/test_apiresponse.py --- a/swh/web/tests/api/test_apiresponse.py +++ b/swh/web/tests/api/test_apiresponse.py @@ -138,3 +138,5 @@ url = reverse("api-1-stat-counters") resp = api_client.get(url) assert resp.status_code == 500 + assert "traceback" in resp.data + assert "Traceback" in resp.data["traceback"] diff --git a/swh/web/tests/api/views/__init__.py b/swh/web/tests/api/views/__init__.py --- a/swh/web/tests/api/views/__init__.py +++ b/swh/web/tests/api/views/__init__.py @@ -1,71 +0,0 @@ -# Copyright (C) 2020 The Software Heritage developers -# See the AUTHORS file at the top-level directory of this distribution -# License: GNU Affero General Public License version 3, or any later version -# See top-level LICENSE file for more information - -from typing import Any, Dict, Optional - -from rest_framework.response import Response -from rest_framework.test import APIClient - - -def check_api_get_responses( - api_client: APIClient, url: str, status_code: int -) -> Response: - """Helper function to check Web API responses to GET requests - for all accepted content types. - - Args: - api_client: DRF test client - url: Web API URL to check responses - status_code: expected HTTP status code - - Returns: - The Web API JSON response - """ - # check API Web UI - html_content_type = "text/html" - resp = api_client.get(url, HTTP_ACCEPT=html_content_type) - assert resp.status_code == status_code, resp.content - assert resp["Content-Type"].startswith(html_content_type) - - # check YAML response - yaml_content_type = "application/yaml" - resp = api_client.get(url, HTTP_ACCEPT=yaml_content_type) - assert resp.status_code == status_code, resp.data - assert resp["Content-Type"] == yaml_content_type - - # check JSON response - resp = api_client.get(url) - assert resp.status_code == status_code, resp.data - assert resp["Content-Type"] == "application/json" - - return resp - - -def check_api_post_responses( - api_client: APIClient, url: str, data: Optional[Dict[str, Any]], status_code: int -) -> Response: - """Helper function to check Web API responses to POST requests - for all accepted content types. - - Args: - api_client: DRF test client - url: Web API URL to check responses - status_code: expected HTTP status code - - Returns: - The Web API JSON response - """ - # check YAML response - yaml_content_type = "application/yaml" - resp = api_client.post(url, data=data, format="json", HTTP_ACCEPT=yaml_content_type) - assert resp.status_code == status_code, resp.data - assert resp["Content-Type"] == yaml_content_type - - # check JSON response - resp = api_client.post(url, data=data, format="json") - assert resp.status_code == status_code, resp.data - assert resp["Content-Type"] == "application/json" - - return resp diff --git a/swh/web/tests/api/views/test_content.py b/swh/web/tests/api/views/test_content.py --- a/swh/web/tests/api/views/test_content.py +++ b/swh/web/tests/api/views/test_content.py @@ -7,10 +7,14 @@ import pytest from swh.web.common.utils import reverse -from swh.web.tests.api.views import check_api_get_responses, check_api_post_responses from swh.web.tests.conftest import ctags_json_missing, fossology_missing from swh.web.tests.data import random_content from swh.web.tests.strategies import content, contents_with_ctags +from swh.web.tests.utils import ( + check_api_get_responses, + check_api_post_responses, + check_http_get_response, +) @given(content()) @@ -250,15 +254,12 @@ def test_api_content_raw_text(api_client, archive_data, content): url = reverse("api-1-content-raw", url_args={"q": "sha1:%s" % content["sha1"]}) - rv = api_client.get(url) - - assert rv.status_code == 200, rv.data + rv = check_http_get_response(api_client, url, status_code=200) assert rv["Content-Type"] == "application/octet-stream" assert ( rv["Content-disposition"] == "attachment; filename=content_sha1_%s_raw" % content["sha1"] ) - assert rv["Content-Type"] == "application/octet-stream" expected_data = archive_data.content_get_data(content["sha1"]) assert rv.content == expected_data["data"] @@ -270,10 +271,7 @@ url_args={"q": "sha1:%s" % content["sha1"]}, query_params={"filename": "filename.txt"}, ) - rv = api_client.get(url) - - assert rv.status_code == 200, rv.data - assert rv["Content-Type"] == "application/octet-stream" + rv = check_http_get_response(api_client, url, status_code=200) assert rv["Content-disposition"] == "attachment; filename=filename.txt" assert rv["Content-Type"] == "application/octet-stream" expected_data = archive_data.content_get_data(content["sha1"]) @@ -320,9 +318,6 @@ "api-1-content-uppercase-checksum", url_args={"q": content["sha1"].upper()} ) - rv = api_client.get(url) - assert rv.status_code == 302, rv.data - + rv = check_http_get_response(api_client, url, status_code=302) redirect_url = reverse("api-1-content", url_args={"q": content["sha1"]}) - assert rv["location"] == redirect_url diff --git a/swh/web/tests/api/views/test_directory.py b/swh/web/tests/api/views/test_directory.py --- a/swh/web/tests/api/views/test_directory.py +++ b/swh/web/tests/api/views/test_directory.py @@ -9,9 +9,9 @@ from swh.web.api.utils import enrich_directory from swh.web.common.utils import reverse -from swh.web.tests.api.views import check_api_get_responses from swh.web.tests.data import random_sha1 from swh.web.tests.strategies import directory +from swh.web.tests.utils import check_api_get_responses, check_http_get_response @given(directory()) @@ -72,8 +72,7 @@ "api-1-directory-uppercase-checksum", url_args={"sha1_git": directory.upper()} ) - resp = api_client.get(url) - assert resp.status_code == 302 + resp = check_http_get_response(api_client, url, status_code=302) redirect_url = reverse("api-1-directory", url_args={"sha1_git": directory}) diff --git a/swh/web/tests/api/views/test_graph.py b/swh/web/tests/api/views/test_graph.py --- a/swh/web/tests/api/views/test_graph.py +++ b/swh/web/tests/api/views/test_graph.py @@ -16,12 +16,12 @@ from swh.web.tests.auth.keycloak_mock import mock_keycloak from swh.web.tests.auth.sample_data import oidc_profile from swh.web.tests.strategies import origin +from swh.web.tests.utils import check_http_get_response def test_graph_endpoint_needs_authentication(api_client): url = reverse("api-1-graph", url_args={"graph_query": "stats"}) - resp = api_client.get(url) - assert resp.status_code == 401 + check_http_get_response(api_client, url, status_code=401) def _authenticate_graph_user(api_client, mocker): @@ -35,8 +35,7 @@ api_client.credentials(HTTP_AUTHORIZATION=f"Bearer {oidc_profile['refresh_token']}") mock_keycloak(mocker, user_permissions=[]) - resp = api_client.get(url) - assert resp.status_code == 403 + check_http_get_response(api_client, url, status_code=403) _authenticate_graph_user(api_client, mocker) requests_mock.get( @@ -44,8 +43,7 @@ json={}, headers={"Content-Type": "application/json"}, ) - resp = api_client.get(url) - assert resp.status_code == 200 + check_http_get_response(api_client, url, status_code=200) def test_graph_text_plain_response(api_client, mocker, requests_mock): @@ -81,10 +79,9 @@ url = reverse("api-1-graph", url_args={"graph_query": graph_query}) - resp = api_client.get(url) - - assert resp.status_code == 200 - assert resp.content_type == "text/plain" + resp = check_http_get_response( + api_client, url, status_code=200, content_type="text/plain" + ) assert resp.content == response_text.encode() @@ -114,9 +111,7 @@ url = reverse("api-1-graph", url_args={"graph_query": graph_query}) - resp = api_client.get(url) - - assert resp.status_code == 200 + resp = check_http_get_response(api_client, url, status_code=200) assert resp.content_type == "application/json" assert resp.content == json.dumps(_response_json).encode() @@ -145,9 +140,7 @@ url = reverse("api-1-graph", url_args={"graph_query": graph_query}) - resp = api_client.get(url) - - assert resp.status_code == 200 + resp = check_http_get_response(api_client, url, status_code=200) assert resp.content_type == "application/x-ndjson" assert resp.content == response_ndjson.encode() @@ -198,9 +191,7 @@ query_params={"direction": "backward"}, ) - resp = api_client.get(url) - - assert resp.status_code == 200 + resp = check_http_get_response(api_client, url, status_code=200) assert resp.content_type == content_type assert resp.content == response_text.encode() @@ -210,9 +201,7 @@ query_params={"direction": "backward", "resolve_origins": "true"}, ) - resp = api_client.get(url) - - assert resp.status_code == 200 + resp = check_http_get_response(api_client, url, status_code=200) assert resp.content_type == content_type assert ( resp.content == response_text.replace(origin_swhid, origin["url"]).encode() @@ -238,8 +227,6 @@ query_params={"resolve_origins": "true"}, ) - resp = api_client.get(url) - - assert resp.status_code == 200 + resp = check_http_get_response(api_client, url, status_code=200) assert resp.content_type == "application/json" assert resp.content == json.dumps(_response_json).encode() diff --git a/swh/web/tests/api/views/test_identifiers.py b/swh/web/tests/api/views/test_identifiers.py --- a/swh/web/tests/api/views/test_identifiers.py +++ b/swh/web/tests/api/views/test_identifiers.py @@ -8,7 +8,6 @@ from swh.model.identifiers import CONTENT, DIRECTORY, RELEASE, REVISION, SNAPSHOT from swh.web.common.identifiers import gen_swhid from swh.web.common.utils import reverse -from swh.web.tests.api.views import check_api_get_responses, check_api_post_responses from swh.web.tests.data import random_sha1 from swh.web.tests.strategies import ( content, @@ -23,6 +22,7 @@ unknown_revision, unknown_snapshot, ) +from swh.web.tests.utils import check_api_get_responses, check_api_post_responses @given(origin(), content(), directory(), release(), revision(), snapshot()) diff --git a/swh/web/tests/api/views/test_origin.py b/swh/web/tests/api/views/test_origin.py --- a/swh/web/tests/api/views/test_origin.py +++ b/swh/web/tests/api/views/test_origin.py @@ -16,8 +16,8 @@ from swh.web.common.exc import BadInputExc from swh.web.common.origin_visits import get_origin_visits from swh.web.common.utils import reverse -from swh.web.tests.api.views import check_api_get_responses from swh.web.tests.strategies import new_origin, new_snapshots, origin, visit_dates +from swh.web.tests.utils import check_api_get_responses def _scroll_results(api_client, url): @@ -25,9 +25,7 @@ results = [] while True: - rv = api_client.get(url) - assert rv.status_code == 200, rv.data - assert rv["Content-Type"] == "application/json" + rv = check_api_get_responses(api_client, url, status_code=200) results.extend(rv.data) diff --git a/swh/web/tests/api/views/test_origin_save.py b/swh/web/tests/api/views/test_origin_save.py --- a/swh/web/tests/api/views/test_origin_save.py +++ b/swh/web/tests/api/views/test_origin_save.py @@ -22,7 +22,7 @@ SaveUnauthorizedOrigin, ) from swh.web.common.utils import reverse -from swh.web.tests.api.views import check_api_get_responses, check_api_post_responses +from swh.web.tests.utils import check_api_get_responses, check_api_post_responses pytestmark = pytest.mark.django_db diff --git a/swh/web/tests/api/views/test_ping.py b/swh/web/tests/api/views/test_ping.py --- a/swh/web/tests/api/views/test_ping.py +++ b/swh/web/tests/api/views/test_ping.py @@ -4,7 +4,7 @@ # See top-level LICENSE file for more information from swh.web.common.utils import reverse -from swh.web.tests.api.views import check_api_get_responses +from swh.web.tests.utils import check_api_get_responses def test_api_1_ping(api_client): diff --git a/swh/web/tests/api/views/test_release.py b/swh/web/tests/api/views/test_release.py --- a/swh/web/tests/api/views/test_release.py +++ b/swh/web/tests/api/views/test_release.py @@ -16,9 +16,9 @@ TimestampWithTimezone, ) from swh.web.common.utils import reverse -from swh.web.tests.api.views import check_api_get_responses from swh.web.tests.data import random_sha1 from swh.web.tests.strategies import content, directory, release +from swh.web.tests.utils import check_api_get_responses, check_http_get_response @given(release()) @@ -113,8 +113,7 @@ "api-1-release-uppercase-checksum", url_args={"sha1_git": release.upper()} ) - resp = api_client.get(url) - assert resp.status_code == 302 + resp = check_http_get_response(api_client, url, status_code=302) redirect_url = reverse( "api-1-release-uppercase-checksum", url_args={"sha1_git": release} diff --git a/swh/web/tests/api/views/test_revision.py b/swh/web/tests/api/views/test_revision.py --- a/swh/web/tests/api/views/test_revision.py +++ b/swh/web/tests/api/views/test_revision.py @@ -8,9 +8,9 @@ from swh.web.api.utils import enrich_revision from swh.web.common.exc import NotFoundExc from swh.web.common.utils import reverse -from swh.web.tests.api.views import check_api_get_responses from swh.web.tests.data import random_sha1 from swh.web.tests.strategies import revision +from swh.web.tests.utils import check_api_get_responses, check_http_get_response @given(revision()) @@ -39,13 +39,11 @@ @given(revision()) def test_api_revision_raw_ok(api_client, archive_data, revision): url = reverse("api-1-revision-raw-message", url_args={"sha1_git": revision}) - rv = api_client.get(url) expected_message = archive_data.revision_get(revision)["message"] - assert rv.status_code == 200 + rv = check_http_get_response(api_client, url, status_code=200) assert rv["Content-Type"] == "application/octet-stream" - assert rv.content == expected_message.encode() @@ -192,8 +190,7 @@ "api-1-revision-uppercase-checksum", url_args={"sha1_git": revision.upper()} ) - resp = api_client.get(url) - assert resp.status_code == 302 + resp = check_http_get_response(api_client, url, status_code=302) redirect_url = reverse("api-1-revision", url_args={"sha1_git": revision}) diff --git a/swh/web/tests/api/views/test_snapshot.py b/swh/web/tests/api/views/test_snapshot.py --- a/swh/web/tests/api/views/test_snapshot.py +++ b/swh/web/tests/api/views/test_snapshot.py @@ -11,9 +11,9 @@ from swh.model.model import Snapshot from swh.web.api.utils import enrich_snapshot from swh.web.common.utils import reverse -from swh.web.tests.api.views import check_api_get_responses from swh.web.tests.data import random_sha1 from swh.web.tests.strategies import new_snapshot, snapshot +from swh.web.tests.utils import check_api_get_responses, check_http_get_response @given(snapshot()) @@ -131,8 +131,7 @@ "api-1-snapshot-uppercase-checksum", url_args={"snapshot_id": snapshot.upper()} ) - resp = api_client.get(url) - assert resp.status_code == 302 + resp = check_http_get_response(api_client, url, status_code=302) redirect_url = reverse( "api-1-snapshot-uppercase-checksum", url_args={"snapshot_id": snapshot} diff --git a/swh/web/tests/api/views/test_stat.py b/swh/web/tests/api/views/test_stat.py --- a/swh/web/tests/api/views/test_stat.py +++ b/swh/web/tests/api/views/test_stat.py @@ -6,7 +6,7 @@ from swh.storage.exc import StorageAPIError, StorageDBError from swh.web.common.exc import BadInputExc from swh.web.common.utils import reverse -from swh.web.tests.api.views import check_api_get_responses +from swh.web.tests.utils import check_api_get_responses def test_api_1_stat_counters_raise_error(api_client, mocker): diff --git a/swh/web/tests/api/views/test_vault.py b/swh/web/tests/api/views/test_vault.py --- a/swh/web/tests/api/views/test_vault.py +++ b/swh/web/tests/api/views/test_vault.py @@ -8,13 +8,18 @@ from swh.model import hashutil from swh.vault.exc import NotFoundExc from swh.web.common.utils import reverse -from swh.web.tests.api.views import check_api_get_responses, check_api_post_responses from swh.web.tests.strategies import ( directory, revision, unknown_directory, unknown_revision, ) +from swh.web.tests.utils import ( + check_api_get_responses, + check_api_post_responses, + check_http_get_response, + check_http_post_response, +) @given(directory(), revision()) @@ -60,9 +65,7 @@ obj_type, hashutil.hash_to_bytes(obj_id), email ) - rv = api_client.get(fetch_url) - - assert rv.status_code == 200 + rv = check_http_get_response(api_client, fetch_url, status_code=200) assert rv["Content-Type"] == "application/gzip" assert rv.content == stub_fetch mock_archive.vault_fetch.assert_called_with( @@ -82,9 +85,9 @@ f"api-1-vault-cook-{obj_type}-uppercase-checksum", url_args={f"{obj_type[:3]}_id": obj_id.upper()}, ) - rv = api_client.post(url, {"email": "test@test.mail"}) - - assert rv.status_code == 302 + rv = check_http_post_response( + api_client, url, data={"email": "test@test.mail"}, status_code=302 + ) redirect_url = reverse( f"api-1-vault-cook-{obj_type}", url_args={f"{obj_type[:3]}_id": obj_id} @@ -97,9 +100,7 @@ url_args={f"{obj_type[:3]}_id": obj_id.upper()}, ) - rv = api_client.get(fetch_url) - - assert rv.status_code == 302 + rv = check_http_get_response(api_client, fetch_url, status_code=302) redirect_url = reverse( f"api-1-vault-fetch-{obj_type}", url_args={f"{obj_type[:3]}_id": obj_id}, diff --git a/swh/web/tests/auth/test_api_auth.py b/swh/web/tests/auth/test_api_auth.py --- a/swh/web/tests/auth/test_api_auth.py +++ b/swh/web/tests/auth/test_api_auth.py @@ -9,6 +9,7 @@ from swh.web.auth.models import OIDCUser from swh.web.common.utils import reverse +from swh.web.tests.utils import check_api_get_responses, check_http_get_response from . import sample_data from .keycloak_mock import mock_keycloak @@ -25,11 +26,9 @@ mock_keycloak(mocker) client.login(code="", code_verifier="", redirect_uri="") - response = client.get(url) + response = check_http_get_response(client, url, status_code=200) request = response.wsgi_request - assert response.status_code == 200 - # user should be authenticated assert isinstance(request.user, OIDCUser) @@ -51,11 +50,9 @@ mock_keycloak(mocker) api_client.credentials(HTTP_AUTHORIZATION=f"Bearer {refresh_token}") - response = api_client.get(url) + response = check_api_get_responses(api_client, url, status_code=200) request = response.wsgi_request - assert response.status_code == 200 - # user should be authenticated assert isinstance(request.user, OIDCUser) @@ -74,19 +71,17 @@ mock_keycloak(mocker, auth_success=False) api_client.credentials(HTTP_AUTHORIZATION=f"Bearer {refresh_token}") - response = api_client.get(url) + response = check_api_get_responses(api_client, url, status_code=403) request = response.wsgi_request - assert response.status_code == 403 assert isinstance(request.user, AnonymousUser) # check for failed authentication when token format is invalid api_client.credentials(HTTP_AUTHORIZATION="Bearer invalid-token-format-ééàà") - response = api_client.get(url) + response = check_api_get_responses(api_client, url, status_code=400) request = response.wsgi_request - assert response.status_code == 400 assert isinstance(request.user, AnonymousUser) @@ -98,17 +93,15 @@ # missing authorization type api_client.credentials(HTTP_AUTHORIZATION=f"{refresh_token}") - response = api_client.get(url) + response = check_api_get_responses(api_client, url, status_code=403) request = response.wsgi_request - assert response.status_code == 403 assert isinstance(request.user, AnonymousUser) # invalid authorization type api_client.credentials(HTTP_AUTHORIZATION="Foo token") - response = api_client.get(url) + response = check_api_get_responses(api_client, url, status_code=403) request = response.wsgi_request - assert response.status_code == 403 assert isinstance(request.user, AnonymousUser) diff --git a/swh/web/tests/auth/test_middlewares.py b/swh/web/tests/auth/test_middlewares.py --- a/swh/web/tests/auth/test_middlewares.py +++ b/swh/web/tests/auth/test_middlewares.py @@ -10,6 +10,7 @@ from django.test import modify_settings from swh.web.common.utils import reverse +from swh.web.tests.utils import check_html_get_response from .keycloak_mock import mock_keycloak @@ -25,9 +26,8 @@ kc_oidc_mock.authorization_code.assert_called() url = reverse("swh-web-homepage") - resp = client.get(url) # no redirection for silent refresh - assert resp.status_code != 302 + check_html_get_response(client, url, status_code=200) @pytest.mark.django_db @@ -38,10 +38,9 @@ kc_oidc_mock.authorization_code.assert_called() url = reverse("swh-web-homepage") - resp = client.get(url) # should redirect for silent session refresh - assert resp.status_code == 302 + resp = check_html_get_response(client, url, status_code=302) silent_refresh_url = reverse( "oidc-login", query_params={"next_path": url, "prompt": "none"} ) diff --git a/swh/web/tests/auth/test_views.py b/swh/web/tests/auth/test_views.py --- a/swh/web/tests/auth/test_views.py +++ b/swh/web/tests/auth/test_views.py @@ -16,7 +16,12 @@ from swh.web.auth.models import OIDCUser, OIDCUserOfflineTokens from swh.web.auth.utils import OIDC_SWH_WEB_CLIENT_ID from swh.web.common.utils import reverse -from swh.web.tests.django_asserts import assert_contains, assert_template_used +from swh.web.tests.django_asserts import assert_contains +from swh.web.tests.utils import ( + check_html_get_response, + check_http_get_response, + check_http_post_response, +) from swh.web.urls import _default_view as homepage_view from . import sample_data @@ -34,12 +39,12 @@ # user initiates login process login_url = reverse("oidc-login") - response = client.get(login_url) - request = response.wsgi_request # should redirect to Keycloak authentication page in order # for a user to login with its username / password - assert response.status_code == 302 + response = check_html_get_response(client, login_url, status_code=302) + request = response.wsgi_request + assert isinstance(request.user, AnonymousUser) parsed_url = urlparse(response["location"]) @@ -88,12 +93,10 @@ }, ) - # login process finalization - response = client.get(login_complete_url) + # login process finalization, should redirect to root url by default + response = check_html_get_response(client, login_complete_url, status_code=302) request = response.wsgi_request - # should redirect to root url by default - assert response.status_code == 302 assert response["location"] == request.build_absolute_uri("/") # user should be authenticated @@ -117,11 +120,11 @@ # user initiates logout oidc_logout_url = reverse("oidc-logout") - response = client.get(oidc_logout_url) - request = response.wsgi_request # should redirect to logout page - assert response.status_code == 302 + response = check_html_get_response(client, oidc_logout_url, status_code=302) + request = response.wsgi_request + logout_url = reverse("logout", query_params={"remote_user": 1}) assert response["location"] == request.build_absolute_uri(logout_url) @@ -142,12 +145,11 @@ # user initiates login process login_url = reverse("oidc-login") - response = client.get(login_url) - request = response.wsgi_request - # should render an error page - assert response.status_code == 500 - assert_template_used(response, "error.html") + response = check_html_get_response( + client, login_url, status_code=500, template_used="error.html" + ) + request = response.wsgi_request # no users should be logged in assert isinstance(request.user, AnonymousUser) @@ -159,10 +161,11 @@ def test_oidc_login_complete_view_no_login_data(client, mocker): # user initiates login process login_url = reverse("oidc-login-complete") - response = client.get(login_url) - # should render an error page - assert_template_used(response, "error.html") + response = check_html_get_response( + client, login_url, status_code=500, template_used="error.html" + ) + assert_contains( response, "Login process has not been initialized.", status_code=500 ) @@ -182,11 +185,11 @@ # user initiates login process login_url = reverse("oidc-login-complete") - response = client.get(login_url) - request = response.wsgi_request - # should render an error page - assert_template_used(response, "error.html") + response = check_html_get_response( + client, login_url, status_code=400, template_used="error.html" + ) + request = response.wsgi_request assert_contains( response, "Missing query parameters for authentication.", status_code=400 ) @@ -215,11 +218,11 @@ "oidc-login-complete", query_params={"code": "some-code", "state": "some-state"} ) - response = client.get(login_url) - request = response.wsgi_request - # should render an error page - assert_template_used(response, "error.html") + response = check_html_get_response( + client, login_url, status_code=400, template_used="error.html" + ) + request = response.wsgi_request assert_contains( response, "Wrong CSRF token, aborting login process.", status_code=400 ) @@ -250,11 +253,11 @@ query_params={"code": "some-code", "state": session["login_data"]["state"]}, ) - response = client.get(login_url) - request = response.wsgi_request - # should render an error page - assert_template_used(response, "error.html") + response = check_html_get_response( + client, login_url, status_code=500, template_used="error.html" + ) + request = response.wsgi_request assert_contains(response, "User authentication failed.", status_code=500) # no user should be logged in @@ -276,11 +279,11 @@ # user initiates logout process logout_url = reverse("oidc-logout") - response = client.get(logout_url) - request = response.wsgi_request - # should render an error page - assert_template_used(response, "error.html") + response = check_html_get_response( + client, logout_url, status_code=500, template_used="error.html" + ) + request = response.wsgi_request assert_contains(response, err_msg, status_code=500) # user should be logged out from Django anyway @@ -298,7 +301,7 @@ login_url = reverse( "oidc-login", query_params={"next_path": next_path, "prompt": "none"} ) - response = client.get(login_url) + response = check_http_get_response(client, login_url, status_code=302) request = response.wsgi_request login_data = request.session["login_data"] @@ -319,12 +322,9 @@ }, ) - # login process finalization - response = client.get(login_complete_url) + # login process finalization, should redirect to logout page + response = check_http_get_response(client, login_complete_url, status_code=302) request = response.wsgi_request - - # should redirect to logout page - assert response.status_code == 302 logout_url = reverse( "logout", query_params={"next_path": next_path, "remote_user": 1} ) @@ -345,8 +345,7 @@ Anonymous user should be refused access with forbidden response. """ url = reverse("oidc-generate-bearer-token") - response = client.post(url, data={"password": "secret"}) - assert response.status_code == 403 + check_http_post_response(client, url, data={"password": "secret"}, status_code=403) def _generate_bearer_token(client, password): @@ -395,8 +394,7 @@ url = reverse( "oidc-list-bearer-tokens", query_params={"draw": 1, "start": 0, "length": 10} ) - response = client.get(url) - assert response.status_code == 403 + check_http_get_response(client, url, status_code=403) @pytest.mark.django_db @@ -414,8 +412,8 @@ url = reverse( "oidc-list-bearer-tokens", query_params={"draw": 1, "start": 0, "length": 10} ) - response = client.get(url) - assert response.status_code == 200 + + response = check_http_get_response(client, url, status_code=200) tokens_data = list(reversed(json.loads(response.content.decode("utf-8"))["data"])) for oidc_token in OIDCUserOfflineTokens.objects.all(): @@ -430,8 +428,7 @@ Anonymous user should be refused access with forbidden response. """ url = reverse("oidc-get-bearer-token") - response = client.post(url) - assert response.status_code == 403 + check_http_post_response(client, url, status_code=403) @pytest.mark.django_db @@ -448,12 +445,14 @@ token = response.content url = reverse("oidc-get-bearer-token") - response = client.post( + + response = check_http_post_response( + client, url, + status_code=200, data={"password": password, "token_id": i + 1}, - content_type="application/json", + content_type="text/plain", ) - assert response.status_code == 200 assert response.content == token @@ -467,12 +466,12 @@ _generate_bearer_token(client, password) url = reverse("oidc-get-bearer-token") - response = client.post( + check_http_post_response( + client, url, + status_code=401, data={"password": "invalid-password", "token_id": 1}, - content_type="application/json", ) - assert response.status_code == 401 def test_oidc_revoke_bearer_tokens_anonymous_user(client): @@ -480,8 +479,7 @@ Anonymous user should be refused access with forbidden response. """ url = reverse("oidc-revoke-bearer-tokens") - response = client.post(url) - assert response.status_code == 403 + check_http_post_response(client, url, status_code=403) @pytest.mark.django_db @@ -497,20 +495,15 @@ _generate_bearer_token(client, password) url = reverse("oidc-revoke-bearer-tokens") - response = client.post( - url, - data={"password": password, "token_ids": [1]}, - content_type="application/json", + + check_http_post_response( + client, url, status_code=200, data={"password": password, "token_ids": [1]}, ) - assert response.status_code == 200 assert len(OIDCUserOfflineTokens.objects.all()) == 2 - response = client.post( - url, - data={"password": password, "token_ids": [2, 3]}, - content_type="application/json", + check_http_post_response( + client, url, status_code=200, data={"password": password, "token_ids": [2, 3]}, ) - assert response.status_code == 200 assert len(OIDCUserOfflineTokens.objects.all()) == 0 @@ -525,9 +518,10 @@ _generate_bearer_token(client, password) url = reverse("oidc-revoke-bearer-tokens") - response = client.post( + + check_http_post_response( + client, url, + status_code=401, data={"password": "invalid-password", "token_ids": [1]}, - content_type="application/json", ) - assert response.status_code == 401 diff --git a/swh/web/tests/browse/views/test_content.py b/swh/web/tests/browse/views/test_content.py --- a/swh/web/tests/browse/views/test_content.py +++ b/swh/web/tests/browse/views/test_content.py @@ -19,11 +19,7 @@ from swh.web.common.exc import NotFoundExc from swh.web.common.identifiers import gen_swhid from swh.web.common.utils import gen_path_info, reverse -from swh.web.tests.django_asserts import ( - assert_contains, - assert_not_contains, - assert_template_used, -) +from swh.web.tests.django_asserts import assert_contains, assert_not_contains from swh.web.tests.strategies import ( content, content_image_type, @@ -36,6 +32,7 @@ origin_with_multiple_visits, unknown_content, ) +from swh.web.tests.utils import check_html_get_response, check_http_get_response @given(content_text()) @@ -50,14 +47,13 @@ url_raw = reverse("browse-content-raw", url_args={"query_string": content["sha1"]}) - resp = client.get(url) + resp = check_html_get_response( + client, url, status_code=200, template_used="browse/content.html" + ) content_display = _process_content_for_display(archive_data, content) mimetype = content_display["mimetype"] - assert resp.status_code == 200 - assert_template_used(resp, "browse/content.html") - if mimetype.startswith("text/"): assert_contains(resp, '' % content_display["language"]) assert_contains(resp, escape(content_display["content_data"])) @@ -77,13 +73,12 @@ url_raw = reverse("browse-content-raw", url_args={"query_string": content["sha1"]}) - resp = client.get(url) + resp = check_html_get_response( + client, url, status_code=200, template_used="browse/content.html" + ) content_display = _process_content_for_display(archive_data, content) - assert resp.status_code == 200 - assert_template_used(resp, "browse/content.html") - assert_contains(resp, '') assert_contains(resp, escape(content_display["content_data"])) assert_contains(resp, url_raw) @@ -101,12 +96,12 @@ url = reverse("browse-content", url_args={"query_string": content["sha1"]}) - resp = client.get(url) + resp = check_html_get_response( + client, url, status_code=200, template_used="browse/content.html" + ) content_display = _process_content_for_display(archive_data, content) - assert resp.status_code == 200 - assert_template_used(resp, "browse/content.html") swh_cnt_id = gen_swhid(CONTENT, sha1_git) swh_cnt_id_url = reverse("browse-swhid", url_args={"swhid": swh_cnt_id}) assert_contains(resp, swh_cnt_id_url) @@ -119,14 +114,13 @@ url_raw = reverse("browse-content-raw", url_args={"query_string": content["sha1"]}) - resp = client.get(url) + resp = check_html_get_response( + client, url, status_code=200, template_used="browse/content.html" + ) content_display = _process_content_for_display(archive_data, content) mimetype = content_display["mimetype"] content_data = content_display["content_data"] - - assert resp.status_code == 200 - assert_template_used(resp, "browse/content.html") assert_contains(resp, '' % (mimetype, content_data)) assert_contains(resp, url_raw) @@ -135,13 +129,12 @@ def test_content_view_image_no_rendering(client, archive_data, content): url = reverse("browse-content", url_args={"query_string": content["sha1"]}) - resp = client.get(url) + resp = check_html_get_response( + client, url, status_code=200, template_used="browse/content.html" + ) mimetype = content["mimetype"] encoding = content["encoding"] - - assert resp.status_code == 200 - assert_template_used(resp, "browse/content.html") assert_contains( resp, ( @@ -161,9 +154,9 @@ query_params={"path": path}, ) - resp = client.get(url) - assert resp.status_code == 200 - assert_template_used(resp, "browse/content.html") + resp = check_html_get_response( + client, url, status_code=200, template_used="browse/content.html" + ) assert_contains(resp, '