Some checks failed
CodeQL / Analyze (javascript) (push) Failing after 16s
CodeQL / Analyze (python) (push) Failing after 3s
i18n sync check / check:sync (push) Failing after 3s
React Doctor / react-doctor (push) Failing after 16s
Branch Build CE / Build-Push Admin Docker Image (${{ matrix.arch }}) (push) Has been cancelled
Branch Build CE / Merge Admin Manifest (push) Has been cancelled
Branch Build CE / Build-Push Web Docker Image (${{ matrix.arch }}) (push) Has been cancelled
Branch Build CE / Merge Web Manifest (push) Has been cancelled
Branch Build CE / Build-Push Space Docker Image (${{ matrix.arch }}) (push) Has been cancelled
Branch Build CE / Merge Proxy Manifest (push) Has been cancelled
Branch Build CE / Merge Space Manifest (push) Has been cancelled
Branch Build CE / Prepare AIO Assets (push) Has been cancelled
Branch Build CE / Build Setup (push) Has been cancelled
Branch Build CE / Build-Push Live Collaboration Docker Image (${{ matrix.arch }}) (push) Has been cancelled
Branch Build CE / Merge Live Collaboration Manifest (push) Has been cancelled
Branch Build CE / Build-Push API Server Docker Image (${{ matrix.arch }}) (push) Has been cancelled
Branch Build CE / Merge API Server Manifest (push) Has been cancelled
Branch Build CE / Build-Push Proxy Docker Image (${{ matrix.arch }}) (push) Has been cancelled
Branch Build CE / Build-Push AIO Docker Image (${{ matrix.arch }}) (push) Has been cancelled
Branch Build CE / Merge AIO Manifest (push) Has been cancelled
Branch Build CE / Upload Build Assets (push) Has been cancelled
Branch Build CE / Build Release (push) Has been cancelled
70 lines
2.4 KiB
Python
70 lines
2.4 KiB
Python
# Copyright (c) 2023-present Plane Software, Inc. and contributors
|
|
# SPDX-License-Identifier: AGPL-3.0-only
|
|
# See the LICENSE file for details.
|
|
|
|
"""
|
|
Regression tests for the ``dispatch()`` exception handling on the shared
|
|
``BaseAPIView`` / ``BaseViewSet`` classes.
|
|
|
|
When ``super().dispatch()`` raises an unhandled exception, ``dispatch()`` must
|
|
return the HTTP ``Response`` produced by ``handle_exception()`` -- not the raw
|
|
exception object. Returning the exception causes Django's response pipeline to
|
|
fail with ``TypeError: 'Exception' object is not a valid HTTP response``.
|
|
|
|
See: https://github.com/makeplane/plane/issues/9157
|
|
"""
|
|
|
|
import pytest
|
|
from unittest.mock import patch
|
|
|
|
from rest_framework import status
|
|
from rest_framework.response import Response
|
|
from rest_framework.test import APIRequestFactory
|
|
|
|
from plane.api.views.base import BaseAPIView as ApiBaseAPIView, BaseViewSet as ApiBaseViewSet
|
|
from plane.app.views.base import BaseAPIView as AppBaseAPIView, BaseViewSet as AppBaseViewSet
|
|
from plane.license.api.views.base import BaseAPIView as LicenseBaseAPIView
|
|
from plane.space.views.base import BaseAPIView as SpaceBaseAPIView, BaseViewSet as SpaceBaseViewSet
|
|
|
|
|
|
# Every shared base view that wraps ``super().dispatch()`` in a try/except.
|
|
VIEW_CLASSES = [
|
|
ApiBaseAPIView,
|
|
ApiBaseViewSet,
|
|
AppBaseAPIView,
|
|
AppBaseViewSet,
|
|
LicenseBaseAPIView,
|
|
SpaceBaseAPIView,
|
|
SpaceBaseViewSet,
|
|
]
|
|
|
|
|
|
@pytest.mark.unit
|
|
@pytest.mark.parametrize(
|
|
"view_class",
|
|
VIEW_CLASSES,
|
|
ids=lambda c: f"{c.__module__}.{c.__name__}",
|
|
)
|
|
def test_dispatch_returns_response_when_super_dispatch_raises(view_class):
|
|
"""dispatch() must return handle_exception()'s Response, not the exception."""
|
|
request = APIRequestFactory().get("/api/test/")
|
|
view = view_class()
|
|
|
|
sentinel = Response(
|
|
{"error": "Something went wrong please try again later"},
|
|
status=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
)
|
|
|
|
with (
|
|
patch("rest_framework.views.APIView.dispatch", side_effect=RuntimeError("boom")),
|
|
patch.object(view_class, "handle_exception", return_value=sentinel) as mock_handle,
|
|
):
|
|
result = view.dispatch(request)
|
|
|
|
mock_handle.assert_called_once()
|
|
assert isinstance(result, Response), (
|
|
f"{view_class.__module__}.{view_class.__name__}.dispatch() returned "
|
|
f"{type(result).__name__} instead of an HTTP Response"
|
|
)
|
|
assert result is sentinel
|