a76760edba
Funciones reutilizables creadas esta sesion para el sistema self-hosted de contactos/calendario (Xandikos) y la app osint_web: - grupo dav (infra): split_vcards, split_vevents_to_vcalendars, extract_or_make_uid, carddav_put_vcard, caldav_put_event, dav_list_resources, dav_get_resource, dav_list_calendars - pipelines: import_vcf_to_carddav, import_ics_to_caldav - obsidian: build_obsidian_graph (grafo agregado del vault)
89 lines
2.5 KiB
Python
89 lines
2.5 KiB
Python
"""Tests para carddav_put_vcard.
|
|
|
|
Smoke deterministas: monkeypatchean urllib.request.urlopen para capturar el
|
|
Request object (URL, method, headers, body) sin enviarlo a un servidor real.
|
|
"""
|
|
|
|
import base64
|
|
import sys
|
|
|
|
import infra.carddav_put_vcard # noqa: F401
|
|
|
|
mod = sys.modules["infra.carddav_put_vcard"]
|
|
carddav_put_vcard = mod.carddav_put_vcard
|
|
|
|
|
|
class _FakeResp:
|
|
status = 201
|
|
|
|
def __enter__(self):
|
|
return self
|
|
|
|
def __exit__(self, *a):
|
|
return False
|
|
|
|
|
|
def _capture(monkeypatch):
|
|
captured = {}
|
|
|
|
def fake_urlopen(req, timeout=None, context=None):
|
|
captured["url"] = req.full_url
|
|
captured["method"] = req.get_method()
|
|
captured["headers"] = dict(req.header_items())
|
|
captured["body"] = req.data
|
|
return _FakeResp()
|
|
|
|
monkeypatch.setattr(mod.urllib.request, "urlopen", fake_urlopen)
|
|
return captured
|
|
|
|
|
|
def _call():
|
|
return carddav_put_vcard(
|
|
base_url="https://dav.example.com",
|
|
username="enmanuel",
|
|
password="secret-pw",
|
|
collection_path="/enmanuel/contacts/addressbook/",
|
|
uid="abc-123@google.com",
|
|
vcard_text="BEGIN:VCARD\r\nFN:Ada\r\nUID:abc-123@google.com\r\nEND:VCARD",
|
|
)
|
|
|
|
|
|
def test_construye_request_put_con_headers_correctos(monkeypatch):
|
|
cap = _capture(monkeypatch)
|
|
res = _call()
|
|
assert res == {"status": "ok", "http_status": 201, "url": cap["url"]}
|
|
assert cap["method"] == "PUT"
|
|
|
|
|
|
def test_url_se_forma_con_uid_saneado(monkeypatch):
|
|
cap = _capture(monkeypatch)
|
|
_call()
|
|
# El '@' del uid se sanea a '_'.
|
|
assert cap["url"].endswith("/enmanuel/contacts/addressbook/abc-123_google.com.vcf")
|
|
|
|
|
|
def test_content_type_es_text_vcard(monkeypatch):
|
|
cap = _capture(monkeypatch)
|
|
_call()
|
|
# urllib capitaliza las claves de header.
|
|
headers = {k.lower(): v for k, v in cap["headers"].items()}
|
|
assert headers["content-type"] == "text/vcard; charset=utf-8"
|
|
|
|
|
|
def test_basic_auth_header_correcto(monkeypatch):
|
|
cap = _capture(monkeypatch)
|
|
_call()
|
|
headers = {k.lower(): v for k, v in cap["headers"].items()}
|
|
expected = "Basic " + base64.b64encode(b"enmanuel:secret-pw").decode("ascii")
|
|
assert headers["authorization"] == expected
|
|
|
|
|
|
def test_httperror_devuelve_status_error(monkeypatch):
|
|
def fake_urlopen(req, timeout=None, context=None):
|
|
raise mod.urllib.error.HTTPError(req.full_url, 409, "Conflict", {}, None)
|
|
|
|
monkeypatch.setattr(mod.urllib.request, "urlopen", fake_urlopen)
|
|
res = _call()
|
|
assert res["status"] == "error"
|
|
assert res["http_status"] == 409
|