From 97d30478c731a9ca3e63ceb6ebd13a29ed207d5c Mon Sep 17 00:00:00 2001 From: Peter Bieringer Date: Tue, 12 Aug 2025 16:12:38 +0200 Subject: [PATCH] add tests for storage hook placeholders --- radicale/tests/test_storage.py | 214 +++++++++++++++++++++++++++++++++ 1 file changed, 214 insertions(+) diff --git a/radicale/tests/test_storage.py b/radicale/tests/test_storage.py index 91ff8110..d6ecefbb 100644 --- a/radicale/tests/test_storage.py +++ b/radicale/tests/test_storage.py @@ -21,7 +21,10 @@ Tests for storage backends. """ +import json +import logging import os +import re import shutil from typing import ClassVar, cast @@ -186,6 +189,217 @@ class TestMultiFileSystem(BaseTest): assert answer is not None assert "\r\nUID:%s\r\n" % uid in answer + def test_hook_placeholders_PUT(self, caplog) -> None: + """Run hook and check placeholders: PUT""" + self.configure({"storage": {"hook": "echo \"hook-json {'user':'%(user)s', 'cwd':'%(cwd)s', 'path':'%(path)s', 'request':'%(request)s', 'to_path':'%(to_path)s'}\""}}) + found = 0 + self.mkcalendar("/calendar.ics/") + event = get_file_content("event1.ics") + path = "/calendar.ics/event1.ics" + self.put(path, event) + for line in caplog.messages: + if line.find("\"hook-json ") != -1: + found = 1 + s = re.search('.*\"hook-json ({.*})".*', line).group(1).replace("'", "\"") + d = json.loads(s) + if d["user"] == "Anonymous": + found = found | 2 + if d["cwd"]: + found = found | 4 + if d["path"]: + found = found | 8 + if d["path"] == d["cwd"] + "/collection-root/calendar.ics/event1.ics": + found = found | 16 + if d["request"]: + found = found | 64 + if d["request"] == "PUT": + found = found | 128 + if d["to_path"]: + found = found | 32 + if d["to_path"] == "": + found = found | 256 + else: + found = found | 256 | 32 + if (found != 511): + raise ValueError("Logging misses expected hook log line, found=%d data=%r", found, d) + else: + logging.info("Logging contains expected hook line, found=%d data=%r", found, d) + + def test_hook_placeholders_DELETE(self, caplog) -> None: + """Run hook and check placeholders: DELETE""" + self.configure({"storage": {"hook": "echo \"hook-json {'user':'%(user)s', 'cwd':'%(cwd)s', 'path':'%(path)s', 'request':'%(request)s', 'to_path':'%(to_path)s'}\""}}) + found = 0 + self.mkcalendar("/calendar.ics/") + event = get_file_content("event1.ics") + path = "/calendar.ics/event1.ics" + self.put(path, event) + self.delete(path) + for line in caplog.messages: + if line.find("\"hook-json ") != -1: + found = 1 + s = re.search('.*\"hook-json ({.*})".*', line).group(1).replace("'", "\"") + d = json.loads(s) + if d["user"] == "Anonymous": + found = found | 2 + if d["cwd"]: + found = found | 4 + if d["path"]: + found = found | 8 + if d["path"] == d["cwd"] + "/collection-root/calendar.ics/event1.ics": + found = found | 16 + if d["request"]: + found = found | 64 + if d["request"] == "DELETE": + found = found | 128 + if d["to_path"]: + found = found | 32 + if d["to_path"] == "": + found = found | 256 + else: + found = found | 256 | 32 + if (found != 511): + raise ValueError("Logging misses expected hook log line, found=%d data=%r", found, s) + else: + logging.info("Logging contains expected hook line, found=%d data=%r", found, d) + + def test_hook_placeholders_MKCALENDAR(self, caplog) -> None: + """Run hook and check placeholders: MKCALENDAR""" + self.configure({"storage": {"hook": "echo \"hook-json {'user':'%(user)s', 'cwd':'%(cwd)s', 'path':'%(path)s', 'request':'%(request)s', 'to_path':'%(to_path)s'}\""}}) + found = 0 + self.mkcalendar("/calendar.ics/") + for line in caplog.messages: + if line.find("\"hook-json ") != -1: + found = 1 + s = re.search('.*\"hook-json ({.*})".*', line).group(1).replace("'", "\"") + d = json.loads(s) + if d["user"] == "Anonymous": + found = found | 2 + if d["cwd"]: + found = found | 4 + if d["path"]: + found = found | 8 + if d["path"] == d["cwd"] + "/collection-root/calendar.ics/": + found = found | 16 + if d["request"]: + found = found | 64 + if d["request"] == "MKCALENDAR": + found = found | 128 + if d["to_path"]: + found = found | 32 + if d["to_path"] == "": + found = found | 256 + else: + found = found | 256 | 32 + if (found != 511): + raise ValueError("Logging misses expected hook log line, found=%d data=%r", found, d) + else: + logging.info("Logging contains expected hook line, found=%d data=%r", found, d) + + def test_hook_placeholders_MKCOL(self, caplog) -> None: + """Run hook and check placeholders: MKCOL""" + self.configure({"storage": {"hook": "echo \"hook-json {'user':'%(user)s', 'cwd':'%(cwd)s', 'path':'%(path)s', 'request':'%(request)s', 'to_path':'%(to_path)s'}\""}}) + found = 0 + self.mkcol("/user1/") + for line in caplog.messages: + if line.find("\"hook-json ") != -1: + found = 1 + s = re.search('.*\"hook-json ({.*})".*', line).group(1).replace("'", "\"") + d = json.loads(s) + if d["user"] == "Anonymous": + found = found | 2 + if d["cwd"]: + found = found | 4 + if d["path"]: + found = found | 8 + if d["path"] == d["cwd"] + "/collection-root/user1/": + found = found | 16 + if d["request"]: + found = found | 64 + if d["request"] == "MKCOL": + found = found | 128 + if d["to_path"]: + found = found | 32 + if d["to_path"] == "": + found = found | 256 + else: + found = found | 256 | 32 + if (found != 511): + raise ValueError("Logging misses expected hook log line, found=%d data=%r", found, d) + else: + logging.info("Logging contains expected hook line, found=%d data=%r", found, d) + + def test_hook_placeholders_PROPPATCH(self, caplog) -> None: + """Run hook and check placeholders: PROPPATCH""" + self.configure({"storage": {"hook": "echo \"hook-json {'user':'%(user)s', 'cwd':'%(cwd)s', 'path':'%(path)s', 'request':'%(request)s', 'to_path':'%(to_path)s'}\""}}) + found = 0 + self.mkcalendar("/calendar.ics/") + proppatch = get_file_content("proppatch_set_calendar_color.xml") + _, responses = self.proppatch("/calendar.ics/", proppatch) + for line in caplog.messages: + if line.find("\"hook-json ") != -1: + found = 1 + s = re.search('.*\"hook-json ({.*})".*', line).group(1).replace("'", "\"") + d = json.loads(s) + if d["user"] == "Anonymous": + found = found | 2 + if d["cwd"]: + found = found | 4 + if d["path"]: + found = found | 8 + if d["path"] == d["cwd"] + "/collection-root/calendar.ics/": + found = found | 16 + if d["request"]: + found = found | 64 + if d["request"] == "PROPPATCH": + found = found | 128 + if d["to_path"]: + found = found | 32 + if d["to_path"] == "": + found = found | 256 + else: + found = found | 256 | 32 + if (found != 511): + raise ValueError("Logging misses expected hook log line, found=%d data=%r", found, d) + else: + logging.info("Logging contains expected hook line, found=%d data=%r", found, d) + + def test_hook_placeholders_MOVE(self, caplog) -> None: + """Run hook and check placeholders: MOVE""" + self.configure({"storage": {"hook": "echo \"hook-json {'user':'%(user)s', 'cwd':'%(cwd)s', 'path':'%(path)s', 'request':'%(request)s', 'to_path':'%(to_path)s'}\""}}) + found = 0 + self.mkcalendar("/calendar.ics/") + event = get_file_content("event1.ics") + path1 = "/calendar.ics/event1.ics" + path2 = "/calendar.ics/event2.ics" + self.put(path1, event) + self.request("MOVE", path1, check=201, + HTTP_DESTINATION="http://127.0.0.1/"+path2) + for line in caplog.messages: + if line.find("\"hook-json ") != -1: + found = 1 + s = re.search('.*\"hook-json ({.*})".*', line).group(1).replace("'", "\"") + d = json.loads(s) + if d["user"] == "Anonymous": + found = found | 2 + if d["cwd"]: + found = found | 4 + if d["path"]: + found = found | 8 + if d["path"] == d["cwd"] + "/collection-root/calendar.ics/event1.ics": + found = found | 16 + if d["request"]: + found = found | 64 + if d["request"] == "MOVE": + found = found | 128 + if d["to_path"]: + found = found | 32 + if d["to_path"] == d["cwd"] + "/collection-root/calendar.ics/event2.ics": + found = found | 256 + if (found != 511): + raise ValueError("Logging misses expected hook log line, found=%d data=%r", found, d) + else: + logging.info("Logging contains expected hook line, found=%d data=%r", found, d) + class TestMultiFileSystemNoLock(BaseTest): """Tests for multifilesystem_nolock."""