Files
strukto-ai--mirage/python/tests/core/sharepoint/test_client.py
T
wehub-resource-sync bcbd1bdb22
Integ / changes (push) Has been skipped
Pre-commit / pre-commit (push) Failing after 1s
CLI exit codes / changes (push) Has been skipped
Test (Install) / changes (push) Has been skipped
Test (Python) / changes (push) Has been skipped
Test (TypeScript) / changes (push) Has been skipped
CLI exit codes / cli-gate (push) Has been cancelled
Test (Install) / test-install-gate (push) Has been cancelled
Integ / integ-gate (push) Has been cancelled
Test (Python) / test-python-gate (push) Has been cancelled
Test (TypeScript) / test-typescript-gate (push) Has been cancelled
Test (Install) / python-minimal (3.12) (push) Has been cancelled
Test (Install) / python-minimal (3.11) (push) Has been cancelled
Test (Install) / python-extra (agno, mirage.agents.agno) (push) Has been cancelled
Test (Install) / python-extra (chroma, mirage.resource.chroma) (push) Has been cancelled
Test (Install) / python-extra (pdf, mirage.core.filetype.pdf) (push) Has been cancelled
Integ / integ (push) Has been cancelled
Integ / integ-database (push) Has been cancelled
Integ / integ-database-ts (push) Has been cancelled
Integ / integ-data (push) Has been cancelled
Integ / integ-ssh (push) Has been cancelled
Integ / integ-ssh-ts (push) Has been cancelled
Test (Python) / audit (push) Has been cancelled
Test (TypeScript) / test (push) Has been cancelled
Test (TypeScript) / python-fs-shim (push) Has been cancelled
CLI exit codes / Python CLI (push) Has been cancelled
CLI exit codes / TypeScript CLI (push) Has been cancelled
CLI exit codes / Cross-language snapshot interop (push) Has been cancelled
Test (Python) / test (push) Has been cancelled
Test (Python) / import-isolation (deepagents, openai, mirage.agents.openai_agents) (push) Has been cancelled
Test (Python) / import-isolation (deepagents, pydantic-ai, mirage.agents.pydantic_ai) (push) Has been cancelled
Integ / integ-ts (push) Has been cancelled
Integ / integ-fuse (push) Has been cancelled
Test (Install) / python-extra (databricks, mirage.resource.databricks_volume) (push) Has been cancelled
Test (Install) / python-extra (deepagents, mirage.agents.langchain) (push) Has been cancelled
Test (Install) / python-extra (email, mirage.resource.email) (push) Has been cancelled
Test (Install) / python-extra (fuse, mirage.fuse.mount) (push) Has been cancelled
Test (Install) / python-extra (hdf5, mirage.core.filetype.hdf5) (push) Has been cancelled
Test (Install) / python-extra (hf, mirage.resource.hf_buckets) (push) Has been cancelled
Test (Install) / python-extra (lancedb, mirage.resource.lancedb) (push) Has been cancelled
Test (Install) / python-extra (langfuse, mirage.resource.langfuse) (push) Has been cancelled
Test (Install) / python-extra (mongodb, mirage.resource.mongodb) (push) Has been cancelled
Test (Install) / python-extra (nextcloud, mirage.resource.nextcloud) (push) Has been cancelled
Test (Install) / python-extra (openai, mirage.agents.openai_agents) (push) Has been cancelled
Test (Install) / python-extra (openhands, mirage.agents.openhands, 3.12) (push) Has been cancelled
Test (Install) / python-extra (parquet, mirage.core.filetype.parquet) (push) Has been cancelled
Test (Install) / python-extra (postgres, mirage.resource.postgres) (push) Has been cancelled
Test (Install) / python-extra (pydantic-ai, mirage.agents.pydantic_ai) (push) Has been cancelled
Test (Install) / python-extra (qdrant, mirage.resource.qdrant) (push) Has been cancelled
Test (Install) / python-extra (redis, mirage.resource.redis) (push) Has been cancelled
Test (Install) / python-extra (s3, mirage.resource.s3) (push) Has been cancelled
Test (Install) / python-extra (ssh, mirage.resource.ssh) (push) Has been cancelled
Test (Install) / ts-minimal (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:30:44 +08:00

148 lines
4.4 KiB
Python

import pytest
from aioresponses import aioresponses
from mirage.accessor.sharepoint import SharePointConfig
from mirage.core.sharepoint._client import (GraphError, drive_ref_path,
graph_get, graph_get_bytes,
graph_list, headers, item_url)
def _cfg(**kw) -> SharePointConfig:
return SharePointConfig(access_token="tok", **kw)
_BASE = "https://graph.microsoft.com/v1.0"
_DRIVE = "b!drive123"
def test_headers_carry_bearer_token():
h = headers(_cfg())
assert h["Authorization"] == "Bearer tok"
def test_headers_resolves_callable_token():
h = headers(SharePointConfig(access_token=lambda: "live"))
assert h["Authorization"] == "Bearer live"
def test_item_url_root_no_path():
url = item_url(_DRIVE, "/")
assert url == f"{_BASE}/drives/{_DRIVE}/root"
def test_item_url_root_children():
url = item_url(_DRIVE, "/", action="/children")
assert url == f"{_BASE}/drives/{_DRIVE}/root/children"
def test_item_url_nested_file():
url = item_url(_DRIVE, "/docs/report.docx")
assert url == f"{_BASE}/drives/{_DRIVE}/root:/docs/report.docx"
def test_item_url_nested_content():
url = item_url(_DRIVE, "/docs/report.docx", action="/content")
assert url == f"{_BASE}/drives/{_DRIVE}/root:/docs/report.docx:/content"
def test_item_url_nested_children():
url = item_url(_DRIVE, "/folder", action="/children")
assert url == f"{_BASE}/drives/{_DRIVE}/root:/folder:/children"
def test_item_url_quotes_spaces():
url = item_url(_DRIVE, "/My Folder/a b.txt")
assert url == f"{_BASE}/drives/{_DRIVE}/root:/My%20Folder/a%20b.txt"
def test_drive_ref_path_root():
assert drive_ref_path(_DRIVE) == f"/drives/{_DRIVE}/root:"
def test_drive_ref_path_folder():
p = drive_ref_path(_DRIVE, "sub/dir")
assert p == f"/drives/{_DRIVE}/root:/sub/dir"
@pytest.mark.asyncio
async def test_graph_get_returns_parsed_json():
url = f"{_BASE}/drives/{_DRIVE}/root"
with aioresponses() as m:
m.get(url, payload={"id": "01ABC", "name": "root"})
result = await graph_get(_cfg(), url)
assert result["id"] == "01ABC"
@pytest.mark.asyncio
async def test_graph_get_raises_grapherror():
url = f"{_BASE}/drives/{_DRIVE}/root"
with aioresponses() as m:
m.get(url,
status=404,
payload={"error": {
"code": "itemNotFound",
"message": "no"
}})
with pytest.raises(GraphError) as exc:
await graph_get(_cfg(), url)
assert exc.value.status == 404
assert exc.value.code == "itemNotFound"
@pytest.mark.asyncio
async def test_graph_list_follows_nextlink():
url = f"{_BASE}/drives/{_DRIVE}/root/children"
page2 = url + "?$skiptoken=x"
with aioresponses() as m:
m.get(url, payload={"value": [{"id": "a"}], "@odata.nextLink": page2})
m.get(page2, payload={"value": [{"id": "b"}]})
items = await graph_list(_cfg(), url)
assert [i["id"] for i in items] == ["a", "b"]
@pytest.mark.asyncio
async def test_graph_get_bytes_returns_raw():
url = f"{_BASE}/drives/{_DRIVE}/root:/a.txt:/content"
with aioresponses() as m:
m.get(url, body=b"hello")
data = await graph_get_bytes(_cfg(), url)
assert data == b"hello"
@pytest.mark.asyncio
async def test_retry_on_429():
url = f"{_BASE}/drives/{_DRIVE}/root"
with aioresponses() as m:
m.get(url, status=429, headers={"Retry-After": "0"})
m.get(url, payload={"id": "ok"})
result = await graph_get(_cfg(), url)
assert result["id"] == "ok"
@pytest.mark.asyncio
async def test_gives_up_after_max_retries():
url = f"{_BASE}/drives/{_DRIVE}/root"
with aioresponses() as m:
for _ in range(3):
m.get(url, status=429, headers={"Retry-After": "0"})
with pytest.raises(GraphError) as exc:
await graph_get(_cfg(max_retries=2), url)
assert exc.value.status == 429
@pytest.mark.asyncio
async def test_401_refreshes_callable_token():
url = f"{_BASE}/drives/{_DRIVE}/root"
calls = {"n": 0}
def provider():
calls["n"] += 1
return "fresh" if calls["n"] > 1 else "stale"
with aioresponses() as m:
m.get(url, status=401, payload={"error": {"code": "x"}})
m.get(url, payload={"id": "ok"})
result = await graph_get(SharePointConfig(access_token=provider), url)
assert result["id"] == "ok"
assert calls["n"] == 2