Skip to content

Commit ed7e276

Browse files
committed
eddited after rewiew:
client_push.py removed unnecessary code, specified exceptions, added type hints test_push_logging.py changeed to use real job
1 parent 8317269 commit ed7e276

File tree

2 files changed

+80
-119
lines changed

2 files changed

+80
-119
lines changed

mergin/client_push.py

Lines changed: 5 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -320,39 +320,23 @@ def push_project_finalize(job):
320320
job.mp.log.info("--- push finished - new project version " + job.server_resp["version"])
321321

322322

323-
def _geodiff_changes_count(mp, diff_rel_path):
323+
def _geodiff_changes_count(mp: MerginProject, diff_rel_path: str):
324324
"""
325325
Best-effort: return number of changes in the .gpkg diff (int) or None.
326326
Never raises – diagnostics/logging must not fail.
327327
"""
328-
if not diff_rel_path:
329-
return None
328+
330329
try:
331330
diff_abs = mp.fpath_meta(diff_rel_path)
332-
except Exception:
331+
except FileNotFoundError:
333332
return None
334333

335334
try:
336-
from pygeodiff import GeoDiff
337-
335+
from pygeodiff import GeoDiff, GeoDiffLibError
338336
return GeoDiff().changes_count(diff_abs)
339-
except Exception:
340-
pass
341-
342-
try:
343-
import geodiff # optional fallback
344-
345-
if hasattr(geodiff, "changes_count"):
346-
try:
347-
return geodiff.changes_count(diff_abs)
348-
except Exception:
349-
return None
350-
except Exception:
337+
except GeoDiffLibError:
351338
return None
352339

