Files
spoolman2/tests_integration/tests/spool/test_use.py

181 lines
5.5 KiB
Python

"""Integration tests for the Spool API endpoint."""
import asyncio
import math
from datetime import datetime, timezone
from typing import Any
import httpx
import pytest
from ..conftest import URL
@pytest.mark.parametrize("use_weight", [0, 0.05, -0.05, 1500]) # 1500 is big enough to use all filament
def test_use_spool_weight(random_filament: dict[str, Any], use_weight: float):
"""Test using a spool in the database."""
# Setup
filament_net_weight = random_filament["weight"]
start_weight = 1000
result = httpx.post(
f"{URL}/api/v1/spool",
json={
"filament_id": random_filament["id"],
"remaining_weight": start_weight,
},
)
result.raise_for_status()
spool = result.json()
# Execute
result = httpx.put(
f"{URL}/api/v1/spool/{spool['id']}/use",
json={
"use_weight": use_weight,
},
)
result.raise_for_status()
# Verify
spool = result.json()
# remaining_weight should be clamped so it's never negative, but used_weight should not be clamped to the net weight
assert spool["used_weight"] == pytest.approx(max(use_weight, 0))
assert spool["remaining_weight"] == pytest.approx(min(max(start_weight - use_weight, 0), filament_net_weight))
# Verify that first_used has been updated
diff = abs((datetime.now(tz=timezone.utc) - datetime.fromisoformat(spool["first_used"])).total_seconds())
assert diff < 60
# Verify that last_used has been updated
diff = abs((datetime.now(tz=timezone.utc) - datetime.fromisoformat(spool["last_used"])).total_seconds())
assert diff < 60
# Clean up
httpx.delete(f"{URL}/api/v1/spool/{spool['id']}").raise_for_status()
@pytest.mark.parametrize("use_length", [0, 10, -10, 500e3]) # 500e3 is big enough to use all the filament
def test_use_spool_length(random_filament: dict[str, Any], use_length: float):
"""Test using a spool in the database."""
# Setup
filament_net_weight = random_filament["weight"]
start_weight = 1000
result = httpx.post(
f"{URL}/api/v1/spool",
json={
"filament_id": random_filament["id"],
"remaining_weight": start_weight,
"first_used": "2023-01-01T00:00:00Z",
},
)
result.raise_for_status()
spool = result.json()
# Execute
result = httpx.put(
f"{URL}/api/v1/spool/{spool['id']}/use",
json={
"use_length": use_length,
},
)
result.raise_for_status()
# Verify
spool = result.json()
use_weight = (
random_filament["density"] * (use_length * 1e-1) * math.pi * ((random_filament["diameter"] * 1e-1 / 2) ** 2)
)
# remaining_weight should be clamped so it's never negative, but used_weight should not be clamped to the net weight
assert spool["used_weight"] == pytest.approx(max(use_weight, 0))
assert spool["remaining_weight"] == pytest.approx(min(max(start_weight - use_weight, 0), filament_net_weight))
# Verify that first_used hasn't been updated since it was already set
assert spool["first_used"] == "2023-01-01T00:00:00Z"
# Verify that last_used has been updated
diff = abs((datetime.now(tz=timezone.utc) - datetime.fromisoformat(spool["last_used"])).total_seconds())
assert diff < 60
# Clean up
httpx.delete(f"{URL}/api/v1/spool/{spool['id']}").raise_for_status()
def test_use_spool_weight_and_length(random_filament: dict[str, Any]):
"""Test using a spool in the database."""
# Setup
result = httpx.post(
f"{URL}/api/v1/spool",
json={"filament_id": random_filament["id"]},
)
result.raise_for_status()
spool = result.json()
# Execute
result = httpx.put(
f"{URL}/api/v1/spool/{spool['id']}/use",
json={
"use_weight": 0.05,
"use_length": 10,
},
)
assert result.status_code == 400 # Cannot use both weight and length
# Clean up
httpx.delete(f"{URL}/api/v1/spool/{spool['id']}").raise_for_status()
def test_use_spool_not_found():
"""Test using a spool that does not exist."""
# Execute
result = httpx.put(
f"{URL}/api/v1/spool/123456789/use",
json={"use_weight": 0.05},
)
assert result.status_code == 404
message = result.json()["message"].lower()
assert "spool" in message
assert "id" in message
assert "123456789" in message
@pytest.mark.asyncio
async def test_use_spool_concurrent(random_filament: dict[str, Any]):
"""Test using a spool with many concurrent requests."""
# Setup
start_weight = 1000
result = httpx.post(
f"{URL}/api/v1/spool",
json={
"filament_id": random_filament["id"],
"remaining_weight": start_weight,
},
)
result.raise_for_status()
spool = result.json()
# Execute
requests = 100
used_weight = 0.5
async with httpx.AsyncClient() as client:
await asyncio.gather(
*(
client.put(
f"{URL}/api/v1/spool/{spool['id']}/use",
json={
"use_weight": used_weight,
},
timeout=60,
)
for _ in range(requests)
),
)
# Verify
result = httpx.get(f"{URL}/api/v1/spool/{spool['id']}")
result.raise_for_status()
spool = result.json()
assert spool["remaining_weight"] == pytest.approx(start_weight - (used_weight * requests))
# Clean up
httpx.delete(f"{URL}/api/v1/spool/{spool['id']}").raise_for_status()