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
187 lines
7.4 KiB
Python
187 lines
7.4 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 asyncio
|
|
import os
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
sys.path.insert(0, str(Path(__file__).parent))
|
|
|
|
from qdrant_client import AsyncQdrantClient, models # noqa: E402
|
|
|
|
from mirage import MountMode, Workspace # noqa: E402
|
|
from mirage.resource.qdrant import QdrantConfig, QdrantResource # noqa: E402
|
|
|
|
QDRANT_URL = os.environ.get("QDRANT_URL")
|
|
QDRANT_API_KEY = os.environ.get("QDRANT_API_KEY")
|
|
QDRANT_HOST = os.environ.get("QDRANT_HOST", "localhost")
|
|
QDRANT_PORT = int(os.environ.get("QDRANT_PORT", "6333"))
|
|
EMBED_DIM = 8
|
|
COLLECTION = "mirage_integ"
|
|
MOUNT = "/db/"
|
|
|
|
ROWS = [
|
|
(1, "cat", "big", "a big orange cat"),
|
|
(2, "cat", "small", "a small grey cat"),
|
|
(3, "dog", "big", "a big brown dog"),
|
|
(4, "dog", "small", "a small white dog"),
|
|
]
|
|
|
|
CASES: list[tuple[str, str]] = [
|
|
("ls_root", "ls {root}"),
|
|
("ls_group", "ls {root}cat"),
|
|
("ls_leaf", "ls {root}cat/big"),
|
|
("tree", "tree {root}"),
|
|
("find_txt", "find {root} -name '*.txt'"),
|
|
("find_json", "find {root} -name '*.json'"),
|
|
("cat_txt", "cat {root}cat/big/1.txt"),
|
|
("cat_json", "cat {root}cat/big/1.json"),
|
|
("wc_c_txt", "wc -c {root}cat/big/1.txt"),
|
|
("grep_text", "grep orange {root}cat/big/1.txt"),
|
|
("grep_json_field", "grep label {root}cat/big/1.json"),
|
|
("grep_i", "grep -i ORANGE {root}cat/big/1.txt"),
|
|
("grep_n", "grep -n cat {root}cat/big/1.json"),
|
|
("grep_c", "grep -c cat {root}cat/big/1.json"),
|
|
("grep_o", "grep -o cat {root}cat/big/1.json"),
|
|
("grep_w", "grep -w big {root}cat/big/1.json"),
|
|
("grep_F_literal", "grep -F 'orange cat' {root}cat/big/1.txt"),
|
|
("grep_E_alt", 'grep -E "orange|brown" {root}cat/big/1.txt'),
|
|
("grep_v", "grep -v zebra {root}cat/big/1.txt"),
|
|
("grep_multi", "grep small {root}cat/small/2.json {root}dog/small/4.json"),
|
|
("grep_r_group", "grep -r orange {root}cat"),
|
|
("grep_rl", "grep -rl cat {root}"),
|
|
("pipe_grep_stdin", "cat {root}cat/big/1.json | grep orange"),
|
|
("rg_basic", "rg orange {root}cat/big/1.txt"),
|
|
# du has no native op -> exercises the stat/readdir walk fallback,
|
|
# which must match the Python du builder byte for byte.
|
|
("du_leaf", "du {root}cat/big"),
|
|
("du_group", "du {root}cat"),
|
|
("du_root", "du {root}"),
|
|
("du_c_multi", "du -c {root}cat {root}dog"),
|
|
# symlink into the mount (namespace state; works on a read-only backend)
|
|
("sym_ln", "ln -s {root}cat/big/1.json {root}meta_link"),
|
|
("sym_readlink", "readlink {root}meta_link"),
|
|
("sym_cat", "cat {root}meta_link"),
|
|
("sym_grep", "grep label {root}meta_link"),
|
|
("sym_ls", "ls -F {root} | grep meta_link"),
|
|
("sym_rm", "rm {root}meta_link && ls {root}"),
|
|
]
|
|
|
|
EXIT_CODE_CASES: list[tuple[str, str]] = [
|
|
("grep_q_match", "grep -q cat {root}cat/big/1.txt"),
|
|
("grep_q_no_match", "grep -q zebra {root}cat/big/1.txt"),
|
|
("grep_no_match", "grep zebra {root}cat/big/1.txt"),
|
|
]
|
|
|
|
|
|
async def run_cases(ws: Workspace) -> None:
|
|
for name, tmpl in CASES:
|
|
result = await ws.execute(tmpl.format(root=MOUNT))
|
|
out = await result.stdout_str()
|
|
print(f"=== {name} ===")
|
|
print(out, end="" if out.endswith("\n") else "\n")
|
|
for name, tmpl in EXIT_CODE_CASES:
|
|
result = await ws.execute(tmpl.format(root=MOUNT))
|
|
out = await result.stdout_str()
|
|
print(f"=== {name} ===")
|
|
print(f"exit={result.exit_code}")
|
|
if out:
|
|
print(out, end="" if out.endswith("\n") else "\n")
|
|
nf_target = f"{MOUNT.rstrip('/')}/cat/big/__nf_missing__.json"
|
|
for nf_name, nf_prog in (("nf_cat", "cat"), ("nf_head", "head"),
|
|
("nf_tail", "tail"), ("nf_wc", "wc"),
|
|
("nf_stat", "stat"), ("nf_grep", "grep x")):
|
|
result = await ws.execute(f"{nf_prog} {nf_target}")
|
|
err = (await result.stderr_str()).strip()
|
|
print(f"=== {nf_name} ===")
|
|
print(f"exit={result.exit_code}")
|
|
if err:
|
|
print(err)
|
|
prov_target = f"{MOUNT}cat/big/1.txt"
|
|
for pv_name, pv_cmd in (("prov_probe_cat", f"cat {prov_target}"),
|
|
("prov_probe_grep", f"grep x {prov_target}"),
|
|
("prov_probe_ls", f"ls {MOUNT}cat/big")):
|
|
result = await ws.execute(pv_cmd, provision=True)
|
|
print(f"=== {pv_name} ===")
|
|
print(f"net={result.network_read} write={result.network_write} "
|
|
f"cache={result.cache_read} ops={result.read_ops} "
|
|
f"hits={result.cache_hits} "
|
|
f"precision={result.precision.value}")
|
|
result = await ws.execute(f"sed -n 1p {prov_target}")
|
|
out = await result.stdout_str()
|
|
print("=== sed_stream_1p ===")
|
|
print(out, end="" if out.endswith("\n") else "\n")
|
|
result = await ws.execute(f"sed -i s/x/y/ {prov_target}")
|
|
err = (await result.stderr_str()).strip()
|
|
print("=== sed_i_readonly ===")
|
|
print(f"exit={result.exit_code}")
|
|
if err:
|
|
print(err)
|
|
|
|
|
|
def _client() -> AsyncQdrantClient:
|
|
if QDRANT_URL:
|
|
return AsyncQdrantClient(url=QDRANT_URL, api_key=QDRANT_API_KEY)
|
|
return AsyncQdrantClient(host=QDRANT_HOST, port=QDRANT_PORT)
|
|
|
|
|
|
async def seed(client: AsyncQdrantClient) -> None:
|
|
await client.delete_collection(COLLECTION)
|
|
await client.create_collection(COLLECTION,
|
|
vectors_config=models.VectorParams(
|
|
size=EMBED_DIM,
|
|
distance=models.Distance.COSINE))
|
|
await client.upsert(COLLECTION,
|
|
points=[
|
|
models.PointStruct(id=i,
|
|
vector=[0.1] * EMBED_DIM,
|
|
payload={
|
|
"label": label,
|
|
"kind": kind,
|
|
"name": name
|
|
})
|
|
for i, label, kind, name in ROWS
|
|
])
|
|
for field in ("label", "kind"):
|
|
await client.create_payload_index(
|
|
COLLECTION,
|
|
field_name=field,
|
|
field_schema=models.PayloadSchemaType.KEYWORD)
|
|
await asyncio.sleep(2)
|
|
|
|
|
|
async def main() -> None:
|
|
client = _client()
|
|
try:
|
|
await seed(client)
|
|
config = QdrantConfig(
|
|
url=QDRANT_URL,
|
|
api_key=QDRANT_API_KEY,
|
|
host=QDRANT_HOST,
|
|
port=QDRANT_PORT,
|
|
collection=COLLECTION,
|
|
group_by=["label", "kind"],
|
|
id_field="id",
|
|
text_field="name",
|
|
)
|
|
ws = Workspace({MOUNT: QdrantResource(config)}, mode=MountMode.READ)
|
|
await run_cases(ws)
|
|
finally:
|
|
await client.delete_collection(COLLECTION)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
asyncio.run(main())
|