from contextlib import asynccontextmanager
import httpx
import pytest
from basic_memory.cli.commands.cloud.upload import upload_path
@pytest.mark.asyncio
async def test_upload_path_dry_run_respects_gitignore_and_bmignore(config_home, tmp_path, capsys):
root = tmp_path / "proj"
root.mkdir()
# Create a .gitignore that ignores one file
(root / ".gitignore").write_text("ignored.md\n", encoding="utf-8")
# Create files
(root / "keep.md").write_text("keep", encoding="utf-8")
(root / "ignored.md").write_text("ignored", encoding="utf-8")
ok = await upload_path(root, "proj", verbose=True, use_gitignore=True, dry_run=True)
assert ok is True
out = capsys.readouterr().out
# Verbose mode prints ignored files in the scan phase, but they must not appear
# in the final "would be uploaded" list.
assert "[INCLUDE] keep.md" in out or "keep.md" in out
assert "[IGNORED] ignored.md" in out
assert "Files that would be uploaded:" in out
assert " keep.md (" in out
assert " ignored.md (" not in out
@pytest.mark.asyncio
async def test_upload_path_non_dry_puts_files_and_skips_archives(config_home, tmp_path):
root = tmp_path / "proj"
root.mkdir()
(root / "keep.md").write_text("keep", encoding="utf-8")
(root / "archive.zip").write_bytes(b"zipbytes")
seen = {"puts": []}
async def handler(request: httpx.Request) -> httpx.Response:
# Expect PUT to the webdav path
assert request.method == "PUT"
seen["puts"].append(request.url.path)
# Must have mtime header
assert request.headers.get("x-oc-mtime")
return httpx.Response(201, text="Created")
transport = httpx.MockTransport(handler)
@asynccontextmanager
async def client_cm_factory():
async with httpx.AsyncClient(transport=transport, base_url="https://cloud.example.test") as client:
yield client
ok = await upload_path(
root,
"proj",
verbose=False,
use_gitignore=False,
dry_run=False,
client_cm_factory=client_cm_factory,
)
assert ok is True
# Only keep.md uploaded; archive skipped
assert "/webdav/proj/keep.md" in seen["puts"]
assert all("archive.zip" not in p for p in seen["puts"])