chore: import upstream snapshot with attribution
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

This commit is contained in:
wehub-resource-sync
2026-07-13 12:30:44 +08:00
commit bcbd1bdb22
5748 changed files with 562488 additions and 0 deletions
@@ -0,0 +1,65 @@
# ========= 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 pydantic import ValidationError
from mirage.resource.aliyun import AliyunConfig, AliyunResource
from mirage.resource.s3 import S3Config
from mirage.resource.secrets import reveal_secret
from mirage.types import ResourceName
def test_aliyun_regional_endpoint():
config = AliyunConfig(bucket="b",
region="cn-hangzhou",
access_key_id="k",
secret_access_key="s")
assert config.resolved_endpoint_url() == (
"https://s3.oss-cn-hangzhou.aliyuncs.com")
def test_aliyun_requires_region():
with pytest.raises(ValidationError):
AliyunConfig(bucket="b", access_key_id="k", secret_access_key="s")
def test_aliyun_custom_endpoint_override():
config = AliyunConfig(bucket="b",
region="cn-beijing",
endpoint_url="https://custom.example.com",
access_key_id="k",
secret_access_key="s")
assert config.resolved_endpoint_url() == "https://custom.example.com"
def test_aliyun_to_s3_config():
config = AliyunConfig(bucket="b",
region="us-west-1",
access_key_id="key",
secret_access_key="secret")
s3 = config.to_s3_config()
assert isinstance(s3, S3Config)
assert s3.endpoint_url == "https://s3.oss-us-west-1.aliyuncs.com"
assert reveal_secret(s3.aws_secret_access_key) == "secret"
def test_aliyun_resource_uses_s3_resource_type():
resource = AliyunResource(
AliyunConfig(bucket="b",
region="cn-hangzhou",
access_key_id="k",
secret_access_key="s"))
assert resource.name == ResourceName.S3
assert isinstance(resource.config, S3Config)
@@ -0,0 +1,65 @@
# ========= 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 pydantic import ValidationError
from mirage.resource.backblaze import BackblazeConfig, BackblazeResource
from mirage.resource.s3 import S3Config
from mirage.resource.secrets import reveal_secret
from mirage.types import ResourceName
def test_backblaze_regional_endpoint():
config = BackblazeConfig(bucket="b",
region="us-west-002",
access_key_id="k",
secret_access_key="s")
assert config.resolved_endpoint_url() == (
"https://s3.us-west-002.backblazeb2.com")
def test_backblaze_requires_region():
with pytest.raises(ValidationError):
BackblazeConfig(bucket="b", access_key_id="k", secret_access_key="s")
def test_backblaze_custom_endpoint_override():
config = BackblazeConfig(bucket="b",
region="us-west-002",
endpoint_url="https://custom.example.com",
access_key_id="k",
secret_access_key="s")
assert config.resolved_endpoint_url() == "https://custom.example.com"
def test_backblaze_to_s3_config():
config = BackblazeConfig(bucket="b",
region="eu-central-003",
access_key_id="key",
secret_access_key="secret")
s3 = config.to_s3_config()
assert isinstance(s3, S3Config)
assert s3.endpoint_url == "https://s3.eu-central-003.backblazeb2.com"
assert reveal_secret(s3.aws_secret_access_key) == "secret"
def test_backblaze_resource_uses_s3_resource_type():
resource = BackblazeResource(
BackblazeConfig(bucket="b",
region="us-west-002",
access_key_id="k",
secret_access_key="s"))
assert resource.name == ResourceName.S3
assert isinstance(resource.config, S3Config)
@@ -0,0 +1,71 @@
# ========= 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 pydantic import ValidationError
from mirage.resource.ceph import CephConfig, CephResource
from mirage.resource.s3 import S3Config
from mirage.resource.secrets import reveal_secret
from mirage.types import ResourceName
def test_ceph_config_defaults():
config = CephConfig(
bucket="my-bucket",
endpoint_url="https://ceph.example.com",
access_key_id="k",
secret_access_key="s",
)
assert config.region == "us-east-1"
assert config.path_style is True
def test_ceph_config_immutable():
config = CephConfig(
bucket="my-bucket",
endpoint_url="https://ceph.example.com",
access_key_id="k",
secret_access_key="s",
)
with pytest.raises(ValidationError):
config.bucket = "other"
def test_ceph_config_to_s3_config():
config = CephConfig(
bucket="my-bucket",
endpoint_url="https://ceph.example.com",
access_key_id="key",
secret_access_key="secret",
)
s3 = config.to_s3_config()
assert isinstance(s3, S3Config)
assert s3.endpoint_url == "https://ceph.example.com"
assert s3.path_style is True
assert reveal_secret(s3.aws_access_key_id) == "key"
assert reveal_secret(s3.aws_secret_access_key) == "secret"
def test_ceph_resource_uses_s3_resource_type():
resource = CephResource(
CephConfig(
bucket="my-bucket",
endpoint_url="https://ceph.example.com",
access_key_id="k",
secret_access_key="s",
))
assert resource.name == ResourceName.S3
assert isinstance(resource.config, S3Config)
assert resource.ceph_config.endpoint_url == "https://ceph.example.com"
@@ -0,0 +1,68 @@
# ========= 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 pydantic import ValidationError
from mirage.resource.digitalocean import (DigitalOceanConfig,
DigitalOceanResource)
from mirage.resource.s3 import S3Config
from mirage.resource.secrets import reveal_secret
from mirage.types import ResourceName
def test_do_regional_endpoint():
config = DigitalOceanConfig(bucket="b",
region="nyc3",
access_key_id="k",
secret_access_key="s")
assert config.resolved_endpoint_url() == (
"https://nyc3.digitaloceanspaces.com")
def test_do_requires_region():
with pytest.raises(ValidationError):
DigitalOceanConfig(bucket="b",
access_key_id="k",
secret_access_key="s")
def test_do_custom_endpoint_override():
config = DigitalOceanConfig(bucket="b",
region="nyc3",
endpoint_url="https://custom.example.com",
access_key_id="k",
secret_access_key="s")
assert config.resolved_endpoint_url() == "https://custom.example.com"
def test_do_to_s3_config():
config = DigitalOceanConfig(bucket="b",
region="fra1",
access_key_id="key",
secret_access_key="secret")
s3 = config.to_s3_config()
assert isinstance(s3, S3Config)
assert s3.endpoint_url == "https://fra1.digitaloceanspaces.com"
assert reveal_secret(s3.aws_access_key_id) == "key"
def test_do_resource_uses_s3_resource_type():
resource = DigitalOceanResource(
DigitalOceanConfig(bucket="b",
region="sfo3",
access_key_id="k",
secret_access_key="s"))
assert resource.name == ResourceName.S3
assert isinstance(resource.config, S3Config)
@@ -0,0 +1,78 @@
# ========= 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 pydantic import ValidationError
from mirage.resource.gcs import GCSConfig, GCSResource
from mirage.resource.secrets import reveal_secret
def test_gcs_config_defaults():
c = GCSConfig(
bucket="my-bucket",
access_key_id="GOOG123",
secret_access_key="secret",
)
assert c.endpoint_url == "https://storage.googleapis.com"
assert c.region == "auto"
assert c.timeout == 30
assert c.proxy is None
def test_gcs_config_immutable():
c = GCSConfig(
bucket="x",
access_key_id="GOOG123",
secret_access_key="secret",
)
with pytest.raises(ValidationError):
c.bucket = "y"
def test_gcs_config_custom_endpoint():
c = GCSConfig(
bucket="my-bucket",
access_key_id="GOOG123",
secret_access_key="secret",
endpoint_url="https://custom.endpoint.com",
)
assert c.endpoint_url == "https://custom.endpoint.com"
def test_gcs_to_s3_config():
c = GCSConfig(
bucket="my-bucket",
access_key_id="GOOG123",
secret_access_key="secret",
)
s3c = c.to_s3_config()
assert s3c.bucket == "my-bucket"
assert reveal_secret(s3c.aws_access_key_id) == "GOOG123"
assert reveal_secret(s3c.aws_secret_access_key) == "secret"
assert s3c.endpoint_url == "https://storage.googleapis.com"
assert s3c.region == "auto"
def test_gcs_resource_creates():
c = GCSConfig(
bucket="my-bucket",
access_key_id="GOOG123",
secret_access_key="secret",
)
resource = GCSResource(c)
assert resource.gcs_config is c
assert resource.accessor.config.bucket == "my-bucket"
expected = "https://storage.googleapis.com"
assert resource.accessor.config.endpoint_url == expected
@@ -0,0 +1,44 @@
# ========= 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 pydantic import ValidationError
from mirage.resource.hf_buckets import HfBucketsConfig, HfBucketsResource
from mirage.types import ResourceName
def test_resource_name():
r = HfBucketsResource(HfBucketsConfig(bucket="o/b"))
assert r.name == ResourceName.HF_BUCKETS
assert r.caches_reads is True
assert r.SUPPORTS_SNAPSHOT is True
def test_config_immutable():
cfg = HfBucketsConfig(bucket="o/b")
with pytest.raises(ValidationError):
cfg.bucket = "other/other"
def test_resource_registers_ops():
r = HfBucketsResource(HfBucketsConfig(bucket="o/b"))
op_names = {o.name for o in r.ops_list()}
assert {"read", "readdir", "stat", "write", "create", "unlink"} <= op_names
def test_resource_registers_commands():
r = HfBucketsResource(HfBucketsConfig(bucket="o/b"))
cmd_names = {c.name for c in r.commands()}
assert {"cat", "ls", "grep", "stat", "touch", "rm"} <= cmd_names
@@ -0,0 +1,44 @@
# ========= 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 pydantic import ValidationError
from mirage.resource.hf_datasets import HfDatasetsConfig, HfDatasetsResource
from mirage.types import ResourceName
def test_resource_name():
r = HfDatasetsResource(HfDatasetsConfig(repo_id="org/dataset"))
assert r.name == ResourceName.HF_DATASETS
assert r.caches_reads is True
assert r.SUPPORTS_SNAPSHOT is True
def test_config_immutable():
cfg = HfDatasetsConfig(repo_id="org/dataset")
with pytest.raises(ValidationError):
cfg.repo_id = "other/other"
def test_resource_registers_ops():
r = HfDatasetsResource(HfDatasetsConfig(repo_id="org/dataset"))
op_names = {o.name for o in r.ops_list()}
assert {"read", "readdir", "stat", "write", "create", "unlink"} <= op_names
def test_resource_registers_commands():
r = HfDatasetsResource(HfDatasetsConfig(repo_id="org/dataset"))
cmd_names = {c.name for c in r.commands()}
assert {"cat", "ls", "grep", "stat", "touch", "rm"} <= cmd_names
@@ -0,0 +1,39 @@
# ========= 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 pydantic import ValidationError
from mirage.resource.hf_models import HfModelsConfig, HfModelsResource
from mirage.types import ResourceName
def test_resource_name():
r = HfModelsResource(HfModelsConfig(repo_id="org/model"))
assert r.name == ResourceName.HF_MODELS
assert r.caches_reads is True
def test_config_immutable():
cfg = HfModelsConfig(repo_id="org/model")
with pytest.raises(ValidationError):
cfg.repo_id = "other/other"
def test_resource_registers_ops_and_commands():
r = HfModelsResource(HfModelsConfig(repo_id="org/model"))
op_names = {o.name for o in r.ops_list()}
cmd_names = {c.name for c in r.commands()}
assert {"read", "readdir", "stat"} <= op_names
assert {"cat", "ls", "stat"} <= cmd_names
@@ -0,0 +1,39 @@
# ========= 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 pydantic import ValidationError
from mirage.resource.hf_spaces import HfSpacesConfig, HfSpacesResource
from mirage.types import ResourceName
def test_resource_name():
r = HfSpacesResource(HfSpacesConfig(repo_id="org/space"))
assert r.name == ResourceName.HF_SPACES
assert r.caches_reads is True
def test_config_immutable():
cfg = HfSpacesConfig(repo_id="org/space")
with pytest.raises(ValidationError):
cfg.repo_id = "other/other"
def test_resource_registers_ops_and_commands():
r = HfSpacesResource(HfSpacesConfig(repo_id="org/space"))
op_names = {o.name for o in r.ops_list()}
cmd_names = {c.name for c in r.commands()}
assert {"read", "readdir", "stat"} <= op_names
assert {"cat", "ls", "stat"} <= cmd_names
@@ -0,0 +1,97 @@
# ========= 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 pydantic import ValidationError
from mirage.resource.minio import MinIOConfig, MinIOResource
from mirage.resource.s3 import S3Config
from mirage.resource.secrets import reveal_secret
from mirage.types import ResourceName
def test_minio_config_defaults():
config = MinIOConfig(
bucket="my-bucket",
endpoint_url="http://localhost:9000",
access_key_id="minioadmin",
secret_access_key="minioadmin",
)
assert config.region == "us-east-1"
assert config.path_style is True
assert config.timeout == 30
def test_minio_config_immutable():
config = MinIOConfig(
bucket="my-bucket",
endpoint_url="http://localhost:9000",
access_key_id="k",
secret_access_key="s",
)
with pytest.raises(ValidationError):
config.bucket = "other"
def test_minio_config_to_s3_config():
config = MinIOConfig(
bucket="my-bucket",
endpoint_url="http://localhost:9000",
access_key_id="minioadmin",
secret_access_key="minioadmin",
proxy="http://localhost:8080",
)
s3 = config.to_s3_config()
assert isinstance(s3, S3Config)
assert s3.bucket == "my-bucket"
assert s3.endpoint_url == "http://localhost:9000"
assert s3.path_style is True
assert reveal_secret(s3.aws_access_key_id) == "minioadmin"
assert reveal_secret(s3.aws_secret_access_key) == "minioadmin"
assert s3.proxy == "http://localhost:8080"
def test_minio_config_path_style_override():
config = MinIOConfig(
bucket="my-bucket",
endpoint_url="https://minio.example.com",
access_key_id="k",
secret_access_key="s",
path_style=False,
)
assert config.to_s3_config().path_style is False
def test_minio_resource_uses_s3_resource_type():
resource = MinIOResource(
MinIOConfig(
bucket="my-bucket",
endpoint_url="http://localhost:9000",
access_key_id="k",
secret_access_key="s",
))
assert resource.name == ResourceName.S3
assert resource.caches_reads is True
assert isinstance(resource.config, S3Config)
def test_minio_resource_preserves_original_config():
config = MinIOConfig(
bucket="my-bucket",
endpoint_url="http://localhost:9000",
access_key_id="k",
secret_access_key="s",
)
resource = MinIOResource(config)
assert resource.minio_config is config
@@ -0,0 +1,108 @@
# ========= 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 pydantic import ValidationError
from mirage.resource.oci import OCIConfig, OCIResource
from mirage.resource.s3 import S3Config
from mirage.resource.secrets import reveal_secret
from mirage.types import ResourceName
def test_oci_config_defaults():
config = OCIConfig(
bucket="my-bucket",
namespace="my-namespace",
region="us-ashburn-1",
access_key_id="access-key",
secret_access_key="secret-key",
)
assert config.timeout == 30
assert config.resolved_endpoint_url() == (
"https://my-namespace.compat.objectstorage."
"us-ashburn-1.oci.customer-oci.com")
def test_oci_config_immutable():
config = OCIConfig(
bucket="my-bucket",
namespace="my-namespace",
region="us-ashburn-1",
access_key_id="access-key",
secret_access_key="secret-key",
)
with pytest.raises(ValidationError):
config.bucket = "other-bucket"
def test_oci_config_to_s3_config():
config = OCIConfig(
bucket="my-bucket",
namespace="my-namespace",
region="us-ashburn-1",
access_key_id="access-key",
secret_access_key="secret-key",
proxy="http://localhost:8080",
)
s3_config = config.to_s3_config()
assert isinstance(s3_config, S3Config)
assert s3_config.bucket == "my-bucket"
assert s3_config.region == "us-ashburn-1"
assert s3_config.endpoint_url == (
"https://my-namespace.compat.objectstorage."
"us-ashburn-1.oci.customer-oci.com")
assert reveal_secret(s3_config.aws_access_key_id) == "access-key"
assert reveal_secret(s3_config.aws_secret_access_key) == "secret-key"
assert s3_config.path_style is True
assert s3_config.proxy == "http://localhost:8080"
def test_oci_config_custom_endpoint():
config = OCIConfig(
bucket="my-bucket",
namespace="my-namespace",
region="us-ashburn-1",
endpoint_url="https://custom.example.com",
access_key_id="access-key",
secret_access_key="secret-key",
)
assert config.resolved_endpoint_url() == "https://custom.example.com"
def test_oci_resource_uses_s3_resource_type():
resource = OCIResource(
OCIConfig(
bucket="my-bucket",
namespace="my-namespace",
region="us-ashburn-1",
access_key_id="access-key",
secret_access_key="secret-key",
))
assert resource.name == ResourceName.S3
assert resource.caches_reads is True
assert isinstance(resource.config, S3Config)
assert resource.config.path_style is True
def test_oci_resource_preserves_original_config():
config = OCIConfig(
bucket="my-bucket",
namespace="my-namespace",
region="us-ashburn-1",
access_key_id="access-key",
secret_access_key="secret-key",
)
resource = OCIResource(config)
assert resource.oci_config is config
@@ -0,0 +1,64 @@
# ========= 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 pydantic import ValidationError
from mirage.resource.qingstor import QingStorConfig, QingStorResource
from mirage.resource.s3 import S3Config
from mirage.resource.secrets import reveal_secret
from mirage.types import ResourceName
def test_qingstor_zone_endpoint():
config = QingStorConfig(bucket="b",
region="pek3b",
access_key_id="k",
secret_access_key="s")
assert config.resolved_endpoint_url() == "https://s3.pek3b.qingstor.com"
def test_qingstor_requires_region():
with pytest.raises(ValidationError):
QingStorConfig(bucket="b", access_key_id="k", secret_access_key="s")
def test_qingstor_custom_endpoint_override():
config = QingStorConfig(bucket="b",
region="sh1a",
endpoint_url="https://custom.example.com",
access_key_id="k",
secret_access_key="s")
assert config.resolved_endpoint_url() == "https://custom.example.com"
def test_qingstor_to_s3_config():
config = QingStorConfig(bucket="b",
region="gd2a",
access_key_id="key",
secret_access_key="secret")
s3 = config.to_s3_config()
assert isinstance(s3, S3Config)
assert s3.endpoint_url == "https://s3.gd2a.qingstor.com"
assert reveal_secret(s3.aws_access_key_id) == "key"
def test_qingstor_resource_uses_s3_resource_type():
resource = QingStorResource(
QingStorConfig(bucket="b",
region="pek3b",
access_key_id="k",
secret_access_key="s"))
assert resource.name == ResourceName.S3
assert isinstance(resource.config, S3Config)
@@ -0,0 +1,84 @@
# ========= 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 pydantic import ValidationError
from mirage.resource.r2 import R2Config, R2Resource
from mirage.resource.s3 import S3Config
from mirage.resource.secrets import reveal_secret
from mirage.types import ResourceName
def test_r2config_defaults():
config = R2Config(bucket="my-bucket", account_id="account-123")
assert config.region == "auto"
assert config.timeout == 30
assert config.resolved_endpoint_url() == (
"https://account-123.r2.cloudflarestorage.com")
def test_r2config_immutable():
config = R2Config(bucket="my-bucket", account_id="account-123")
with pytest.raises(ValidationError):
config.bucket = "other-bucket"
def test_r2config_to_s3_config():
config = R2Config(
bucket="my-bucket",
account_id="account-123",
access_key_id="access-key",
secret_access_key="secret-key",
proxy="http://localhost:8080",
)
s3_config = config.to_s3_config()
assert isinstance(s3_config, S3Config)
assert s3_config.bucket == "my-bucket"
assert s3_config.region == "auto"
assert s3_config.endpoint_url == (
"https://account-123.r2.cloudflarestorage.com")
assert reveal_secret(s3_config.aws_access_key_id) == "access-key"
assert reveal_secret(s3_config.aws_secret_access_key) == "secret-key"
assert s3_config.proxy == "http://localhost:8080"
def test_r2config_custom_endpoint():
config = R2Config(
bucket="my-bucket",
endpoint_url="https://custom.example.com",
)
assert config.resolved_endpoint_url() == "https://custom.example.com"
def test_r2config_requires_account_id_or_endpoint():
config = R2Config(bucket="my-bucket")
with pytest.raises(ValueError):
config.resolved_endpoint_url()
def test_r2resource_uses_s3_resource_type():
resource = R2Resource(
R2Config(bucket="my-bucket", account_id="account-123"))
assert resource.name == ResourceName.S3
assert resource.caches_reads is True
assert isinstance(resource.config, S3Config)
assert resource.config.endpoint_url == (
"https://account-123.r2.cloudflarestorage.com")
def test_r2resource_preserves_original_config():
config = R2Config(bucket="my-bucket", account_id="account-123")
resource = R2Resource(config)
assert resource.r2_config is config
@@ -0,0 +1,79 @@
# ========= 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 pydantic import ValidationError
from mirage.resource.s3 import S3Config
def test_s3config_defaults():
c = S3Config(bucket="my-bucket")
assert c.region is None
assert c.timeout == 30
def test_s3config_immutable():
c = S3Config(bucket="x")
with pytest.raises(ValidationError):
c.bucket = "y"
def test_s3_write_commands_tagged():
from mirage.commands.builtin.s3 import COMMANDS
write_names = {
"rm",
"mkdir",
"touch",
"cp",
"mv",
"ln",
"tee",
"mktemp",
"split",
"csplit",
"gzip",
"gunzip",
"zip",
"unzip",
"tar",
"patch",
"iconv",
}
for fn in COMMANDS:
for rc in fn._registered_commands:
if rc.name in write_names:
assert rc.write is True, (f"{rc.name} should be write=True")
else:
assert rc.write is False, (f"{rc.name} should be write=False")
def test_s3_write_ops_tagged():
from mirage.ops.s3 import OPS
write_op_names = {
"write",
"unlink",
"rmdir",
"mkdir",
"create",
"truncate",
"rename",
}
for fn in OPS:
for ro in fn._registered_ops:
if ro.name in write_op_names:
assert ro.write is True, (f"op {ro.name} should be write=True")
else:
assert ro.write is False, (
f"op {ro.name} should be write=False")
@@ -0,0 +1,72 @@
# ========= 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 re
from io import BytesIO
from unittest.mock import MagicMock
from mirage.resource.s3 import S3Config, S3Resource
def _mock_backend(data: bytes) -> S3Resource:
config = S3Config(
bucket="test-bucket",
region="us-east-1",
aws_access_key_id="fake",
aws_secret_access_key="fake",
)
backend = S3Resource.__new__(S3Resource)
backend.config = config
backend._prefix = ""
backend._event_handlers = []
mock_client = MagicMock()
body = BytesIO(data)
mock_client.get_object.return_value = {"Body": body}
backend._client = mock_client
return backend
def test_grep_file_uses_streaming():
from mirage.commands.builtin.grep_helper import grep_lines
data = b"hello world\nfoo bar\nhello again\n"
compiled = re.compile("hello")
results = grep_lines("test.txt",
data.decode(errors="replace").splitlines(),
compiled,
invert=False,
line_numbers=False,
count_only=False,
files_only=False,
only_matching=False,
max_count=None)
assert len(results) == 2
assert "hello world" in results[0]
def test_grep_file_max_count():
from mirage.commands.builtin.grep_helper import grep_lines
lines = [f"match line {i}".encode() for i in range(100)]
data = b"\n".join(lines) + b"\n"
compiled = re.compile("match")
results = grep_lines("test.txt",
data.decode(errors="replace").splitlines(),
compiled,
invert=False,
line_numbers=False,
count_only=False,
files_only=False,
only_matching=False,
max_count=3)
assert len(results) == 3
@@ -0,0 +1,293 @@
# ========= 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. =========
from datetime import datetime, timezone
from unittest.mock import AsyncMock, MagicMock, patch
import pytest
from mirage.accessor.s3 import S3Accessor
from mirage.cache.index import IndexEntry
from mirage.cache.index.ram import RAMIndexCacheStore
from mirage.core.s3.readdir import readdir
from mirage.core.s3.stat import stat
from mirage.resource.s3 import S3Config
from mirage.types import FileType, PathSpec
from mirage.utils.key_prefix import mount_key
@pytest.fixture
def s3_config():
return S3Config(bucket="test-bucket", region="us-east-1")
@pytest.fixture
def s3_accessor(s3_config):
return S3Accessor(s3_config)
@pytest.fixture
def index():
return RAMIndexCacheStore()
def _mock_client_ctx(mock_client):
mock_ctx = AsyncMock()
mock_ctx.__aenter__.return_value = mock_client
return mock_ctx
class TestStatDirectoryFallback:
@pytest.mark.asyncio
async def test_stat_file_returns_filestat(self, s3_accessor):
with patch("mirage.core.s3.stat.async_session") as mock_session:
mock_client = AsyncMock()
mock_client.head_object.return_value = {
"ContentLength": 1024,
"LastModified": datetime(2026, 1, 1, tzinfo=timezone.utc),
"ETag": '"abc123"',
}
mock_session.return_value.client.return_value = _mock_client_ctx(
mock_client)
path = PathSpec(resource_path=mount_key("/s3/data/file.txt",
"/s3"),
virtual="/s3/data/file.txt",
directory="/s3/data/")
result = await stat(s3_accessor, path)
assert result.name == "file.txt"
assert result.size == 1024
assert result.type == FileType.TEXT
@pytest.mark.asyncio
async def test_stat_directory_prefix_fallback(self, s3_accessor):
with patch("mirage.core.s3.stat.async_session") as mock_session:
mock_client = AsyncMock()
err = Exception("not found")
err.response = {"Error": {"Code": "404"}}
mock_client.head_object.side_effect = err
mock_client.list_objects_v2.return_value = {
"CommonPrefixes": [{
"Prefix": "data/subdir/"
}],
}
mock_session.return_value.client.return_value = _mock_client_ctx(
mock_client)
path = PathSpec(resource_path=mount_key("/s3/data", "/s3"),
virtual="/s3/data",
directory="/s3/")
result = await stat(s3_accessor, path)
assert result.name == "data"
assert result.type == FileType.DIRECTORY
@pytest.mark.asyncio
async def test_stat_directory_prefix_with_contents(self, s3_accessor):
with patch("mirage.core.s3.stat.async_session") as mock_session:
mock_client = AsyncMock()
err = Exception("not found")
err.response = {"Error": {"Code": "NoSuchKey"}}
mock_client.head_object.side_effect = err
mock_client.list_objects_v2.return_value = {
"Contents": [{
"Key": "data/file.txt"
}],
}
mock_session.return_value.client.return_value = _mock_client_ctx(
mock_client)
path = PathSpec(resource_path=mount_key("/s3/data", "/s3"),
virtual="/s3/data",
directory="/s3/")
result = await stat(s3_accessor, path)
assert result.name == "data"
assert result.type == FileType.DIRECTORY
@pytest.mark.asyncio
async def test_stat_nonexistent_raises(self, s3_accessor):
with patch("mirage.core.s3.stat.async_session") as mock_session:
mock_client = AsyncMock()
err = Exception("not found")
err.response = {"Error": {"Code": "404"}}
mock_client.head_object.side_effect = err
mock_client.list_objects_v2.return_value = {}
mock_session.return_value.client.return_value = _mock_client_ctx(
mock_client)
path = PathSpec(resource_path=mount_key("/s3/nope", "/s3"),
virtual="/s3/nope",
directory="/s3/")
with pytest.raises(FileNotFoundError):
await stat(s3_accessor, path)
@pytest.mark.asyncio
async def test_stat_root_returns_directory(self, s3_accessor):
path = PathSpec(resource_path=mount_key("/s3/", "/s3"),
virtual="/s3/",
directory="/s3/")
result = await stat(s3_accessor, path)
assert result.name == "/"
assert result.type == FileType.DIRECTORY
class TestStatIndexCache:
@pytest.mark.asyncio
async def test_stat_uses_index_for_folder(self, s3_accessor, index):
await index.put(
"/s3/data",
IndexEntry(id="/data", name="data", resource_type="folder"))
path = PathSpec(resource_path=mount_key("/s3/data", "/s3"),
virtual="/s3/data",
directory="/s3/")
result = await stat(s3_accessor, path, index)
assert result.name == "data"
assert result.type == FileType.DIRECTORY
@pytest.mark.asyncio
async def test_stat_uses_index_for_file(self, s3_accessor, index):
await index.put(
"/s3/data/file.txt",
IndexEntry(id="/data/file.txt",
name="file.txt",
resource_type="file",
size=2048))
path = PathSpec(resource_path=mount_key("/s3/data/file.txt", "/s3"),
virtual="/s3/data/file.txt",
directory="/s3/data/")
result = await stat(s3_accessor, path, index)
assert result.name == "file.txt"
assert result.size == 2048
assert result.type == FileType.TEXT
class TestReaddirIndexEntries:
@pytest.mark.asyncio
async def test_readdir_stores_folder_type(self, s3_accessor, index):
with patch("mirage.core.s3.readdir.async_session") as mock_session:
mock_client = AsyncMock()
page_data = {
"CommonPrefixes": [{
"Prefix": "subdir/data/"
}],
"Contents": [{
"Key": "subdir/readme.txt",
"Size": 100
}],
}
async def _paginate(**kwargs):
yield page_data
mock_paginator = MagicMock()
mock_paginator.paginate = _paginate
mock_client.get_paginator = MagicMock(return_value=mock_paginator)
mock_session.return_value.client.return_value = _mock_client_ctx(
mock_client)
path = PathSpec(resource_path=mount_key("/s3/subdir", "/s3"),
virtual="/s3/subdir",
directory="/s3/")
result = await readdir(s3_accessor, path, index)
assert "/s3/subdir/data" in result
assert "/s3/subdir/readme.txt" in result
lookup = await index.get("/s3/subdir/data")
assert lookup.entry is not None
assert lookup.entry.resource_type == "folder"
assert lookup.entry.name == "data"
lookup = await index.get("/s3/subdir/readme.txt")
assert lookup.entry is not None
assert lookup.entry.resource_type == "file"
assert lookup.entry.size == 100
@pytest.mark.asyncio
async def test_readdir_cache_hit(self, s3_accessor, index):
with patch("mirage.core.s3.readdir.async_session") as mock_session:
mock_client = AsyncMock()
page_data = {
"CommonPrefixes": [{
"Prefix": "subdir/nested/"
}],
"Contents": [],
}
async def _paginate(**kwargs):
yield page_data
mock_paginator = MagicMock()
mock_paginator.paginate = _paginate
mock_client.get_paginator = MagicMock(return_value=mock_paginator)
mock_session.return_value.client.return_value = _mock_client_ctx(
mock_client)
path = PathSpec(resource_path=mount_key("/s3/subdir", "/s3"),
virtual="/s3/subdir",
directory="/s3/")
r1 = await readdir(s3_accessor, path, index)
r2 = await readdir(s3_accessor, path, index)
assert r1 == r2
assert mock_client.get_paginator.call_count == 1
class TestStatAfterReaddir:
@pytest.mark.asyncio
async def test_stat_hits_cache_after_readdir(self, s3_accessor, index):
with patch("mirage.core.s3.readdir.async_session") as mock_session:
mock_client = AsyncMock()
page_data = {
"CommonPrefixes": [{
"Prefix": "subdir/nested/"
}],
"Contents": [{
"Key": "subdir/readme.txt",
"Size": 500
}],
}
async def _paginate(**kwargs):
yield page_data
mock_paginator = MagicMock()
mock_paginator.paginate = _paginate
mock_client.get_paginator = MagicMock(return_value=mock_paginator)
mock_session.return_value.client.return_value = _mock_client_ctx(
mock_client)
path = PathSpec(resource_path=mount_key("/s3/subdir", "/s3"),
virtual="/s3/subdir",
directory="/s3/")
await readdir(s3_accessor, path, index)
result = await stat(
s3_accessor,
PathSpec(resource_path=mount_key("/s3/subdir/nested", "/s3"),
virtual="/s3/subdir/nested",
directory="/s3/subdir/"), index)
assert result.name == "nested"
assert result.type == FileType.DIRECTORY
result = await stat(
s3_accessor,
PathSpec(resource_path=mount_key("/s3/subdir/readme.txt", "/s3"),
virtual="/s3/subdir/readme.txt",
directory="/s3/subdir/"), index)
assert result.name == "readme.txt"
assert result.size == 500
@@ -0,0 +1,101 @@
# ========= 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. =========
from unittest.mock import AsyncMock, patch
import pytest
from mirage.accessor.s3 import S3Accessor
from mirage.resource.s3 import S3Config, S3Resource
from mirage.types import PathSpec
@pytest.fixture
def s3_config():
return S3Config(bucket="test-bucket", region="us-east-1")
@pytest.fixture
def s3_accessor(s3_config):
return S3Accessor(s3_config)
@pytest.fixture
def s3_backend(s3_config):
return S3Resource(s3_config)
@pytest.mark.asyncio
async def test_get_bytes(s3_accessor):
from mirage.core.s3.read import read_bytes
with patch("mirage.core.s3.read.async_session") as mock_session:
mock_client = AsyncMock()
mock_body = AsyncMock()
mock_body.read.return_value = b"hello world\nfoo bar\nbaz"
mock_client.get_object.return_value = {"Body": mock_body}
mock_ctx = AsyncMock()
mock_ctx.__aenter__.return_value = mock_client
mock_session.return_value.client.return_value = mock_ctx
data = await read_bytes(
s3_accessor,
PathSpec(resource_path="data/file.txt",
virtual="/data/file.txt",
directory="/data/file.txt"))
assert data == b"hello world\nfoo bar\nbaz"
@pytest.mark.asyncio
async def test_range_get(s3_accessor):
from mirage.core.s3.read import read_bytes
with patch("mirage.core.s3.read.async_session") as mock_session:
mock_client = AsyncMock()
mock_body = AsyncMock()
mock_body.read.return_value = b"hello"
mock_client.get_object.return_value = {"Body": mock_body}
mock_ctx = AsyncMock()
mock_ctx.__aenter__.return_value = mock_client
mock_session.return_value.client.return_value = mock_ctx
data = await read_bytes(s3_accessor,
PathSpec(resource_path="data/file.txt",
virtual="/data/file.txt",
directory="/data/file.txt"),
offset=0,
size=5)
assert data == b"hello"
mock_client.get_object.assert_called_once()
call_kwargs = mock_client.get_object.call_args[1]
assert "Range" in call_kwargs
assert call_kwargs["Range"] == "bytes=0-4"
@pytest.mark.asyncio
async def test_put_bytes(s3_accessor):
from mirage.core.s3.write import write_bytes
with patch("mirage.core.s3.write.async_session") as mock_session:
mock_client = AsyncMock()
mock_ctx = AsyncMock()
mock_ctx.__aenter__.return_value = mock_client
mock_session.return_value.client.return_value = mock_ctx
await write_bytes(
s3_accessor,
PathSpec(resource_path="data/out.txt",
virtual="/data/out.txt",
directory="/data/out.txt"), b"hello")
mock_client.put_object.assert_called_once()
call_kwargs = mock_client.put_object.call_args[1]
assert call_kwargs["Body"] == b"hello"
assert call_kwargs["Key"] == "data/out.txt"
@@ -0,0 +1,98 @@
# ========= 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
from io import BytesIO
from unittest.mock import AsyncMock, MagicMock, patch
from mirage.accessor.s3 import S3Accessor
from mirage.resource.s3 import S3Config
def _config():
return S3Accessor(
S3Config(
bucket="test-bucket",
region="us-east-1",
aws_access_key_id="fake",
aws_secret_access_key="fake",
))
def _mock_session(data: bytes, chunk_size: int = 8192):
mock_client = AsyncMock()
body_mock = AsyncMock()
body_mock.read = AsyncMock(return_value=data)
async def _iter_chunks(size=chunk_size):
buf = BytesIO(data)
while True:
chunk = buf.read(size)
if not chunk:
break
yield chunk
body_mock.iter_chunks = _iter_chunks
mock_client.get_object = AsyncMock(return_value={"Body": body_mock})
mock_session = MagicMock()
ctx = AsyncMock()
ctx.__aenter__ = AsyncMock(return_value=mock_client)
ctx.__aexit__ = AsyncMock(return_value=False)
mock_session.client = MagicMock(return_value=ctx)
return mock_session
def test_read_stream_returns_async_iterator():
from mirage.core.s3.stream import read_stream
config = _config()
session = _mock_session(b"hello world")
async def _run():
chunks = []
async for chunk in read_stream(config, "test.txt"):
chunks.append(chunk)
return chunks
with patch("mirage.core.s3.stream.async_session", return_value=session):
chunks = asyncio.run(_run())
assert b"".join(chunks) == b"hello world"
def test_read_stream_yields_chunks():
from mirage.core.s3.stream import read_stream
config = _config()
session = _mock_session(b"a" * 100, chunk_size=30)
async def _run():
chunks = []
async for chunk in read_stream(config, "test.txt", chunk_size=30):
chunks.append(chunk)
return chunks
with patch("mirage.core.s3.stream.async_session", return_value=session):
chunks = asyncio.run(_run())
assert b"".join(chunks) == b"a" * 100
assert len(chunks) >= 2
def test_read_bytes_returns_bytes():
from mirage.core.s3.read import read_bytes
config = _config()
session = _mock_session(b"file content here")
with patch("mirage.core.s3.read.async_session", return_value=session):
result = asyncio.run(read_bytes(config, "test.txt"))
assert isinstance(result, bytes)
assert result == b"file content here"
@@ -0,0 +1,64 @@
# ========= 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 pydantic import ValidationError
from mirage.resource.s3 import S3Config
from mirage.resource.scaleway import ScalewayConfig, ScalewayResource
from mirage.resource.secrets import reveal_secret
from mirage.types import ResourceName
def test_scaleway_regional_endpoint():
config = ScalewayConfig(bucket="b",
region="fr-par",
access_key_id="k",
secret_access_key="s")
assert config.resolved_endpoint_url() == "https://s3.fr-par.scw.cloud"
def test_scaleway_requires_region():
with pytest.raises(ValidationError):
ScalewayConfig(bucket="b", access_key_id="k", secret_access_key="s")
def test_scaleway_custom_endpoint_override():
config = ScalewayConfig(bucket="b",
region="nl-ams",
endpoint_url="https://custom.example.com",
access_key_id="k",
secret_access_key="s")
assert config.resolved_endpoint_url() == "https://custom.example.com"
def test_scaleway_to_s3_config():
config = ScalewayConfig(bucket="b",
region="pl-waw",
access_key_id="key",
secret_access_key="secret")
s3 = config.to_s3_config()
assert isinstance(s3, S3Config)
assert s3.endpoint_url == "https://s3.pl-waw.scw.cloud"
assert reveal_secret(s3.aws_access_key_id) == "key"
def test_scaleway_resource_uses_s3_resource_type():
resource = ScalewayResource(
ScalewayConfig(bucket="b",
region="fr-par",
access_key_id="k",
secret_access_key="s"))
assert resource.name == ResourceName.S3
assert isinstance(resource.config, S3Config)
@@ -0,0 +1,97 @@
# ========= 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 pydantic import ValidationError
from mirage.resource.s3 import S3Config
from mirage.resource.seaweedfs import SeaweedFSConfig, SeaweedFSResource
from mirage.resource.secrets import reveal_secret
from mirage.types import ResourceName
def test_seaweedfs_config_defaults():
config = SeaweedFSConfig(
bucket="my-bucket",
endpoint_url="http://localhost:8333",
access_key_id="weed",
secret_access_key="weed",
)
assert config.region == "us-east-1"
assert config.path_style is True
assert config.timeout == 30
def test_seaweedfs_config_immutable():
config = SeaweedFSConfig(
bucket="my-bucket",
endpoint_url="http://localhost:8333",
access_key_id="k",
secret_access_key="s",
)
with pytest.raises(ValidationError):
config.bucket = "other"
def test_seaweedfs_config_to_s3_config():
config = SeaweedFSConfig(
bucket="my-bucket",
endpoint_url="http://localhost:8333",
access_key_id="weed",
secret_access_key="weed",
proxy="http://localhost:8080",
)
s3 = config.to_s3_config()
assert isinstance(s3, S3Config)
assert s3.bucket == "my-bucket"
assert s3.endpoint_url == "http://localhost:8333"
assert s3.path_style is True
assert reveal_secret(s3.aws_access_key_id) == "weed"
assert reveal_secret(s3.aws_secret_access_key) == "weed"
assert s3.proxy == "http://localhost:8080"
def test_seaweedfs_config_path_style_override():
config = SeaweedFSConfig(
bucket="my-bucket",
endpoint_url="https://seaweedfs.example.com",
access_key_id="k",
secret_access_key="s",
path_style=False,
)
assert config.to_s3_config().path_style is False
def test_seaweedfs_resource_uses_s3_resource_type():
resource = SeaweedFSResource(
SeaweedFSConfig(
bucket="my-bucket",
endpoint_url="http://localhost:8333",
access_key_id="k",
secret_access_key="s",
))
assert resource.name == ResourceName.S3
assert resource.caches_reads is True
assert isinstance(resource.config, S3Config)
def test_seaweedfs_resource_preserves_original_config():
config = SeaweedFSConfig(
bucket="my-bucket",
endpoint_url="http://localhost:8333",
access_key_id="k",
secret_access_key="s",
)
resource = SeaweedFSResource(config)
assert resource.seaweedfs_config is config
@@ -0,0 +1,123 @@
# ========= 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 pydantic import ValidationError
from mirage.core.s3._client import _client_kwargs
from mirage.resource.s3 import S3Config
from mirage.resource.secrets import reveal_secret
from mirage.resource.supabase import SupabaseConfig, SupabaseResource
from mirage.types import ResourceName
def test_supabase_config_defaults():
config = SupabaseConfig(
bucket="my-bucket",
project_ref="project-123",
region="us-west-2",
access_key_id="access-key",
secret_access_key="secret-key",
)
assert config.timeout == 30
assert config.resolved_endpoint_url() == (
"https://project-123.storage.supabase.co/storage/v1/s3")
def test_supabase_config_immutable():
config = SupabaseConfig(
bucket="my-bucket",
project_ref="project-123",
region="us-west-2",
access_key_id="access-key",
secret_access_key="secret-key",
)
with pytest.raises(ValidationError):
config.bucket = "other-bucket"
def test_supabase_config_to_s3_config():
config = SupabaseConfig(
bucket="my-bucket",
endpoint_url="https://example.supabase.co/storage/v1/s3",
region="us-west-2",
access_key_id="access-key",
secret_access_key="secret-key",
session_token="session-token",
proxy="http://localhost:8080",
)
s3_config = config.to_s3_config()
assert isinstance(s3_config, S3Config)
assert s3_config.bucket == "my-bucket"
assert s3_config.region == "us-west-2"
assert (
s3_config.endpoint_url == "https://example.supabase.co/storage/v1/s3")
assert reveal_secret(s3_config.aws_access_key_id) == "access-key"
assert reveal_secret(s3_config.aws_secret_access_key) == "secret-key"
assert reveal_secret(s3_config.aws_session_token) == "session-token"
assert s3_config.path_style is True
assert s3_config.proxy == "http://localhost:8080"
def test_supabase_config_requires_project_ref_or_endpoint():
config = SupabaseConfig(
bucket="my-bucket",
region="us-west-2",
access_key_id="access-key",
secret_access_key="secret-key",
)
with pytest.raises(ValueError):
config.resolved_endpoint_url()
def test_supabase_resource_uses_s3_resource_type():
resource = SupabaseResource(
SupabaseConfig(
bucket="my-bucket",
project_ref="project-123",
region="us-west-2",
access_key_id="access-key",
secret_access_key="secret-key",
))
assert resource.name == ResourceName.S3
assert resource.caches_reads is True
assert isinstance(resource.config, S3Config)
assert resource.config.path_style is True
def test_supabase_resource_preserves_original_config():
config = SupabaseConfig(
bucket="my-bucket",
project_ref="project-123",
region="us-west-2",
access_key_id="access-key",
secret_access_key="secret-key",
)
resource = SupabaseResource(config)
assert resource.supabase_config is config
def test_s3_client_kwargs_support_path_style_and_session_token():
config = S3Config(
bucket="my-bucket",
region="us-west-2",
endpoint_url="https://example.com",
aws_access_key_id="access-key",
aws_secret_access_key="secret-key",
aws_session_token="session-token",
path_style=True,
)
kwargs = _client_kwargs(config)
assert kwargs["aws_session_token"] == "session-token"
assert kwargs["config"].s3 == {"addressing_style": "path"}
@@ -0,0 +1,65 @@
# ========= 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 pydantic import ValidationError
from mirage.resource.s3 import S3Config
from mirage.resource.secrets import reveal_secret
from mirage.resource.tencent import TencentConfig, TencentResource
from mirage.types import ResourceName
def test_tencent_regional_endpoint():
config = TencentConfig(bucket="b-1250",
region="ap-guangzhou",
access_key_id="k",
secret_access_key="s")
assert config.resolved_endpoint_url() == (
"https://cos.ap-guangzhou.myqcloud.com")
def test_tencent_requires_region():
with pytest.raises(ValidationError):
TencentConfig(bucket="b", access_key_id="k", secret_access_key="s")
def test_tencent_custom_endpoint_override():
config = TencentConfig(bucket="b",
region="ap-beijing",
endpoint_url="https://custom.example.com",
access_key_id="k",
secret_access_key="s")
assert config.resolved_endpoint_url() == "https://custom.example.com"
def test_tencent_to_s3_config():
config = TencentConfig(bucket="b-1250",
region="ap-singapore",
access_key_id="key",
secret_access_key="secret")
s3 = config.to_s3_config()
assert isinstance(s3, S3Config)
assert s3.endpoint_url == "https://cos.ap-singapore.myqcloud.com"
assert reveal_secret(s3.aws_access_key_id) == "key"
def test_tencent_resource_uses_s3_resource_type():
resource = TencentResource(
TencentConfig(bucket="b-1250",
region="ap-guangzhou",
access_key_id="k",
secret_access_key="s"))
assert resource.name == ResourceName.S3
assert isinstance(resource.config, S3Config)
@@ -0,0 +1,69 @@
# ========= 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 pydantic import ValidationError
from mirage.resource.s3 import S3Config
from mirage.resource.secrets import reveal_secret
from mirage.resource.wasabi import WasabiConfig, WasabiResource
from mirage.types import ResourceName
def test_wasabi_default_region_endpoint():
config = WasabiConfig(bucket="b", access_key_id="k", secret_access_key="s")
assert config.region == "us-east-1"
assert config.resolved_endpoint_url() == "https://s3.wasabisys.com"
def test_wasabi_regional_endpoint():
config = WasabiConfig(bucket="b",
region="us-west-1",
access_key_id="k",
secret_access_key="s")
assert config.resolved_endpoint_url() == (
"https://s3.us-west-1.wasabisys.com")
def test_wasabi_custom_endpoint_override():
config = WasabiConfig(bucket="b",
endpoint_url="https://custom.example.com",
access_key_id="k",
secret_access_key="s")
assert config.resolved_endpoint_url() == "https://custom.example.com"
def test_wasabi_config_immutable():
config = WasabiConfig(bucket="b", access_key_id="k", secret_access_key="s")
with pytest.raises(ValidationError):
config.bucket = "other"
def test_wasabi_to_s3_config():
config = WasabiConfig(bucket="b",
region="us-east-2",
access_key_id="key",
secret_access_key="secret")
s3 = config.to_s3_config()
assert isinstance(s3, S3Config)
assert s3.endpoint_url == "https://s3.us-east-2.wasabisys.com"
assert s3.path_style is False
assert reveal_secret(s3.aws_access_key_id) == "key"
def test_wasabi_resource_uses_s3_resource_type():
resource = WasabiResource(
WasabiConfig(bucket="b", access_key_id="k", secret_access_key="s"))
assert resource.name == ResourceName.S3
assert isinstance(resource.config, S3Config)