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

390 lines
12 KiB
Python

# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
import pytest
from mirage.cache.file.ram import RAMFileCacheStore
from mirage.commands.registry import command
from mirage.commands.spec.types import CommandSpec
from mirage.io.types import IOResult
from mirage.resource.base import BaseResource
from mirage.resource.ram import RAMResource
from mirage.resource.ssh import SSHConfig, SSHResource
from mirage.types import MountMode, PathSpec
from mirage.workspace.mount import MountCommandUnsupported, MountRegistry
# ── mount_for ──────────────────────────────────
def test_mount_for_exact(registry):
mount = registry.mount_for("/data/file.txt")
assert mount.prefix == "/data/"
def test_mount_for_nested_path(registry):
mount = registry.mount_for("/data/sub/deep/file.txt")
assert mount.prefix == "/data/"
def test_mount_for_prefix_root(registry):
mount = registry.mount_for("/data")
assert mount.prefix == "/data/"
def test_mount_for_no_match(registry):
with pytest.raises(ValueError, match="no mount"):
registry.mount_for("/unknown/file.txt")
def test_mount_for_dev_default(registry):
mount = registry.mount_for("/dev/null")
assert mount.prefix == "/dev/"
# ── longest prefix match ──────────────────────
def test_nested_prefix_longest_match(nested_registry):
mount = nested_registry.mount_for("/data/sub/deep.txt")
assert mount.prefix == "/data/sub/"
def test_nested_prefix_outer(nested_registry):
mount = nested_registry.mount_for("/data/file.txt")
assert mount.prefix == "/data/"
# ── descendant_mounts ──────────────────────────
def test_descendant_mounts_under_root(multi_registry):
descs = multi_registry.descendant_mounts("/")
prefixes = [m.prefix for m in descs]
# /dev/ is auto-mounted by the registry; ours are /s3/, /disk/, /ram/.
assert "/disk/" in prefixes
assert "/ram/" in prefixes
assert "/s3/" in prefixes
def test_descendant_mounts_under_root_sorted(multi_registry):
descs = multi_registry.descendant_mounts("/")
prefixes = [m.prefix for m in descs]
assert prefixes == sorted(prefixes)
def test_descendant_mounts_at_a_mount_root_is_empty(registry):
# /data/ is a mount; nothing is below it.
assert registry.descendant_mounts("/data") == []
assert registry.descendant_mounts("/data/") == []
def test_descendant_mounts_inside_a_mount_is_empty(registry):
assert registry.descendant_mounts("/data/sub") == []
def test_descendant_mounts_nested(nested_registry):
# Top: /data/, /data/sub/.
descs = nested_registry.descendant_mounts("/")
prefixes = [m.prefix for m in descs]
assert "/data/" in prefixes
assert "/data/sub/" in prefixes
# Below /data/, the only descendant is /data/sub/.
descs2 = nested_registry.descendant_mounts("/data")
assert [m.prefix for m in descs2] == ["/data/sub/"]
# /data/ as a mount root returns its own children only (excludes self).
assert "/data/" not in [m.prefix for m in descs2]
def test_descendant_mounts_excludes_self(nested_registry):
descs = nested_registry.descendant_mounts("/data")
assert all(m.prefix != "/data/" for m in descs)
def test_descendant_mounts_unrelated_path(multi_registry):
# A path in /s3/ has no mount nested below it.
assert multi_registry.descendant_mounts("/s3/data") == []
# ── resolve ────────────────────────────────────
def test_resolve_strips_prefix(registry):
prov, pp, mode = registry.resolve("/data/hello.txt")
assert pp == "/hello.txt"
assert prov.name == "ram"
def test_resolve_root_path(registry):
_, pp, _ = registry.resolve("/data")
assert pp == "/"
def test_resolve_trailing_slash(registry):
_, pp, _ = registry.resolve("/data/sub/")
assert pp.endswith("/")
def test_resolve_mode(registry):
_, _, mode = registry.resolve("/data/file.txt")
assert mode == MountMode.WRITE
def test_resolve_no_match(registry):
with pytest.raises(ValueError):
registry.resolve("/unknown/path")
# ── multi mount (s3 + disk + ram) ──────────────
def test_multi_mount_resolves_s3(multi_registry):
mount = multi_registry.mount_for("/s3/data/report.csv")
assert mount.prefix == "/s3/"
assert mount.resource.name == "s3"
def test_multi_mount_resolves_disk(multi_registry):
mount = multi_registry.mount_for("/disk/readme.txt")
assert mount.prefix == "/disk/"
assert mount.resource.name == "disk"
def test_multi_mount_resolves_ram(multi_registry):
mount = multi_registry.mount_for("/ram/hello.txt")
assert mount.prefix == "/ram/"
assert mount.resource.name == "ram"
def test_multi_mount_modes(multi_registry):
_, _, s3_mode = multi_registry.resolve("/s3/file.txt")
_, _, disk_mode = multi_registry.resolve("/disk/file.txt")
_, _, ram_mode = multi_registry.resolve("/ram/file.txt")
assert s3_mode == MountMode.READ
assert disk_mode == MountMode.WRITE
assert ram_mode == MountMode.WRITE
def test_multi_mount_resource_paths(multi_registry):
_, pp_s3, _ = multi_registry.resolve("/s3/data/report.csv")
_, pp_disk, _ = multi_registry.resolve("/disk/readme.txt")
_, pp_ram, _ = multi_registry.resolve("/ram/hello.txt")
assert pp_s3 == "/data/report.csv"
assert pp_disk == "/readme.txt"
assert pp_ram == "/hello.txt"
# ── mount ──────────────────────────────────────
def test_mount_returns_mount_object():
reg = MountRegistry()
p = RAMResource()
m = reg.mount("/test/", p, MountMode.READ)
assert m.prefix == "/test/"
assert m.resource is p
def test_mount_normalizes_prefix():
reg = MountRegistry()
m = reg.mount("/test/", RAMResource(), MountMode.READ)
assert m.prefix == "/test/"
def test_mount_duplicate_raises(registry):
with pytest.raises(ValueError, match="duplicate"):
registry.mount("/data/", RAMResource())
# ── mounts listing ─────────────────────────────
def test_mounts_returns_all(multi_registry):
prefixes = {m.prefix for m in multi_registry.mounts()}
assert "/s3/" in prefixes
assert "/disk/" in prefixes
assert "/ram/" in prefixes
assert "/dev/" in prefixes
def test_mounts_count(multi_registry):
assert len(multi_registry.mounts()) == 4
# ── group_by_mount ─────────────────────────────
def test_group_by_mount(multi_registry):
groups = multi_registry.group_by_mount(
["/s3/a.txt", "/s3/b.txt", "/disk/c.txt"])
assert len(groups) == 2
s3_group = [g for g in groups if g[0].prefix == "/s3/"][0]
assert len(s3_group[1]) == 2
disk_group = [g for g in groups if g[0].prefix == "/disk/"][0]
assert len(disk_group[1]) == 1
def test_group_by_mount_single(multi_registry):
groups = multi_registry.group_by_mount(["/ram/hello.txt"])
assert len(groups) == 1
# ── get_resource_type ──────────────────────────
def test_get_resource_type_s3(multi_registry):
assert multi_registry.get_resource_type("/s3/file.txt") == "s3"
def test_get_resource_type_disk(multi_registry):
assert multi_registry.get_resource_type("/disk/file.txt") == "disk"
def test_get_resource_type_ram(multi_registry):
assert multi_registry.get_resource_type("/ram/file.txt") == "ram"
def test_get_resource_type_none(multi_registry):
assert multi_registry.get_resource_type(None) is None
def test_get_resource_type_unknown(multi_registry):
assert multi_registry.get_resource_type("/unknown/f") is None
# ── find_resource_by_name ──────────────────────
def test_find_resource_s3(multi_registry):
prov = multi_registry.find_resource_by_name("s3")
assert prov is not None
assert prov.name == "s3"
def test_find_resource_disk(multi_registry):
prov = multi_registry.find_resource_by_name("disk")
assert prov is not None
assert prov.name == "disk"
def test_find_resource_ram(multi_registry):
prov = multi_registry.find_resource_by_name("ram")
assert prov is not None
def test_find_resource_none(multi_registry):
assert multi_registry.find_resource_by_name(None) is None
def test_find_resource_missing(multi_registry):
assert multi_registry.find_resource_by_name("nonexistent") is None
# ── mount_for_command ──────────────────────────
def test_mount_for_command_cat(registry):
mount = registry.mount_for_command("cat")
assert mount is not None
def test_mount_for_command_nonexistent(registry):
assert registry.mount_for_command("nonexistent_cmd") is None
def test_mount_for_command_grep(multi_registry):
mount = multi_registry.mount_for_command("grep")
assert mount is not None
# ── resolve_mount cache redirect ───────────────
def _remote_registry_with_cache():
reg = MountRegistry()
reg.mount("/ssh/", SSHResource(SSHConfig(host="example", root="/srv")),
MountMode.WRITE)
cache = RAMFileCacheStore()
reg.attach_file_cache(cache)
return reg, cache
@pytest.mark.asyncio
async def test_resolve_mount_keeps_cached_read_on_real_mount():
# Warm reads are served in place by with_read_cache, so a cached
# read-only command stays on its real mount (keeping its safeguards and
# custom handlers) instead of being redirected to the cache mount.
reg, cache = _remote_registry_with_cache()
await cache.set("/ssh/a.txt", b"hi")
scope = PathSpec(resource_path="ssh/a.txt",
virtual="/ssh/a.txt",
directory="/ssh",
resolved=True)
mount = await reg.resolve_mount("cat", [scope], "/ssh")
assert mount.prefix == "/ssh/"
@pytest.mark.asyncio
async def test_resolve_mount_keeps_cached_write_on_remote():
reg, cache = _remote_registry_with_cache()
await cache.set("/ssh/a.txt", b"hi")
scope = PathSpec(resource_path="ssh/a.txt",
virtual="/ssh/a.txt",
directory="/ssh",
resolved=True)
mount = await reg.resolve_mount("rm", [scope], "/ssh")
assert mount.prefix == "/ssh/"
class _LimitedResource(BaseResource):
name = "limited"
class _FallbackResource(BaseResource):
name = "fallback"
@command("fallback-only", resource="fallback", spec=CommandSpec())
async def _fallback_only(_store, paths, *texts, **kw):
return b"fallback", IOResult()
def _path_bound_registry_with_default():
reg = MountRegistry()
reg.mount("/limited/", _LimitedResource(), MountMode.WRITE)
fallback = _FallbackResource()
fallback.register(_fallback_only)
reg.mount("/", fallback, MountMode.WRITE)
return reg
@pytest.mark.asyncio
async def test_resolve_mount_rejects_path_bound_unsupported_command():
reg = _path_bound_registry_with_default()
scope = PathSpec(resource_path="limited/file.txt",
virtual="/limited/file.txt",
directory="/limited",
resolved=True)
with pytest.raises(
MountCommandUnsupported,
match="fallback-only: /limited/file.txt: Operation not supported"):
await reg.resolve_mount("fallback-only", [scope], "/limited")
@pytest.mark.asyncio
async def test_resolve_mount_allows_default_without_path_binding():
reg = _path_bound_registry_with_default()
mount = await reg.resolve_mount("fallback-only", [], "/limited")
assert mount is not None
assert mount.prefix == "/"