Backend now fully supports negative consumption

Updated integration tests to verify this.
This commit is contained in:
Donkie
2023-07-08 20:07:32 +02:00
parent 746b891703
commit 936b11de24
2 changed files with 23 additions and 11 deletions

View File

@@ -4,6 +4,7 @@ from datetime import datetime, timezone
from typing import Optional from typing import Optional
import sqlalchemy import sqlalchemy
from sqlalchemy import case
from sqlalchemy.exc import NoResultFound from sqlalchemy.exc import NoResultFound
from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.orm import contains_eager, joinedload from sqlalchemy.orm import contains_eager, joinedload
@@ -149,7 +150,12 @@ async def use_weight_safe(db: AsyncSession, spool_id: int, weight: float) -> Non
await db.execute( await db.execute(
sqlalchemy.update(models.Spool) sqlalchemy.update(models.Spool)
.where(models.Spool.id == spool_id) .where(models.Spool.id == spool_id)
.values(used_weight=models.Spool.used_weight + weight), .values(
used_weight=case(
(models.Spool.used_weight + weight >= 0.0, models.Spool.used_weight + weight), # noqa: PLR2004
else_=0.0, # Set used_weight to 0 if the result would be negative
),
),
) )

View File

@@ -440,9 +440,11 @@ def test_update_spool_not_found(random_filament: dict[str, Any]):
assert "123456789" in message assert "123456789" in message
def test_use_spool_weight(random_filament: dict[str, Any]): @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.""" """Test using a spool in the database."""
# Setup # Setup
filament_net_weight = random_filament["weight"]
start_weight = 1000 start_weight = 1000
result = httpx.post( result = httpx.post(
f"{URL}/api/v1/spool", f"{URL}/api/v1/spool",
@@ -455,26 +457,29 @@ def test_use_spool_weight(random_filament: dict[str, Any]):
spool = result.json() spool = result.json()
# Execute # Execute
used_weight = 0.05
result = httpx.put( result = httpx.put(
f"{URL}/api/v1/spool/{spool['id']}/use", f"{URL}/api/v1/spool/{spool['id']}/use",
json={ json={
"use_weight": used_weight, "use_weight": use_weight,
}, },
) )
result.raise_for_status() result.raise_for_status()
# Verify # Verify
spool = result.json() spool = result.json()
assert spool["remaining_weight"] == pytest.approx(start_weight - used_weight) # 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))
# Clean up # Clean up
httpx.delete(f"{URL}/api/v1/spool/{spool['id']}").raise_for_status() httpx.delete(f"{URL}/api/v1/spool/{spool['id']}").raise_for_status()
def test_use_spool_length(random_filament: dict[str, Any]): @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.""" """Test using a spool in the database."""
# Setup # Setup
filament_net_weight = random_filament["weight"]
start_weight = 1000 start_weight = 1000
result = httpx.post( result = httpx.post(
f"{URL}/api/v1/spool", f"{URL}/api/v1/spool",
@@ -487,21 +492,22 @@ def test_use_spool_length(random_filament: dict[str, Any]):
spool = result.json() spool = result.json()
# Execute # Execute
used_length = 10 # mm
result = httpx.put( result = httpx.put(
f"{URL}/api/v1/spool/{spool['id']}/use", f"{URL}/api/v1/spool/{spool['id']}/use",
json={ json={
"use_length": used_length, "use_length": use_length,
}, },
) )
result.raise_for_status() result.raise_for_status()
# Verify # Verify
spool = result.json() spool = result.json()
used_weight = ( use_weight = (
random_filament["density"] * (used_length * 1e-1) * math.pi * ((random_filament["diameter"] * 1e-1 / 2) ** 2) random_filament["density"] * (use_length * 1e-1) * math.pi * ((random_filament["diameter"] * 1e-1 / 2) ** 2)
) )
assert spool["remaining_weight"] == pytest.approx(start_weight - used_weight) # 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))
# Clean up # Clean up
httpx.delete(f"{URL}/api/v1/spool/{spool['id']}").raise_for_status() httpx.delete(f"{URL}/api/v1/spool/{spool['id']}").raise_for_status()