Files
cowork-local/tests/test_cloud_workspace_sync.py
T
13e2c22067
CI / test (push) Canceled after 0s
Fix/qa defects df002 df011 (#9)
## Summary

What changed and why?

## Change Type

- [ ] Cowork feature
- [ ] Bug fix
- [ ] Core AI contribution
- [ ] Test / hardening
- [ ] Performance
- [ ] Documentation

## Related Work

Cowork Task:

Core Repo: http://34.143.229.138/gitea-admin/fsg-ai-core-assets

Core AI Issue:

Core Task:

Related PR:

## Scope

What is intentionally included?

What is intentionally NOT included?

## Validation

- [ ] Unit tests
- [ ] Integration tests
- [ ] Manual verification
- [ ] Regression check

Commands / evidence:

## Security Impact

Permission / credential / network / customer data impact:

## Compatibility

- [ ] No breaking change
- [ ] Breaking change documented

## Reviewer Notes

Anything Cowork reviewers should pay attention to.

---------

Co-authored-by: thanhnv <thanhnv.ip@gmail.com>
Co-authored-by: Vu Dam Tuan <vudt15@fpt.com>
Reviewed-on: #9
2026-09-09 16:19:31 +00:00

133 lines
4.5 KiB
Python

"""DF-007 — core/cloud_workspace_sync.py: mirror a cloud folder to/from a
local directory. All Graph calls are faked (monkeypatch on the ``graph``
module the sync module imports) — no network."""
from __future__ import annotations
from pathlib import Path
import pytest
from cowork_local.core import cloud_workspace_sync as sync
from cowork_local.core import ms365_graph as graph
def _fake_tree():
"""root/
a.txt
sub/
b.txt
"""
files = {"a.txt": b"hello", "sub/b.txt": b"world"}
listing = {
"": [{"name": "a.txt"}, {"name": "sub", "folder": {}}],
"sub": [{"name": "b.txt"}],
}
return files, listing
def test_download_folder_mirrors_tree(tmp_path: Path, monkeypatch) -> None:
files, listing = _fake_tree()
def fake_list_onedrive_files(token, path=""):
return listing.get(path, [])
def fake_download_bytes(token, path):
return files[path]
monkeypatch.setattr(graph, "list_onedrive_files", fake_list_onedrive_files)
monkeypatch.setattr(graph, "download_onedrive_file_bytes", fake_download_bytes)
local_dir = tmp_path / "mirror"
report = sync.download_folder("tok", {"provider": "onedrive", "remote_path": ""}, local_dir)
assert report.transferred == 2
assert report.errors == []
assert (local_dir / "a.txt").read_bytes() == b"hello"
assert (local_dir / "sub" / "b.txt").read_bytes() == b"world"
def test_download_folder_collects_errors_without_raising(tmp_path: Path, monkeypatch) -> None:
def fake_list_onedrive_files(token, path=""):
raise graph.Ms365GraphError("boom")
monkeypatch.setattr(graph, "list_onedrive_files", fake_list_onedrive_files)
local_dir = tmp_path / "mirror"
report = sync.download_folder("tok", {"provider": "onedrive", "remote_path": ""}, local_dir)
assert report.transferred == 0
assert len(report.errors) == 1
assert "boom" in report.errors[0]
def test_upload_folder_pushes_every_file(tmp_path: Path, monkeypatch) -> None:
local_dir = tmp_path / "mirror"
(local_dir / "sub").mkdir(parents=True)
(local_dir / "a.txt").write_bytes(b"hello")
(local_dir / "sub" / "b.txt").write_bytes(b"world")
uploaded = {}
def fake_upload_bytes(token, path, data):
uploaded[path] = data
return {}
monkeypatch.setattr(graph, "upload_onedrive_file_bytes", fake_upload_bytes)
report = sync.upload_folder("tok", {"provider": "onedrive", "remote_path": "work"}, local_dir)
assert report.transferred == 2
assert uploaded == {"work/a.txt": b"hello", "work/sub/b.txt": b"world"}
def test_upload_folder_reports_files_over_the_simple_upload_limit(tmp_path: Path, monkeypatch) -> None:
local_dir = tmp_path / "mirror"
local_dir.mkdir()
(local_dir / "big.bin").write_bytes(b"x")
def fake_upload_bytes(token, path, data):
raise graph.Ms365GraphError("File too large for simple upload (huge > 4 bytes)")
monkeypatch.setattr(graph, "upload_onedrive_file_bytes", fake_upload_bytes)
report = sync.upload_folder("tok", {"provider": "onedrive", "remote_path": ""}, local_dir)
assert report.transferred == 0
assert report.skipped_too_large == ["big.bin"]
assert report.errors == []
def test_upload_size_guard_rejects_before_any_request(monkeypatch) -> None:
huge = b"x" * (graph.MAX_SIMPLE_UPLOAD_BYTES + 1)
def fail_if_called(*a, **k): # pragma: no cover - must not be reached
raise AssertionError("_request should not be called for an oversized upload")
monkeypatch.setattr(graph, "_request", fail_if_called)
with pytest.raises(graph.Ms365GraphError, match="too large"):
graph.upload_onedrive_file_bytes("tok", "a.bin", huge)
def test_sharepoint_provider_uses_site_scoped_calls(tmp_path: Path, monkeypatch) -> None:
seen = {}
def fake_list_sharepoint_files(token, site_id, path=""):
seen["list_site_id"] = site_id
return [{"name": "a.txt"}] if path == "" else []
def fake_download_sharepoint_bytes(token, site_id, path):
seen["download_site_id"] = site_id
return b"hi"
monkeypatch.setattr(graph, "list_sharepoint_files", fake_list_sharepoint_files)
monkeypatch.setattr(graph, "download_sharepoint_file_bytes", fake_download_sharepoint_bytes)
local_dir = tmp_path / "mirror"
cloud_source = {"provider": "sharepoint", "site_id": "site-123", "remote_path": ""}
report = sync.download_folder("tok", cloud_source, local_dir)
assert report.transferred == 1
assert seen["list_site_id"] == "site-123"
assert seen["download_site_id"] == "site-123"