bcbd1bdb22
Test (Python) / test-python-gate (push) Blocked by required conditions
Test (TypeScript) / test-typescript-gate (push) Blocked by required conditions
CLI exit codes / cli-gate (push) Blocked by required conditions
Test (Install) / test-install-gate (push) Blocked by required conditions
Integ / integ-gate (push) Blocked by required conditions
CLI exit codes / Python CLI (push) Waiting to run
Integ / changes (push) Has been skipped
Test (Install) / python-minimal (3.11) (push) Waiting to run
Test (Install) / python-minimal (3.12) (push) Waiting to run
Test (Install) / python-extra (chroma, mirage.resource.chroma) (push) Waiting to run
Integ / integ-ts (push) Waiting to run
Integ / integ (push) Waiting to run
Test (Install) / python-extra (deepagents, mirage.agents.langchain) (push) Waiting to run
Integ / integ-database (push) Waiting to run
Test (Install) / python-extra (email, mirage.resource.email) (push) Waiting to run
Test (Install) / python-extra (hdf5, mirage.core.filetype.hdf5) (push) Waiting to run
Integ / integ-ssh (push) Waiting to run
Pre-commit / pre-commit (push) Failing after 1s
CLI exit codes / changes (push) Has been skipped
Test (Install) / changes (push) Has been skipped
CLI exit codes / TypeScript CLI (push) Waiting to run
CLI exit codes / Cross-language snapshot interop (push) Waiting to run
Test (Install) / python-extra (agno, mirage.agents.agno) (push) Waiting to run
Test (Install) / python-extra (databricks, mirage.resource.databricks_volume) (push) Waiting to run
Test (Python) / changes (push) Has been skipped
Integ / integ-database-ts (push) Waiting to run
Test (Install) / python-extra (fuse, mirage.fuse.mount) (push) Waiting to run
Integ / integ-data (push) Waiting to run
Test (Install) / python-extra (lancedb, mirage.resource.lancedb) (push) Waiting to run
Test (Python) / test (push) Waiting to run
Integ / integ-fuse (push) Waiting to run
Test (Install) / python-extra (langfuse, mirage.resource.langfuse) (push) Waiting to run
Test (Python) / import-isolation (deepagents, openai, mirage.agents.openai_agents) (push) Waiting to run
Test (Python) / audit (push) Waiting to run
Test (Install) / python-extra (hf, mirage.resource.hf_buckets) (push) Waiting to run
Integ / integ-ssh-ts (push) Waiting to run
Test (Install) / python-extra (mongodb, mirage.resource.mongodb) (push) Waiting to run
Test (Python) / import-isolation (deepagents, pydantic-ai, mirage.agents.pydantic_ai) (push) Waiting to run
Test (TypeScript) / changes (push) Has been skipped
Test (Install) / python-extra (nextcloud, mirage.resource.nextcloud) (push) Waiting to run
Test (Install) / python-extra (openai, mirage.agents.openai_agents) (push) Waiting to run
Test (Install) / python-extra (openhands, mirage.agents.openhands, 3.12) (push) Waiting to run
Test (Install) / python-extra (parquet, mirage.core.filetype.parquet) (push) Waiting to run
Test (TypeScript) / test (push) Waiting to run
Test (Install) / python-extra (pdf, mirage.core.filetype.pdf) (push) Waiting to run
Test (TypeScript) / python-fs-shim (push) Waiting to run
Test (Install) / python-extra (postgres, mirage.resource.postgres) (push) Waiting to run
Test (Install) / python-extra (pydantic-ai, mirage.agents.pydantic_ai) (push) Waiting to run
Test (Install) / python-extra (qdrant, mirage.resource.qdrant) (push) Waiting to run
Test (Install) / python-extra (redis, mirage.resource.redis) (push) Waiting to run
Test (Install) / python-extra (s3, mirage.resource.s3) (push) Waiting to run
Test (Install) / python-extra (ssh, mirage.resource.ssh) (push) Waiting to run
Test (Install) / ts-minimal (push) Waiting to run
179 lines
4.9 KiB
Python
179 lines
4.9 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 import MountMode, Workspace
|
|
from mirage.commands.config import command
|
|
from mirage.commands.spec import SPECS
|
|
from mirage.io.types import IOResult
|
|
from mirage.ops.registry import op
|
|
from mirage.resource.ram import RAMResource
|
|
|
|
|
|
@pytest.fixture
|
|
def ws():
|
|
return Workspace({"/data": RAMResource()}, mode=MountMode.WRITE)
|
|
|
|
|
|
@pytest.fixture
|
|
def ws_two_mounts():
|
|
return Workspace({
|
|
"/a": RAMResource(),
|
|
"/b": RAMResource(),
|
|
},
|
|
mode=MountMode.WRITE)
|
|
|
|
|
|
def test_ws_mounts_returns_all(ws):
|
|
mounts = ws.mounts()
|
|
prefixes = [m.prefix for m in mounts]
|
|
assert "/data/" in prefixes
|
|
|
|
|
|
def test_ws_mount_by_prefix(ws):
|
|
m = ws.mount("/data/")
|
|
assert m.prefix == "/data/"
|
|
|
|
|
|
def test_commands_introspection(ws):
|
|
m = ws.mount("/data/")
|
|
cmds = m.commands()
|
|
assert isinstance(cmds, dict)
|
|
assert "cat" in cmds
|
|
assert None in cmds["cat"]
|
|
|
|
|
|
def test_commands_has_filetype_variants(ws):
|
|
m = ws.mount("/data/")
|
|
cmds = m.commands()
|
|
assert len(cmds.get("cat", [])) > 1
|
|
|
|
|
|
def test_registered_ops_introspection(ws):
|
|
m = ws.mount("/data/")
|
|
ops = m.registered_ops()
|
|
assert isinstance(ops, dict)
|
|
assert "read" in ops
|
|
assert "stat" in ops
|
|
|
|
|
|
def test_register_fns_adds_command(ws):
|
|
|
|
@command("test_custom", resource="ram", spec=SPECS["cat"])
|
|
async def custom(accessor, paths, *texts, **kw):
|
|
return b"custom", IOResult()
|
|
|
|
m = ws.mount("/data/")
|
|
assert "test_custom" not in m.commands()
|
|
m.register_fns([custom])
|
|
assert "test_custom" in m.commands()
|
|
|
|
|
|
def test_register_fns_adds_op(ws):
|
|
|
|
@op("test_custom_op", resource="ram")
|
|
async def custom_op(accessor, scope, **kwargs):
|
|
return b"hello"
|
|
|
|
m = ws.mount("/data/")
|
|
assert "test_custom_op" not in m.registered_ops()
|
|
m.register_fns([custom_op])
|
|
assert "test_custom_op" in m.registered_ops()
|
|
|
|
|
|
def test_unregister_removes_command(ws):
|
|
m = ws.mount("/data/")
|
|
assert "rm" in m.commands()
|
|
m.unregister(["rm"])
|
|
assert "rm" not in m.commands()
|
|
|
|
|
|
def test_unregister_removes_all_filetypes(ws):
|
|
m = ws.mount("/data/")
|
|
cmds = m.commands()
|
|
assert len(cmds.get("cat", [])) > 1
|
|
m.unregister(["cat"])
|
|
assert "cat" not in m.commands()
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_unregister_then_register_works(ws):
|
|
m = ws.mount("/data/")
|
|
m.unregister(["cat"])
|
|
assert "cat" not in m.commands()
|
|
|
|
@command("cat", resource="ram", spec=SPECS["cat"])
|
|
async def custom_cat(accessor, paths, *texts, **kw):
|
|
return b"custom cat output", IOResult()
|
|
|
|
m.register_fns([custom_cat])
|
|
assert "cat" in m.commands()
|
|
await ws.execute('echo hello | tee /data/hello.txt')
|
|
result = await ws.execute("cat /data/hello.txt")
|
|
assert result.exit_code == 0
|
|
assert b"custom cat output" in result.stdout
|
|
|
|
|
|
def test_register_isolated_per_mount(ws_two_mounts):
|
|
ma = ws_two_mounts.mount("/a/")
|
|
mb = ws_two_mounts.mount("/b/")
|
|
ma.unregister(["rm"])
|
|
assert "rm" not in ma.commands()
|
|
assert "rm" in mb.commands()
|
|
|
|
|
|
def test_register_fns_isolated_per_mount(ws_two_mounts):
|
|
|
|
@command("only_on_a", resource="ram", spec=SPECS["cat"])
|
|
async def only_a(accessor, paths, *texts, **kw):
|
|
return b"a", IOResult()
|
|
|
|
ws_two_mounts.mount("/a/").register_fns([only_a])
|
|
assert "only_on_a" in ws_two_mounts.mount("/a/").commands()
|
|
assert "only_on_a" not in ws_two_mounts.mount("/b/").commands()
|
|
|
|
|
|
def test_register_fns_wrong_resource_raises(ws):
|
|
|
|
@command("s3_only", resource="s3", spec=SPECS["cat"])
|
|
async def s3_cmd(accessor, paths, *texts, **kw):
|
|
return b"s3", IOResult()
|
|
|
|
m = ws.mount("/data/")
|
|
with pytest.raises(ValueError, match=r"'s3'"):
|
|
m.register_fns([s3_cmd])
|
|
|
|
|
|
def test_register_fns_wrong_resource_op_raises(ws):
|
|
|
|
@op("s3_read", resource="s3")
|
|
async def s3_op(accessor, scope, **kwargs):
|
|
return b"s3"
|
|
|
|
m = ws.mount("/data/")
|
|
with pytest.raises(ValueError, match=r"'s3'"):
|
|
m.register_fns([s3_op])
|
|
|
|
|
|
def test_register_fns_multi_resource_filters_to_matching(ws):
|
|
|
|
@command("multi", resource=["ram", "s3"], spec=SPECS["cat"])
|
|
async def multi(accessor, paths, *texts, **kw):
|
|
return b"multi", IOResult()
|
|
|
|
m = ws.mount("/data/")
|
|
m.register_fns([multi])
|
|
assert "multi" in m.commands()
|