From 936b11de24d063ee0139fe6130690f30e90799e7 Mon Sep 17 00:00:00 2001 From: Donkie Date: Sat, 8 Jul 2023 20:07:32 +0200 Subject: [PATCH] Backend now fully supports negative consumption Updated integration tests to verify this. --- spoolman/database/spool.py | 8 +++++++- tests_integration/tests/test_spool.py | 26 ++++++++++++++++---------- 2 files changed, 23 insertions(+), 11 deletions(-) diff --git a/spoolman/database/spool.py b/spoolman/database/spool.py index 1681a9b..d1e7c56 100644 --- a/spoolman/database/spool.py +++ b/spoolman/database/spool.py @@ -4,6 +4,7 @@ from datetime import datetime, timezone from typing import Optional import sqlalchemy +from sqlalchemy import case from sqlalchemy.exc import NoResultFound from sqlalchemy.ext.asyncio import AsyncSession 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( sqlalchemy.update(models.Spool) .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 + ), + ), ) diff --git a/tests_integration/tests/test_spool.py b/tests_integration/tests/test_spool.py index 12f9062..d99fba1 100644 --- a/tests_integration/tests/test_spool.py +++ b/tests_integration/tests/test_spool.py @@ -440,9 +440,11 @@ def test_update_spool_not_found(random_filament: dict[str, Any]): 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.""" # Setup + filament_net_weight = random_filament["weight"] start_weight = 1000 result = httpx.post( f"{URL}/api/v1/spool", @@ -455,26 +457,29 @@ def test_use_spool_weight(random_filament: dict[str, Any]): spool = result.json() # Execute - used_weight = 0.05 result = httpx.put( f"{URL}/api/v1/spool/{spool['id']}/use", json={ - "use_weight": used_weight, + "use_weight": use_weight, }, ) result.raise_for_status() # Verify 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 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.""" # Setup + filament_net_weight = random_filament["weight"] start_weight = 1000 result = httpx.post( f"{URL}/api/v1/spool", @@ -487,21 +492,22 @@ def test_use_spool_length(random_filament: dict[str, Any]): spool = result.json() # Execute - used_length = 10 # mm result = httpx.put( f"{URL}/api/v1/spool/{spool['id']}/use", json={ - "use_length": used_length, + "use_length": use_length, }, ) result.raise_for_status() # Verify spool = result.json() - used_weight = ( - random_filament["density"] * (used_length * 1e-1) * math.pi * ((random_filament["diameter"] * 1e-1 / 2) ** 2) + use_weight = ( + 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 httpx.delete(f"{URL}/api/v1/spool/{spool['id']}").raise_for_status()