From 83b00f1b7b27af7770925f3ffdcea68f54fa91e7 Mon Sep 17 00:00:00 2001 From: Peter Bieringer Date: Mon, 8 Jun 2026 21:59:57 +0200 Subject: [PATCH] sharing/bday conversion: add additional test cases via proxy --- radicale/tests/test_sharing.py | 141 +++++++++++++++++++++++++++++++-- 1 file changed, 135 insertions(+), 6 deletions(-) diff --git a/radicale/tests/test_sharing.py b/radicale/tests/test_sharing.py index 447893a2..5a01b643 100644 --- a/radicale/tests/test_sharing.py +++ b/radicale/tests/test_sharing.py @@ -86,13 +86,13 @@ class TestSharingApiSanity(BaseTest): _, headers, answer = self._sharing_api(sharing_type, action, check, login, data, content_type, accept, prefix=prefix) return _, headers, answer - def _propfind_allprop(self, path: str, login: str = "", prefix: Union[str, None] = None, check=207) -> dict: + def _propfind_allprop(self, path: str, login: str = "", prefix: Union[str, None] = None, check=207, x_forwarded_for: Union[str, None] = None) -> dict: propfind_allprop = get_file_content("allprop.xml") if prefix is not None: path = prefix + path _, responses = self.propfind(path=path, data=propfind_allprop, login=login, x_forwarded_for="127.0.0.2", check=check) else: - _, responses = self.propfind(path=path, data=propfind_allprop, login=login, check=check) + _, responses = self.propfind(path=path, data=propfind_allprop, login=login, check=check, x_forwarded_for=x_forwarded_for) logging.info("response: %r", responses) if check != 207: return {} @@ -5845,7 +5845,9 @@ permissions: RrWw""") assert int(str(prop.text)) == 2 def test_sharing_api_map_vcf_bday_self(self) -> None: - """share-by-map with conversion=bday to self tests.""" + """share-by-map with conversion=bday to self tests (without and with simulated proxy).""" + script_name = "/radicale" + self.configure({"auth": {"type": "htpasswd", "htpasswd_filename": self.htpasswd_file_path, "htpasswd_encryption": "plain"}, @@ -5859,6 +5861,7 @@ permissions: RrWw""") "response_header_on_debug": "True", "response_content_on_debug": "True", "request_content_on_debug": "True"}, + "server": {"script_name": script_name}, "rights": {"type": "owner_only"}}) json_dict: dict @@ -5899,6 +5902,17 @@ permissions: RrWw""") assert not isinstance(response, int) assert "CR:supported-address-data" in response + logging.info("\n*** PROPFIND collection owner via proxy -> ok") + _, responses = self.propfind(script_name + path_mapped, """\ + + + +""", login="owner:ownerpw", x_forwarded_for="127.0.0.2") + logging.info("response: %r", responses) + response = responses[script_name + path_mapped] + assert not isinstance(response, int) + assert "CR:supported-address-data" in response + # execute GET as owner logging.info("\n*** GET VCF collection owner -> ok") _, answer = self.get(path_mapped, login="owner:ownerpw") @@ -5948,6 +5962,36 @@ permissions: RrWw""") assert "{urn:ietf:params:xml:ns:carddav}addressbook" in resourcetypes.tag assert "{urn:ietf:params:xml:ns:caldav}calendar" not in resourcetypes.tag + logging.info("\n*** PROPFIND all as owner via proxy") + _, responses = self.propfind(script_name + path_owner, """\ + + + + + + + + + + + + + + +""", login="owner:ownerpw", HTTP_DEPTH="1", x_forwarded_for="127.0.0.2") + # logging.debug("responses: %r", responses) + response = responses[script_name + path_mapped] + assert not isinstance(response, int) + logging.debug("response %r: %r", path_mapped, response) + assert "C:supported-calendar-component-set" in response + assert path_shared not in responses + assert "D:resourcetype" in response + status, resourcetype = response["D:resourcetype"] + resourcetypes = resourcetype.find(xmlutils.make_clark("CR:addressbook")) + assert resourcetypes is not None + assert "{urn:ietf:params:xml:ns:carddav}addressbook" in resourcetypes.tag + assert "{urn:ietf:params:xml:ns:caldav}calendar" not in resourcetypes.tag + # enable + unhide logging.info("\n*** enable+unhide bday owner to itself -> ok") json_dict = {} @@ -5957,7 +6001,7 @@ permissions: RrWw""") _, headers, answer = self._sharing_api_json("map", "update", check=200, login="owner:ownerpw", json_dict=json_dict) # check PROPFIND item as owner - logging.info("\n*** PROPFIND all as owner") + logging.info("\n*** PROPFIND item as owner") _, responses = self.propfind(path_owner, """\ @@ -5995,8 +6039,47 @@ permissions: RrWw""") assert {'name': 'VTODO'} not in comp_attr assert {'name': 'VJOURNAL'} not in comp_attr - # check PROPFIND item as owner - logging.info("\n*** PROPFIND item as owner -> calendar") + # check PROPFIND item as owner via proxy + logging.info("\n*** PROPFIND collection as owner via proxy") + _, responses = self.propfind(script_name + path_owner, """\ + + + + + + + + + + + + + + +""", login="owner:ownerpw", HTTP_DEPTH="1", x_forwarded_for="127.0.0.2") + # logging.debug("responses: %r", responses) + response = responses[script_name + path_shared] + assert not isinstance(response, int) + logging.debug("response %r: %r", path_mapped, response) + assert "C:supported-calendar-component-set" in response + assert script_name + path_shared in responses + status, resourcetype = response["D:resourcetype"] + resourcetypes = resourcetype.find(xmlutils.make_clark("C:calendar")) + assert resourcetypes is not None + assert "{urn:ietf:params:xml:ns:carddav}addressbook" not in resourcetypes.tag + assert "{urn:ietf:params:xml:ns:caldav}calendar" in resourcetypes.tag + status, sup_cal_comp_set = response["C:supported-calendar-component-set"] + sup_cal_comp_sets = sup_cal_comp_set.findall(xmlutils.make_clark("C:comp")) + comp_attr = [] + for comp in sup_cal_comp_sets: + comp_attr.append(comp.attrib) + logging.debug("comp: %r", comp.attrib) + assert {'name': 'VEVENT'} in comp_attr + assert {'name': 'VTODO'} not in comp_attr + assert {'name': 'VJOURNAL'} not in comp_attr + + # check PROPFIND collection as owner + logging.info("\n*** PROPFIND collection as owner -> calendar") response = self._propfind_allprop(path_shared, login="owner:ownerpw") logging.debug("response: %r", response) assert "CR:supported-address-data" not in response @@ -6004,6 +6087,15 @@ permissions: RrWw""") assert "C:supported-calendar-component-set" in response assert "D:current-user-privilege-set" in response + # check PROPFIND collection as owner via proxy + logging.info("\n*** PROPFIND collection as owner via proxy -> calendar") + response = self._propfind_allprop(script_name + path_shared, login="owner:ownerpw", x_forwarded_for="127.0.0.2") + logging.debug("response: %r", response) + assert "CR:supported-address-data" not in response + assert "D:sync-token" not in response + assert "C:supported-calendar-component-set" in response + assert "D:current-user-privilege-set" in response + # verify content as owner logging.info("\n*** GET collection owner -> ok") _, headers, answer = self.request("GET", path_shared, login="owner:ownerpw") @@ -6013,6 +6105,43 @@ permissions: RrWw""") assert 'Content-Disposition' in headers assert 'Calendar.ics' in headers['Content-Disposition'] + # verify content as owner via proxy + logging.info("\n*** GET collection owner via proxy -> ok") + _, headers, answer = self.request("GET", script_name + path_shared, login="owner:ownerpw", x_forwarded_for="127.0.0.2") + assert 'Content-Type' in headers + assert 'text/calendar' in headers['Content-Type'] + # title from default + assert 'Content-Disposition' in headers + assert 'Calendar.ics' in headers['Content-Disposition'] + + # verify report as owner + logging.info("\n*** REPORT collection owner -> ok") + _, responses = self.report(path_shared, """\ + + + + + +""", login="owner:ownerpw") + logging.debug("resonses: %r", responses) + assert path_shared + "contact2-with-bday.ics" in responses + assert path_shared + "contact3-with-bday.ics" in responses + assert path_shared + "contact1.ics" not in responses + + # verify report as owner via proxy + logging.info("\n*** REPORT collection owner -> ok") + _, responses = self.report(script_name + path_shared, """\ + + + + + +""", login="owner:ownerpw", x_forwarded_for="127.0.0.2") + logging.debug("resonses: %r", responses) + assert script_name + path_shared + "contact2-with-bday.ics" in responses + assert script_name + path_shared + "contact3-with-bday.ics" in responses + assert script_name + path_shared + "contact1.ics" not in responses + def test_sharing_api_token_vcf_bday(self) -> None: """share-by-bday to a token tests.""" self.configure({"auth": {"type": "htpasswd",