testcontainers-rustfs 1.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
"""Unofficial Testcontainers module for RustFS, an S3-compatible object store."""
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING, Any
|
|
4
|
+
|
|
5
|
+
from testcontainers.core.container import DockerContainer
|
|
6
|
+
from testcontainers.core.wait_strategies import CompositeWaitStrategy, HttpWaitStrategy
|
|
7
|
+
|
|
8
|
+
if TYPE_CHECKING:
|
|
9
|
+
from mypy_boto3_s3.client import S3Client
|
|
10
|
+
|
|
11
|
+
__all__ = ["RustfsContainer"]
|
|
12
|
+
|
|
13
|
+
_DEFAULT_IMAGE = "rustfs/rustfs:1.0.0-beta.12"
|
|
14
|
+
_S3_HEALTH_PATH = "/health"
|
|
15
|
+
_CONSOLE_HEALTH_PATH = "/rustfs/console/health"
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class RustfsContainer(DockerContainer):
|
|
19
|
+
"""RustFS container exposing an S3-compatible API.
|
|
20
|
+
|
|
21
|
+
Example::
|
|
22
|
+
|
|
23
|
+
with RustfsContainer() as rustfs:
|
|
24
|
+
client = rustfs.get_client()
|
|
25
|
+
client.create_bucket(Bucket="testbucket")
|
|
26
|
+
client.put_object(Bucket="testbucket", Key="hello.txt", Body=b"Hello RustFS")
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
def __init__( # noqa: PLR0913
|
|
30
|
+
self,
|
|
31
|
+
image: str = _DEFAULT_IMAGE,
|
|
32
|
+
port: int = 9000,
|
|
33
|
+
access_key: str = "rustfsadmin",
|
|
34
|
+
secret_key: str = "rustfsadmin", # noqa: S107
|
|
35
|
+
*,
|
|
36
|
+
console: bool = False,
|
|
37
|
+
console_port: int = 9001,
|
|
38
|
+
region_name: str = "us-east-1",
|
|
39
|
+
**kwargs: Any, # noqa: ANN401
|
|
40
|
+
) -> None:
|
|
41
|
+
"""Create a RustFS container.
|
|
42
|
+
|
|
43
|
+
Args:
|
|
44
|
+
image: Docker image to run.
|
|
45
|
+
port: Container port serving the S3 API.
|
|
46
|
+
access_key: Access key for client connections.
|
|
47
|
+
secret_key: Secret key for client connections.
|
|
48
|
+
console: Whether to enable and expose the web console.
|
|
49
|
+
console_port: Container port serving the web console.
|
|
50
|
+
region_name: Region reported to S3 clients.
|
|
51
|
+
kwargs: Passed through to ``DockerContainer``.
|
|
52
|
+
"""
|
|
53
|
+
wait_strategy = HttpWaitStrategy(port, _S3_HEALTH_PATH)
|
|
54
|
+
if console:
|
|
55
|
+
wait_strategy = CompositeWaitStrategy(
|
|
56
|
+
wait_strategy,
|
|
57
|
+
HttpWaitStrategy(console_port, _CONSOLE_HEALTH_PATH),
|
|
58
|
+
)
|
|
59
|
+
super().__init__(image, _wait_strategy=wait_strategy, **kwargs)
|
|
60
|
+
|
|
61
|
+
self.port = port
|
|
62
|
+
self.access_key = access_key
|
|
63
|
+
self.secret_key = secret_key
|
|
64
|
+
self.console = console
|
|
65
|
+
self.console_port = console_port
|
|
66
|
+
self.region_name = region_name
|
|
67
|
+
|
|
68
|
+
self.with_exposed_ports(self.port)
|
|
69
|
+
self.with_env("RUSTFS_ACCESS_KEY", self.access_key)
|
|
70
|
+
self.with_env("RUSTFS_SECRET_KEY", self.secret_key)
|
|
71
|
+
self.with_env("RUSTFS_ADDRESS", f":{self.port}")
|
|
72
|
+
|
|
73
|
+
if self.console:
|
|
74
|
+
self.with_exposed_ports(self.console_port)
|
|
75
|
+
self.with_env("RUSTFS_CONSOLE_ENABLE", "true")
|
|
76
|
+
self.with_env("RUSTFS_CONSOLE_ADDRESS", f":{self.console_port}")
|
|
77
|
+
|
|
78
|
+
def get_url(self) -> str:
|
|
79
|
+
"""Return the S3 endpoint URL reachable from the host."""
|
|
80
|
+
return f"http://{self.get_container_host_ip()}:{self.get_exposed_port(self.port)}"
|
|
81
|
+
|
|
82
|
+
def get_console_url(self) -> str:
|
|
83
|
+
"""Return the web console URL reachable from the host.
|
|
84
|
+
|
|
85
|
+
Raises:
|
|
86
|
+
RuntimeError: If the console was not enabled.
|
|
87
|
+
"""
|
|
88
|
+
if not self.console:
|
|
89
|
+
msg = "The RustFS console is disabled; construct the container with RustfsContainer(console=True)."
|
|
90
|
+
raise RuntimeError(msg)
|
|
91
|
+
return f"http://{self.get_container_host_ip()}:{self.get_exposed_port(self.console_port)}"
|
|
92
|
+
|
|
93
|
+
def get_config(self) -> dict[str, str]:
|
|
94
|
+
"""Return the connection settings for the container."""
|
|
95
|
+
host_ip = self.get_container_host_ip()
|
|
96
|
+
exposed_port = self.get_exposed_port(self.port)
|
|
97
|
+
return {
|
|
98
|
+
"endpoint": f"{host_ip}:{exposed_port}",
|
|
99
|
+
"endpoint_url": f"http://{host_ip}:{exposed_port}",
|
|
100
|
+
"access_key": self.access_key,
|
|
101
|
+
"secret_key": self.secret_key,
|
|
102
|
+
"region_name": self.region_name,
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
def get_client(self, **kwargs: Any) -> "S3Client": # noqa: ANN401, UP037
|
|
106
|
+
"""Return a boto3 S3 client bound to this container.
|
|
107
|
+
|
|
108
|
+
Raises:
|
|
109
|
+
RuntimeError: If the optional boto3 dependency is not installed.
|
|
110
|
+
"""
|
|
111
|
+
try:
|
|
112
|
+
import boto3 # noqa: PLC0415
|
|
113
|
+
except ImportError as exc:
|
|
114
|
+
msg = "boto3 is required by get_client(); install it with: pip install 'testcontainers-rustfs[boto3]'"
|
|
115
|
+
raise RuntimeError(msg) from exc
|
|
116
|
+
|
|
117
|
+
return boto3.client(
|
|
118
|
+
"s3",
|
|
119
|
+
endpoint_url=self.get_url(),
|
|
120
|
+
aws_access_key_id=self.access_key,
|
|
121
|
+
aws_secret_access_key=self.secret_key,
|
|
122
|
+
region_name=self.region_name,
|
|
123
|
+
**kwargs,
|
|
124
|
+
)
|
|
File without changes
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: testcontainers-rustfs
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Unofficial Testcontainers Python module for RustFS
|
|
5
|
+
Author: Bence Molnár
|
|
6
|
+
Author-email: Bence Molnár <developer@molnarbence.dev>
|
|
7
|
+
License-Expression: MIT
|
|
8
|
+
License-File: LICENSE
|
|
9
|
+
Classifier: Development Status :: 4 - Beta
|
|
10
|
+
Classifier: Intended Audience :: Developers
|
|
11
|
+
Classifier: Operating System :: OS Independent
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
14
|
+
Classifier: Topic :: Software Development :: Testing
|
|
15
|
+
Classifier: Typing :: Typed
|
|
16
|
+
Requires-Dist: testcontainers>=4.15.0
|
|
17
|
+
Requires-Dist: boto3>=1.34 ; extra == 'boto3'
|
|
18
|
+
Requires-Python: >=3.14
|
|
19
|
+
Project-URL: Homepage, https://github.com/mb-dot-dev/testcontainers-rustfs
|
|
20
|
+
Project-URL: Repository, https://github.com/mb-dot-dev/testcontainers-rustfs
|
|
21
|
+
Project-URL: Issues, https://github.com/mb-dot-dev/testcontainers-rustfs/issues
|
|
22
|
+
Provides-Extra: boto3
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
|
|
25
|
+
# testcontainers-rustfs
|
|
26
|
+
|
|
27
|
+
Unofficial [Testcontainers](https://testcontainers.com/) Python module for
|
|
28
|
+
[RustFS](https://github.com/rustfs/rustfs), an S3-compatible object store.
|
|
29
|
+
|
|
30
|
+
Not affiliated with or endorsed by the RustFS or Testcontainers projects.
|
|
31
|
+
|
|
32
|
+
## Install
|
|
33
|
+
|
|
34
|
+
Requires Python 3.14 or newer.
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
pip install 'testcontainers-rustfs[boto3]'
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
The `boto3` extra is optional. Without it the container still starts and
|
|
41
|
+
`get_config()` / `get_url()` work; only `get_client()` requires boto3.
|
|
42
|
+
|
|
43
|
+
## Usage
|
|
44
|
+
|
|
45
|
+
```python
|
|
46
|
+
from testcontainers_rustfs import RustfsContainer
|
|
47
|
+
|
|
48
|
+
with RustfsContainer() as rustfs:
|
|
49
|
+
client = rustfs.get_client()
|
|
50
|
+
client.create_bucket(Bucket="testbucket")
|
|
51
|
+
client.put_object(Bucket="testbucket", Key="hello.txt", Body=b"Hello RustFS")
|
|
52
|
+
|
|
53
|
+
stored = client.get_object(Bucket="testbucket", Key="hello.txt")["Body"].read()
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Bucket names must be 3–63 characters — RustFS rejects shorter names with
|
|
57
|
+
`InvalidBucketName`.
|
|
58
|
+
|
|
59
|
+
### Bringing your own client
|
|
60
|
+
|
|
61
|
+
```python
|
|
62
|
+
with RustfsContainer() as rustfs:
|
|
63
|
+
config = rustfs.get_config()
|
|
64
|
+
# {'endpoint': 'localhost:32768', 'endpoint_url': 'http://localhost:32768',
|
|
65
|
+
# 'access_key': 'rustfsadmin', 'secret_key': 'rustfsadmin', 'region_name': 'us-east-1'}
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
`endpoint` is the `host:port` form some SDKs expect; `endpoint_url` is the full
|
|
69
|
+
URL boto3 wants.
|
|
70
|
+
|
|
71
|
+
### Web console
|
|
72
|
+
|
|
73
|
+
Disabled by default. Enable it to inspect a failing test's data by eye:
|
|
74
|
+
|
|
75
|
+
```python
|
|
76
|
+
with RustfsContainer(console=True) as rustfs:
|
|
77
|
+
print(rustfs.get_console_url())
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
`get_console_url()` raises `RuntimeError` if the console was not enabled.
|
|
81
|
+
|
|
82
|
+
## Configuration
|
|
83
|
+
|
|
84
|
+
| Parameter | Default | Description |
|
|
85
|
+
|---|---|---|
|
|
86
|
+
| `image` | `rustfs/rustfs:1.0.0-beta.12` | Docker image. Pinned deliberately — RustFS is pre-1.0 and `:latest` moves often |
|
|
87
|
+
| `port` | `9000` | Container port serving the S3 API |
|
|
88
|
+
| `access_key` | `rustfsadmin` | Access key for client connections |
|
|
89
|
+
| `secret_key` | `rustfsadmin` | Secret key for client connections |
|
|
90
|
+
| `console` | `False` | Enable and expose the web console (keyword-only) |
|
|
91
|
+
| `console_port` | `9001` | Container port serving the console (keyword-only) |
|
|
92
|
+
| `region_name` | `us-east-1` | Region reported to S3 clients (keyword-only) |
|
|
93
|
+
|
|
94
|
+
Any further keyword arguments are passed through to `DockerContainer`.
|
|
95
|
+
|
|
96
|
+
Credentials and region are always passed explicitly to the boto3 client, so your
|
|
97
|
+
`~/.aws/config` never influences test behaviour.
|
|
98
|
+
|
|
99
|
+
## Development
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
make install-dev
|
|
103
|
+
make test # lint + unit
|
|
104
|
+
make coverage
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Tests require a running Docker daemon.
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
testcontainers_rustfs/__init__.py,sha256=XWC95p33jPQ7YY_txyCmWZp_ojZeilCyaOpRg4Ktf_k,4607
|
|
2
|
+
testcontainers_rustfs/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
3
|
+
testcontainers_rustfs-1.0.0.dist-info/licenses/LICENSE,sha256=enDLkoEGO6lxkkX0_DJT385bmEoAHwMTBo938cHeRgo,1072
|
|
4
|
+
testcontainers_rustfs-1.0.0.dist-info/WHEEL,sha256=oy45bIW3ehK02fnLDUKD-FzeaR3VpJxY5Jdblkktnpw,80
|
|
5
|
+
testcontainers_rustfs-1.0.0.dist-info/METADATA,sha256=yG5ewaJe3AutBxQdUAB4Xq9B7AoQzhLOweiJmqe8IxA,3520
|
|
6
|
+
testcontainers_rustfs-1.0.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 molnarbence.dev
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|