Skip to content

Commit 281e0ee

Browse files
committed
[FIX] api_log: Log readonly exception
1 parent 4bd47a7 commit 281e0ee

3 files changed

Lines changed: 46 additions & 3 deletions

File tree

api_log/models/api_log.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -173,10 +173,10 @@ def log_response(self, response):
173173
return self.sudo().write(log_response_values)
174174

175175
def _prepare_log_exception(self, exception):
176-
exception.headers = getattr(exception, "headers", {})
176+
exception_headers = getattr(exception, "headers", {})
177177
values = {
178178
"stack_trace": "".join(format_exception(exception)),
179-
"response_headers": self._inject_log_entry(exception.headers),
179+
"response_headers": self._inject_log_entry(exception_headers),
180180
"response_body": str(exception),
181181
"response_date": fields.Datetime.now(),
182182
"response_time": self._current_time(),

api_log/tests/common.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,23 @@
11
# Copyright 2025 Simone Rubino - PyTech
22
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
33

4+
import contextlib
5+
6+
from odoo.http import Response
47
from odoo.tests.common import HttpCase
58

9+
from odoo.addons.website.tools import MockRequest
10+
611

712
class Common(HttpCase):
813
@classmethod
914
def setUpClass(cls):
1015
super().setUpClass()
1116
cls.log_model = cls.env["api.log"]
17+
18+
@contextlib.contextmanager
19+
def _mock_request_exc_handling(self, *args, **kwargs):
20+
"""Enhance the standard mock of a request with exception handling."""
21+
with MockRequest(*args, **kwargs) as mock_request:
22+
mock_request.dispatcher.handle_error = lambda exc: Response()
23+
yield mock_request

api_log/tests/test_api_log.py

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,37 @@ def test_log_response(self):
5050

5151
def test_log_exception(self):
5252
log = self.log_model.create({})
53-
log.log_exception(Exception())
53+
54+
with self._mock_request_exc_handling(self.env):
55+
log.log_exception(Exception())
5456

5557
self.assertEqual(log.response_headers["API-Log-Entry-ID"], str(log.id))
58+
59+
def test_log_exception_readonly_headers(self):
60+
"""
61+
If the exception's headers are readonly,
62+
they can be logged.
63+
"""
64+
# Arrange
65+
log = self.log_model.create({})
66+
exc_headers = {
67+
"answer": 42,
68+
}
69+
70+
class ReadOnlyException(Exception):
71+
@property
72+
def headers(self):
73+
return exc_headers.copy()
74+
75+
ro_exception = ReadOnlyException()
76+
# pre-condition
77+
with self.assertRaises(AttributeError) as ae:
78+
ro_exception.headers = dict()
79+
self.assertIn("can't set attribute", str(ae.exception))
80+
81+
# Act
82+
with self._mock_request_exc_handling(self.env):
83+
log.log_exception(ro_exception)
84+
85+
# Assert
86+
self.assertLess(exc_headers.items(), log.response_headers.items())

0 commit comments

Comments
 (0)