From 4b9827f491210fe6bbedd2c068fc1fae27a847d3 Mon Sep 17 00:00:00 2001 From: Peter Bieringer Date: Fri, 3 Apr 2026 07:16:07 +0200 Subject: [PATCH 1/5] delay_on_error: catch all (not only PermissionDenied) execptions --- radicale/app/__init__.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/radicale/app/__init__.py b/radicale/app/__init__.py index 1303dc9f..0a93dc2c 100644 --- a/radicale/app/__init__.py +++ b/radicale/app/__init__.py @@ -36,6 +36,7 @@ import pprint import pstats import random import time +import traceback import zlib from http import client from typing import Iterable, List, Mapping, Tuple, Union @@ -574,6 +575,10 @@ class Application(ApplicationPartDelete, ApplicationPartHead, except PermissionError as e: logger.error("PermissionError: %s", e) status, headers, answer, xml_request = httputils.INTERNAL_SERVER_ERROR + except Exception as e: + logger.error("Exception: %s", e) + logging.error("%s", traceback.format_exc()) + status, headers, answer, xml_request = httputils.INTERNAL_SERVER_ERROR # Profiling if self._profiling_per_request: From dfa7ffc0b31292d3369b7ceaaa403ec9ff1cb019 Mon Sep 17 00:00:00 2001 From: Peter Bieringer Date: Fri, 3 Apr 2026 07:17:12 +0200 Subject: [PATCH 2/5] server/delay_on_error: add code to trigger for testing --- radicale/app/options.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/radicale/app/options.py b/radicale/app/options.py index 9e347de2..b4c1c29c 100644 --- a/radicale/app/options.py +++ b/radicale/app/options.py @@ -18,6 +18,7 @@ # You should have received a copy of the GNU General Public License # along with Radicale. If not, see . +import os from http import client from radicale import httputils, types @@ -33,4 +34,7 @@ class ApplicationPartOptions(ApplicationBase): "Allow": ", ".join( name[3:] for name in dir(self) if name.startswith("do_")), "DAV": httputils.DAV_HEADERS} + if 'PYTEST_VERSION' in os.environ and 'PYTEST_RADICALE_RAISE_GENERIC_ERROR' in os.environ: + # trigger special test case + raise ValueError('PYTEST_RADICALE_RAISE_GENERIC_ERROR') return client.OK, headers, None, None From 525fddf587816c9ae6e81d3de9aabe4248740ba0 Mon Sep 17 00:00:00 2001 From: Peter Bieringer Date: Fri, 3 Apr 2026 07:17:41 +0200 Subject: [PATCH 3/5] extend copyright --- radicale/app/options.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/radicale/app/options.py b/radicale/app/options.py index b4c1c29c..bcb3663e 100644 --- a/radicale/app/options.py +++ b/radicale/app/options.py @@ -3,7 +3,7 @@ # Copyright © 2008 Pascal Halter # Copyright © 2008-2017 Guillaume Ayoub # Copyright © 2017-2021 Unrud -# Copyright © 2025-2025 Peter Bieringer +# Copyright © 2025-2026 Peter Bieringer # # This library is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by From d50479cefbf91a4b44d4e1e2c02a791fce6ce214 Mon Sep 17 00:00:00 2001 From: Peter Bieringer Date: Fri, 3 Apr 2026 07:18:09 +0200 Subject: [PATCH 4/5] server_delay_on_error: add test --- radicale/tests/test_base.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/radicale/tests/test_base.py b/radicale/tests/test_base.py index d17f3d15..98bdf654 100644 --- a/radicale/tests/test_base.py +++ b/radicale/tests/test_base.py @@ -720,6 +720,23 @@ permissions: RrWw""") _, headers, _ = self.request("OPTIONS", "/", check=200) assert "DAV" in headers + def test_server_error_delay_basic(self) -> None: + """Trigger a server error and check delay.""" + delay = .3 + delay_min = delay * 0.9 # no random jitter during test + delay_max = delay + 0.2 # no random jitter during test + if sys.platform == "darwin": # no reliable sleep times + delay_max = delay_max * 1.5 + + self.configure({"server": {"delay_on_error": delay}}) + os.environ["PYTEST_RADICALE_RAISE_GENERIC_ERROR"] = "1" + time_begin = datetime.datetime.now() + _, headers, answer = self.request("OPTIONS", "/", check=500) + time_end = datetime.datetime.now() + time_delta = (time_end - time_begin).total_seconds() + assert time_delta > delay_min + assert time_delta < delay_max + def test_delete_collection(self) -> None: """Delete a collection.""" self.mkcalendar("/calendar.ics/") From ad43feacb89e9618651a6e9be484253c09265c40 Mon Sep 17 00:00:00 2001 From: Peter Bieringer Date: Fri, 3 Apr 2026 07:28:29 +0200 Subject: [PATCH 5/5] delay_on_error: remove trigger flag from environment --- radicale/tests/test_base.py | 1 + 1 file changed, 1 insertion(+) diff --git a/radicale/tests/test_base.py b/radicale/tests/test_base.py index 98bdf654..b36497dd 100644 --- a/radicale/tests/test_base.py +++ b/radicale/tests/test_base.py @@ -736,6 +736,7 @@ permissions: RrWw""") time_delta = (time_end - time_begin).total_seconds() assert time_delta > delay_min assert time_delta < delay_max + del os.environ["PYTEST_RADICALE_RAISE_GENERIC_ERROR"] def test_delete_collection(self) -> None: """Delete a collection."""