Files
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

188 lines
6.0 KiB
Python

import pytest
from aioresponses import aioresponses
from mirage.accessor.onedrive import OneDriveConfig
from mirage.core.onedrive._client import (GraphError, drive_base, graph_get,
graph_get_bytes, graph_list, headers,
item_url, split_path)
from mirage.types import PathSpec
from mirage.utils.key_prefix import mount_key
def test_split_path_strips_real_prefix():
p = PathSpec(resource_path=mount_key("/od/a.txt", "/od"),
virtual="/od/a.txt",
directory="/od/a.txt")
assert split_path(p) == ("/od", "a.txt")
def test_split_path_does_not_strip_sibling_prefix_match():
# `/data` must not be stripped from the sibling `/database.txt`; the
# boundary guard lives in mount_key, whose output split_path returns.
p = PathSpec(resource_path=mount_key("/database.txt", "/data"),
virtual="/database.txt",
directory="/database.txt")
assert split_path(p) == ("", "database.txt")
def test_headers_resolves_callable_token():
h = headers(OneDriveConfig(access_token=lambda: "live-token"))
assert h["Authorization"] == "Bearer live-token"
def _cfg(**kw) -> OneDriveConfig:
return OneDriveConfig(access_token="tok", **kw)
def test_drive_base_defaults_to_me_drive():
assert drive_base(_cfg()) == "https://graph.microsoft.com/v1.0/me/drive"
def test_drive_base_uses_drive_id():
base = drive_base(_cfg(drive_id="b!abc"))
assert base == "https://graph.microsoft.com/v1.0/drives/b!abc"
def test_drive_base_uses_site_default_drive():
base = drive_base(_cfg(site_id="site123"))
assert base == "https://graph.microsoft.com/v1.0/sites/site123/drive"
def test_item_url_root_children():
url = item_url(_cfg(), "/", action="/children")
assert url == "https://graph.microsoft.com/v1.0/me/drive/root/children"
def test_item_url_nested_metadata_no_action():
url = item_url(_cfg(), "/Docs/report.docx")
assert url == (
"https://graph.microsoft.com/v1.0/me/drive/root:/Docs/report.docx")
def test_item_url_nested_content():
url = item_url(_cfg(), "/Docs/report.docx", action="/content")
assert url == ("https://graph.microsoft.com/v1.0/me/drive"
"/root:/Docs/report.docx:/content")
def test_item_url_nested_children():
url = item_url(_cfg(), "/Docs", action="/children")
assert url == (
"https://graph.microsoft.com/v1.0/me/drive/root:/Docs:/children")
def test_item_url_applies_key_prefix():
url = item_url(_cfg(key_prefix="team/files"), "/a.txt", action="/content")
assert url == ("https://graph.microsoft.com/v1.0/me/drive"
"/root:/team/files/a.txt:/content")
def test_item_url_quotes_spaces():
url = item_url(_cfg(), "/My Folder/a b.txt")
assert url == ("https://graph.microsoft.com/v1.0/me/drive"
"/root:/My%20Folder/a%20b.txt")
def test_headers_carry_bearer_token():
h = headers(_cfg())
assert h["Authorization"] == "Bearer tok"
_ROOT = "https://graph.microsoft.com/v1.0/me/drive/root"
@pytest.mark.asyncio
async def test_graph_get_returns_parsed_json():
with aioresponses() as m:
m.get(_ROOT, payload={"id": "01ABC", "name": "root"})
result = await graph_get(_cfg(), _ROOT)
assert result["id"] == "01ABC"
@pytest.mark.asyncio
async def test_graph_get_raises_grapherror_with_status():
with aioresponses() as m:
m.get(_ROOT,
status=404,
payload={"error": {
"code": "itemNotFound",
"message": "nope"
}})
with pytest.raises(GraphError) as exc:
await graph_get(_cfg(), _ROOT)
assert exc.value.status == 404
assert exc.value.code == "itemNotFound"
@pytest.mark.asyncio
async def test_graph_list_follows_odata_nextlink():
page2 = _ROOT + "/children?$skiptoken=abc"
with aioresponses() as m:
m.get(_ROOT + "/children",
payload={
"value": [{
"id": "a"
}],
"@odata.nextLink": page2
})
m.get(page2, payload={"value": [{"id": "b"}]})
items = await graph_list(_cfg(), _ROOT + "/children")
assert [i["id"] for i in items] == ["a", "b"]
@pytest.mark.asyncio
async def test_graph_get_bytes_returns_raw_content():
url = _ROOT + ":/a.txt:/content"
with aioresponses() as m:
m.get(url, body=b"hello bytes")
data = await graph_get_bytes(_cfg(), url)
assert data == b"hello bytes"
@pytest.mark.asyncio
async def test_request_retries_on_429_then_succeeds():
with aioresponses() as m:
m.get(_ROOT, status=429, headers={"Retry-After": "0"})
m.get(_ROOT, payload={"id": "ok"})
result = await graph_get(_cfg(), _ROOT)
assert result["id"] == "ok"
@pytest.mark.asyncio
async def test_request_gives_up_after_max_retries():
with aioresponses() as m:
for _ in range(3):
m.get(_ROOT, status=429, headers={"Retry-After": "0"})
with pytest.raises(GraphError) as exc:
await graph_get(_cfg(max_retries=2), _ROOT)
assert exc.value.status == 429
@pytest.mark.asyncio
async def test_401_refreshes_callable_token_once_then_succeeds():
calls = {"n": 0}
def provider():
calls["n"] += 1
return "fresh" if calls["n"] > 1 else "stale"
with aioresponses() as m:
m.get(_ROOT,
status=401,
payload={"error": {
"code": "InvalidAuthenticationToken"
}})
m.get(_ROOT, payload={"id": "ok"})
result = await graph_get(OneDriveConfig(access_token=provider), _ROOT)
assert result["id"] == "ok"
assert calls["n"] == 2
@pytest.mark.asyncio
async def test_401_with_static_token_does_not_retry():
with aioresponses() as m:
m.get(_ROOT, status=401, payload={"error": {"code": "x"}})
with pytest.raises(GraphError) as exc:
await graph_get(_cfg(), _ROOT)
assert exc.value.status == 401