test_bulk_edit_dispatch_claim.py 2.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758
  1. """Bulk edit leaves a row a dispatch claimed during the edit (DM/BULK).
  2. The bulk edit checked the claim on the rows it loaded, then awaited cost and
  3. budget checks per row before changing it. A row the scheduler claimed for
  4. dispatch in between was changed anyway, so its printer or cost centre no
  5. longer matched the upload already under way.
  6. """
  7. from datetime import datetime, timezone
  8. from unittest.mock import AsyncMock, patch
  9. import pytest
  10. from sqlalchemy import update
  11. from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker
  12. from backend.app.models.finance import CostCenter
  13. from backend.app.models.print_queue import PrintQueueItem
  14. pytestmark = [pytest.mark.asyncio, pytest.mark.integration]
  15. async def test_a_row_claimed_during_the_edit_is_skipped(
  16. async_client, db_session, test_engine, printer_factory, archive_factory
  17. ):
  18. printer = await printer_factory()
  19. other_printer = await printer_factory(name="Other")
  20. archive = await archive_factory(printer.id)
  21. center = CostCenter(name="Lab", is_active=True, is_private=False)
  22. db_session.add(center)
  23. claimed = PrintQueueItem(printer_id=printer.id, archive_id=archive.id, status="pending", target_model="X1C")
  24. free = PrintQueueItem(printer_id=printer.id, archive_id=archive.id, status="pending")
  25. db_session.add_all([claimed, free])
  26. await db_session.commit()
  27. other = async_sessionmaker(test_engine, class_=AsyncSession, expire_on_commit=False)
  28. async def dispatch_claims(*_args, exclude_queue_item_id=None, **_kwargs):
  29. if exclude_queue_item_id == claimed.id:
  30. async with other() as db:
  31. await db.execute(
  32. update(PrintQueueItem)
  33. .where(PrintQueueItem.id == claimed.id)
  34. .values(dispatching_at=datetime.now(timezone.utc))
  35. )
  36. await db.commit()
  37. with patch("backend.app.api.routes.print_queue.validate_print_budget", AsyncMock(side_effect=dispatch_claims)):
  38. response = await async_client.patch(
  39. "/api/v1/queue/bulk",
  40. json={"item_ids": [claimed.id, free.id], "cost_center_id": center.id, "printer_id": other_printer.id},
  41. )
  42. assert response.status_code == 200, response.text
  43. assert (response.json()["updated_count"], response.json()["skipped_count"]) == (1, 1)
  44. async with other() as db:
  45. claimed_row = await db.get(PrintQueueItem, claimed.id)
  46. free_row = await db.get(PrintQueueItem, free.id)
  47. assert (claimed_row.printer_id, claimed_row.cost_center_id, claimed_row.target_model) == (printer.id, None, "X1C")
  48. assert (free_row.printer_id, free_row.cost_center_id) == (other_printer.id, center.id)