You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

167 lines
5.6 KiB

from sqlalchemy import select
import pytest
from app.models.entities import Blob, BlobReplica, FileEntry, FileVersion
@pytest.mark.anyio
async def test_reconcile_uses_preferred_and_excluded_backends(api_client, session_factory, fake_s3) -> None:
stable_a = await api_client.post(
"/api/backends",
json={
"name": "s3-stable-a",
"type": "s3",
"stability_class": "stable",
"read_priority": 80,
"write_priority": 80,
"config": {"bucket": "stable-a"},
},
)
stable_b = await api_client.post(
"/api/backends",
json={
"name": "s3-stable-b",
"type": "s3",
"stability_class": "stable",
"read_priority": 90,
"write_priority": 90,
"config": {"bucket": "stable-b"},
},
)
opportunistic = await api_client.post(
"/api/backends",
json={
"name": "s3-opp",
"type": "s3",
"stability_class": "opportunistic",
"read_priority": 70,
"write_priority": 70,
"config": {"bucket": "opp"},
},
)
stable_a_id = stable_a.json()["backend"]["id"]
stable_b_id = stable_b.json()["backend"]["id"]
opportunistic_id = opportunistic.json()["backend"]["id"]
await api_client.put(
"/api/policies/placement/image",
json={
"require_local": True,
"stable_replica_count": 1,
"opportunistic_replica_count": 1,
"preferred_backend_ids": [stable_b_id, opportunistic_id],
"excluded_backend_ids": [stable_a_id],
"max_non_local_size_bytes": None,
},
)
create_response = await api_client.post(
"/files",
headers={"Tus-Resumable": "1.0.0", "Upload-Length": "9"},
)
upload_id = create_response.headers["Location"].rsplit("/", 1)[-1]
await api_client.patch(
f"/files/{upload_id}",
headers={
"Tus-Resumable": "1.0.0",
"Upload-Offset": "0",
"Content-Type": "application/offset+octet-stream",
},
content=b"image-bin",
)
finalize_response = await api_client.post(
f"/api/uploads/{upload_id}/finalize",
json={"directory_id": "dir_root", "filename": "poster.jpg"},
)
assert finalize_response.status_code == 200
run_response = await api_client.post("/api/jobs/run-pending")
assert run_response.status_code == 200
assert run_response.json()["completed"] >= 1
file_id = finalize_response.json()["file"]["id"]
async with session_factory() as session:
blob_replicas = (
await session.execute(
select(BlobReplica.backend_id)
.join(Blob, BlobReplica.blob_id == Blob.id)
.join(FileVersion, Blob.file_version_id == FileVersion.id)
.join(FileEntry, FileVersion.id == FileEntry.current_version_id)
.where(FileEntry.id == file_id, BlobReplica.status == "ready")
)
).scalars().all()
assert "bkd_local_default" in blob_replicas
assert stable_b_id in blob_replicas
assert opportunistic_id in blob_replicas
assert stable_a_id not in blob_replicas
download_response = await api_client.get(f"/api/files/{file_id}/download")
assert download_response.status_code == 200
assert download_response.content == b"image-bin"
@pytest.mark.anyio
async def test_large_file_policy_can_skip_non_local_replicas(api_client, session_factory, fake_s3) -> None:
stable_backend = await api_client.post(
"/api/backends",
json={
"name": "s3-stable-a",
"type": "s3",
"stability_class": "stable",
"read_priority": 80,
"write_priority": 80,
"config": {"bucket": "stable-a"},
},
)
stable_backend_id = stable_backend.json()["backend"]["id"]
await api_client.put(
"/api/policies/placement/video",
json={
"require_local": True,
"stable_replica_count": 1,
"opportunistic_replica_count": 0,
"preferred_backend_ids": [stable_backend_id],
"excluded_backend_ids": [],
"max_non_local_size_bytes": 4,
},
)
create_response = await api_client.post(
"/files",
headers={"Tus-Resumable": "1.0.0", "Upload-Length": "5"},
)
upload_id = create_response.headers["Location"].rsplit("/", 1)[-1]
await api_client.patch(
f"/files/{upload_id}",
headers={
"Tus-Resumable": "1.0.0",
"Upload-Offset": "0",
"Content-Type": "application/offset+octet-stream",
},
content=b"hello",
)
finalize_response = await api_client.post(
f"/api/uploads/{upload_id}/finalize",
json={"directory_id": "dir_root", "filename": "clip.mp4"},
)
assert finalize_response.status_code == 200
run_response = await api_client.post("/api/jobs/run-pending")
assert run_response.status_code == 200
async with session_factory() as session:
blob_replicas = (
await session.execute(
select(BlobReplica.backend_id)
.join(Blob, BlobReplica.blob_id == Blob.id)
.join(FileVersion, Blob.file_version_id == FileVersion.id)
.join(FileEntry, FileVersion.id == FileEntry.current_version_id)
.where(
FileEntry.id == finalize_response.json()["file"]["id"],
BlobReplica.status == "ready",
)
)
).scalars().all()
assert blob_replicas == ["bkd_local_default"]