353-
return None
354-
355-
356340
def push_project_cancel(job):
357341
"""
358342
To be called (from main thread) to cancel a job that has uploads in progress.

mergin/test/test_push_logging.py

Lines changed: 75 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -1,110 +1,87 @@
1+
from types import SimpleNamespace
2+
from pathlib import Path
13
import logging
24
import tempfile
3-
from pathlib import Path
4-
from types import SimpleNamespace
5-
65
import pytest
76

7+
from pygeodiff import GeoDiff
8+
from mergin.client_push import push_project_finalize, UploadJob
9+
from mergin.common import ClientError
810

911
@pytest.mark.parametrize("status_code", [502, 504])
10-
def test_push_finalize_logs_on_5xx_real_diff(caplog, status_code):
11-
# geodiff is required – if missing, skip the test gracefully
12-
pytest.importorskip("pygeodiff")
13-
from pygeodiff import GeoDiff
14-
15-
from mergin.client_push import push_project_finalize
16-
from mergin.common import ClientError
17-
18-
# --- exact paths according to your repo structure ---
12+
def test_push_finalize_logs_on_5xx_real_diff(caplog, status_code, tmp_path):
13+
# --- data ---
1914
data_dir = Path(__file__).resolve().parent / "test_data"
2015
base = data_dir / "base.gpkg"
2116
modified = data_dir / "inserted_1_A.gpkg"
22-
23-
# if something is missing, print the directory contents and FAIL
24-
if not base.exists() or not modified.exists():
25-
print("[DEBUG] data_dir:", data_dir)
26-
print("[DEBUG] data_dir.exists():", data_dir.exists())
27-
if data_dir.exists():
28-
print("[DEBUG] contents:", [p.name for p in sorted(data_dir.iterdir())])
29-
pytest.fail(f"Expected files are not available: base={base.exists()} inserted_1_A={modified.exists()}")
30-
31-
# --- create a real .diff (changeset) ---
32-
with tempfile.TemporaryDirectory(prefix="geodiff-") as tmpdir:
33-
tmpdir = Path(tmpdir)
34-
diff_path = tmpdir / "base_to_inserted_1_A.diff"
35-
36-
gd = GeoDiff()
37-
gd.create_changeset(str(base), str(modified), str(diff_path))
38-
diff_size = diff_path.stat().st_size
39-
file_size = modified.stat().st_size
40-
41-
# --- logger captured by caplog ---
42-
logger = logging.getLogger("mergin_test")
43-
logger.setLevel(logging.DEBUG)
44-
logger.propagate = True
45-
46-
# --- fake mc.post: /finish -> 5xx, /cancel -> ok ---
47-
def fake_post(url, *args, **kwargs):
48-
if "/finish/" in url:
49-
err = ClientError("Gateway error")
50-
setattr(err, "http_error", status_code)
51-
raise err
52-
if "/cancel/" in url:
17+
assert base.exists()
18+
assert modified.exists()
19+
20+
diff_path = tmp_path / "base_to_inserted_1_A.diff"
21+
GeoDiff().create_changeset(str(base), str(modified), str(diff_path))
22+
diff_size = diff_path.stat().st_size
23+
file_size = modified.stat().st_size
24+
25+
# --- logger ---
26+
logger = logging.getLogger("mergin_test")
27+
logger.setLevel(logging.DEBUG)
28+
logger.propagate = True
29+
caplog.set_level(logging.ERROR, logger="mergin_test")
30+
31+
# --- fake MP/MC len tam, kde treba ---
32+
class MP:
33+
def __init__(self, log): self.log = log
34+
def update_metadata(self, *a, **k): pass
35+
def apply_push_changes(self, *a, **k): pass
36+
def fpath_meta(self, rel): return str(diff_path) if rel == diff_path.name else rel
37+
38+
tx = "tx-1"
39+
40+
class MC:
41+
def post(self, url, *args, **kwargs):
42+
if url.endswith(f"/v1/project/push/finish/{tx}"):
43+
err = ClientError("Gateway error"); setattr(err, "http_error", status_code); raise err
44+
if url.endswith(f"/v1/project/push/cancel/{tx}"):
5345
return SimpleNamespace(msg="cancelled")
5446
return SimpleNamespace(msg="ok")
5547

56-
# --- fake future/executor (no exceptions) ---
57-
fake_future = SimpleNamespace(done=lambda: True, exception=lambda: None, running=lambda: False)
58-
fake_executor = SimpleNamespace(shutdown=lambda wait=True: None)
59-
60-
# mp.fpath_meta should resolve the relative diff path to an absolute path
61-
def fpath_meta(rel):
62-
return str(diff_path) if rel == diff_path.name else rel
63-
64-
# --- minimal job – only what finalize() uses ---
65-
job = SimpleNamespace(
66-
executor=fake_executor,
67-
futures=[fake_future],
68-
transferred_size=1234,
69-
total_size=1234,
70-
upload_queue_items=[1],
71-
transaction_id="tx-1",
72-
mp=SimpleNamespace(
73-
log=logger,
74-
update_metadata=lambda *a, **k: None,
75-
apply_push_changes=lambda *a, **k: None,
76-
fpath_meta=fpath_meta,
77-
),
78-
mc=SimpleNamespace(post=fake_post),
79-
changes={
80-
"added": [],
81-
"updated": [
82-
{
83-
"path": modified.name,
84-
"size": file_size,
85-
"diff": {"path": diff_path.name, "size": diff_size},
86-
"chunks": [1],
87-
}
88-
],
89-
"removed": [],
90-
},
91-
tmp_dir=SimpleNamespace(cleanup=lambda: None),
92-
)
93-
94-
# capture ERROR-level logs from "mergin_test"
95-
caplog.set_level(logging.ERROR, logger="mergin_test")
96-
97-
# --- call production logic (expecting 5xx) ---
98-
with pytest.raises(ClientError):
99-
push_project_finalize(job)
100-
101-
text = caplog.text
102-
103-
assert f"Push failed with HTTP error {status_code}" in text
104-
assert "Upload details:" in text
105-
assert "Files:" in text
106-
assert modified.name in text
107-
assert f"size={file_size}" in text
108-
assert f"diff_size={diff_size}" in text
109-
# helper may compute changes, or log changes=n/a – accept both
110-
assert ("changes=" in text) or ("changes=n/a" in text)
48+
tmp_dir = tempfile.TemporaryDirectory(prefix="python-api-client-test-")
49+
50+
# --- real UploadJob objekt ---
51+
job = UploadJob(
52+
project_path="u/p",
53+
changes={
54+
"added": [],
55+
"updated": [{
56+
"path": modified.name,
57+
"size": file_size,
58+
"diff": {"path": diff_path.name, "size": diff_size},
59+
"chunks": [1],
60+
}],
61+
"removed": [],
62+
},
63+
transaction_id=tx,
64+
mp=MP(logger),
65+
mc=MC(),
66+
tmp_dir=tmp_dir,
67+
)
68+
69+
# nastav to, čo finalize() očakáva
70+
job.total_size = 1234
71+
job.transferred_size = 1234
72+
job.upload_queue_items = [1] # len pre log „Upload details“
73+
job.executor = SimpleNamespace(shutdown=lambda wait=True: None)
74+
job.futures = [SimpleNamespace(done=lambda: True, exception=lambda: None, running=lambda: False)]
75+
job.server_resp = {"version": "n/a"} # aj tak sa 5xx vyhodí skôr
76+
77+
with pytest.raises(ClientError):
78+
push_project_finalize(job)
79+
80+
text = caplog.text
81+
assert f"Push failed with HTTP error {status_code}" in text
82+
assert "Upload details:" in text
83+
assert "Files:" in text
84+
assert modified.name in text
85+
assert f"size={file_size}" in text
86+
assert f"diff_size={diff_size}" in text
87+
assert ("changes=" in text) or ("changes=n/a" in text)

0 commit comments

Comments
 (0)