Skip to content

Commit 6614a99

Browse files
authored
test: add SeaweedFS (#29)
1 parent bd29aa8 commit 6614a99

2 files changed

Lines changed: 160 additions & 9 deletions

File tree

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@ py314 = { features = ["testing", "py314"] }
120120

121121
[tool.pixi.feature.testing.dependencies]
122122
flamegraph-pl = "*"
123+
seaweedfs = "*"
123124

124125
[tool.pixi.feature.testing.pypi-dependencies]
125126
flameprof = "*"

tests/conftest.py

Lines changed: 159 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,13 @@
44

55
import base64
66
import hashlib
7+
import json
8+
import os
79
import random
10+
import signal
11+
import subprocess
12+
import time
13+
from tempfile import TemporaryDirectory
814

915
import boto3
1016
import botocore
@@ -15,13 +21,6 @@
1521
from signurlarity import Client
1622
from signurlarity.aio import AsyncClient
1723

18-
# logging.basicConfig(
19-
# format="%(levelname)s [%(asctime)s] %(name)s - %(message)s",
20-
# datefmt="%Y-%m-%d %H:%M:%S",
21-
# level=logging.DEBUG,
22-
# )
23-
24-
2524
# Constants
2625
BUCKET_NAME = "test-bucket"
2726
OTHER_BUCKET_NAME = "other-bucket"
@@ -143,9 +142,159 @@ def minio_server():
143142
subprocess.run(cmd, check=True) # noqa: S603
144143

145144

145+
@pytest.fixture(scope="module")
146+
def seaweedfs_server():
147+
"""Run a SeaweedFS server with S3 API enabled.
148+
149+
Because it creates volumes on the fly, we have to upload a file
150+
and wait for the initialization to be over, otherwise all the tests
151+
fail.
152+
"""
153+
AWS_ACCESS_KEY_ID = "admin"
154+
AWS_SECRET_ACCESS_KEY = "key" # noqa: S105
155+
156+
def check_volume_status(max_retries=10, retry_delay=5):
157+
cmd = ["weed", "shell"]
158+
# Use echo to send the command to weed shell
159+
input_cmd = "cluster.status\n"
160+
161+
for attempt in range(1, max_retries + 1):
162+
try:
163+
process = subprocess.Popen( # noqa: S603
164+
cmd,
165+
stdin=subprocess.PIPE,
166+
stdout=subprocess.PIPE,
167+
stderr=subprocess.PIPE,
168+
text=True,
169+
)
170+
stdout, _stderr = process.communicate(input=input_cmd, timeout=15)
171+
172+
# Check if "7 volume" is in the output
173+
if "7 volume" in stdout:
174+
print("Found '7 volume' in output!")
175+
return
176+
177+
print(
178+
f"'7 volume' not found (attempt {attempt}/{max_retries}), "
179+
f"retrying in {retry_delay} seconds..."
180+
)
181+
except subprocess.TimeoutExpired:
182+
process.kill()
183+
stdout, _stderr = process.communicate()
184+
print(
185+
f"weed shell timed out (attempt {attempt}/{max_retries}), "
186+
f"retrying in {retry_delay} seconds..."
187+
)
188+
except Exception as exc:
189+
print(
190+
f"Error checking volume status (attempt {attempt}/{max_retries}): {exc}"
191+
)
192+
193+
if attempt < max_retries:
194+
time.sleep(retry_delay)
195+
196+
raise RuntimeError(
197+
f"SeaweedFS did not report '7 volume' after {max_retries} attempts"
198+
)
199+
200+
with TemporaryDirectory() as tmp_dir:
201+
os.mkdir(f"{tmp_dir}/seaweedfs")
202+
with open(f"{tmp_dir}/seaweedfs_s3.json", "wt") as f:
203+
json.dump(
204+
{
205+
"identities": [
206+
{
207+
"name": "admin",
208+
"credentials": [
209+
{
210+
"accessKey": AWS_ACCESS_KEY_ID,
211+
"secretKey": AWS_SECRET_ACCESS_KEY,
212+
}
213+
],
214+
"actions": ["Admin", "Read", "Write", "List", "Tagging"],
215+
}
216+
]
217+
},
218+
f,
219+
)
220+
cmd = [
221+
"weed",
222+
"mini",
223+
"-dir",
224+
f"{tmp_dir}/seaweedfs",
225+
"-s3.config",
226+
f"{tmp_dir}/seaweedfs_s3.json",
227+
]
228+
with open(f"{tmp_dir}/seaweedfs.log", "w") as log_file:
229+
pid = None
230+
try:
231+
process = subprocess.Popen( # noqa: S603
232+
cmd,
233+
stdout=log_file,
234+
stderr=subprocess.STDOUT, # Redirect stderr to stdout
235+
)
236+
237+
pid = process.pid
238+
print(f"Process PID: {pid} Working Directory {tmp_dir}")
239+
upload_cmd = [
240+
"weed",
241+
"upload",
242+
"-master",
243+
"localhost:9333",
244+
f"{tmp_dir}/seaweedfs.log",
245+
]
246+
max_retries = 10
247+
retry_delay = 5
248+
249+
for attempt in range(1, max_retries + 1):
250+
try:
251+
subprocess.run( # noqa: S603
252+
upload_cmd, check=True, capture_output=True, text=True
253+
)
254+
print("Upload successful!")
255+
break
256+
except subprocess.CalledProcessError as e:
257+
if attempt >= max_retries:
258+
raise RuntimeError(
259+
f"Upload failed after {max_retries} attempts: {e.stderr}"
260+
) from e
261+
print(
262+
f"Upload failed (attempt {attempt}/{max_retries}), "
263+
f"retrying in {retry_delay} seconds... (Error: {e.stderr})"
264+
)
265+
time.sleep(retry_delay)
266+
check_volume_status()
267+
268+
yield {
269+
"endpoint_url": "http://localhost:8333",
270+
"aws_access_key_id": AWS_ACCESS_KEY_ID,
271+
"aws_secret_access_key": AWS_SECRET_ACCESS_KEY,
272+
}
273+
except RuntimeError as e:
274+
print(e)
275+
log_file.flush()
276+
print("=== SeaweedFS log start ===")
277+
try:
278+
with open(
279+
f"{tmp_dir}/seaweedfs.log",
280+
"rt",
281+
encoding="utf-8",
282+
errors="replace",
283+
) as read_log:
284+
print(read_log.read())
285+
except OSError as log_error:
286+
print(f"Failed to read SeaweedFS log file: {log_error}")
287+
print("=== SeaweedFS log end ===")
288+
raise
289+
finally:
290+
if pid:
291+
os.kill(pid, signal.SIGKILL)
292+
293+
146294
# Synchronous client fixtures
147295
@pytest.fixture(
148-
scope="function", params=["minio_server", "moto_server", "rustfs_server"]
296+
scope="function",
297+
params=["minio_server", "moto_server", "rustfs_server", "seaweedfs_server"],
149298
)
150299
def s3_clients(request):
151300
"""S3 clients for synchronous tests with multiple server backends.
@@ -171,7 +320,8 @@ def s3_clients(request):
171320

172321
# Asynchronous client fixtures
173322
@pytest.fixture(
174-
scope="function", params=["minio_server", "moto_server", "rustfs_server"]
323+
scope="function",
324+
params=["minio_server", "moto_server", "rustfs_server", "seaweedfs_server"],
175325
)
176326
async def s3_clients_aio(request):
177327
"""S3 clients for asynchronous tests with multiple server backends.

0 commit comments

Comments
 (0)