diff --git a/swh/core/api/__init__.py b/swh/core/api/__init__.py --- a/swh/core/api/__init__.py +++ b/swh/core/api/__init__.py @@ -1,4 +1,4 @@ -# Copyright (C) 2015-2020 The Software Heritage developers +# Copyright (C) 2015-2022 The Software Heritage developers # See the AUTHORS file at the top-level directory of this distribution # License: GNU General Public License version 3, or any later version # See top-level LICENSE file for more information @@ -320,9 +320,6 @@ status_code = response.status_code status_class = response.status_code // 100 - if status_code == 404: - raise RemoteException(payload="404 not found", response=response) - exception = None # TODO: only old servers send pickled error; stop trying to unpickle @@ -356,6 +353,9 @@ except (TypeError, pickle.UnpicklingError): raise RemoteException(payload=data, response=response) + if status_code == 404 and type(exception) not in self.reraise_exceptions: + raise RemoteException(payload="404 not found", response=response) + if exception: raise exception from None diff --git a/swh/core/api/tests/test_rpc_client_server.py b/swh/core/api/tests/test_rpc_client_server.py --- a/swh/core/api/tests/test_rpc_client_server.py +++ b/swh/core/api/tests/test_rpc_client_server.py @@ -1,4 +1,4 @@ -# Copyright (C) 2018-2019 The Software Heritage developers +# Copyright (C) 2018-2022 The Software Heritage developers # See the AUTHORS file at the top-level directory of this distribution # License: GNU General Public License version 3, or any later version # See top-level LICENSE file for more information @@ -19,6 +19,10 @@ """Another exception class to distinguish error handlers""" +class NotFoundException(Exception): + pass + + # this class is used on the server part class RPCTest: @remote_api_endpoint("endpoint_url") @@ -42,6 +46,10 @@ def raise_expectedexc(self): raise ExpectedException("that was expected") + @remote_api_endpoint("raises_not_found_exc") + def raise_not_found_exc(self): + raise NotFoundException() + # this class is used on the client part. We cannot inherit from RPCTest # because the automagic metaclass based code that generates the RPCClient @@ -70,9 +78,14 @@ def raise_expectedexc(self): return "nothing" + @remote_api_endpoint("raises_not_found_exc") + def raise_not_found_exc(self): + return "not found" + class RPCTestClient(RPCClient): backend_class = RPCTest2 + reraise_exceptions = [NotFoundException] @pytest.fixture @@ -85,6 +98,10 @@ def my_expected_error_handler(exception): return error_handler(exception, encode_data_server, status_code=400) + @application.errorhandler(NotFoundException) + def not_found_error_handler(exception): + return error_handler(exception, encode_data_server, status_code=404) + @application.errorhandler(Exception) def my_error_handler(exception): return error_handler(exception, encode_data_server) @@ -111,6 +128,13 @@ swh_rpc_client.not_on_server() +def test_api_reraise_not_found(swh_rpc_client): + # A 'missing' endpoint (server-side) should raise an exception + # due to a 404, since at the end, we do a GET/POST an inexistent URL + with pytest.raises(NotFoundException): + swh_rpc_client.raise_not_found_exc() + + def test_api_endpoint_kwargs(swh_rpc_client): res = swh_rpc_client.something(data="whatever") assert res == "whatever"