test_print_log_plate_backfill.py 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. """Older print log runs get the plate they printed where it is known.
  2. Runs are now written with their plate. For runs written before, it is the
  3. plate of the queue item that ran them, or the archive's when the run is that
  4. archive's only one. A run of a reprinted archive with no queue item stays
  5. NULL: the archive's plate need not be the one that run printed.
  6. """
  7. import pytest
  8. from sqlalchemy import select
  9. from sqlalchemy.ext.asyncio import async_sessionmaker, create_async_engine
  10. import backend.app.models # noqa: F401 - populate Base.metadata
  11. from backend.app.core.database import Base, _backfill_print_log_plate_ids
  12. from backend.app.models.archive import PrintArchive
  13. from backend.app.models.print_log import PrintLogEntry
  14. from backend.app.models.print_queue import PrintQueueItem
  15. from backend.app.models.printer import Printer
  16. @pytest.mark.asyncio
  17. async def test_older_runs_get_their_plate_where_it_is_known():
  18. engine = create_async_engine("sqlite+aiosqlite:///:memory:", echo=False)
  19. try:
  20. async with engine.begin() as conn:
  21. await conn.run_sync(Base.metadata.create_all)
  22. maker = async_sessionmaker(engine, expire_on_commit=False)
  23. async with maker() as db:
  24. printer = Printer(name="P", serial_number="S", ip_address="127.0.0.1", access_code="c", model="X1C")
  25. single = PrintArchive(filename="a.3mf", file_path="a", file_size=1, status="completed", plate_id=2)
  26. reprinted = PrintArchive(filename="b.3mf", file_path="b", file_size=1, status="completed", plate_id=5)
  27. db.add_all([printer, single, reprinted])
  28. await db.flush()
  29. queued = PrintQueueItem(printer_id=printer.id, archive_id=reprinted.id, status="completed", plate_id=4)
  30. db.add(queued)
  31. await db.flush()
  32. runs = {
  33. "queued": PrintLogEntry(archive_id=reprinted.id, queue_item_id=queued.id, status="completed"),
  34. "reprinted": PrintLogEntry(archive_id=reprinted.id, status="completed"),
  35. "single": PrintLogEntry(archive_id=single.id, status="completed"),
  36. "known": PrintLogEntry(archive_id=single.id, status="failed", plate_id=1, queue_item_id=queued.id),
  37. "orphan": PrintLogEntry(archive_id=None, status="completed"),
  38. }
  39. db.add_all(runs.values())
  40. await db.commit()
  41. ids = {name: run.id for name, run in runs.items()}
  42. for _ in range(2): # every start runs it; the second changes nothing
  43. async with engine.begin() as conn:
  44. await _backfill_print_log_plate_ids(conn)
  45. async with maker() as db:
  46. plates = dict((await db.execute(select(PrintLogEntry.id, PrintLogEntry.plate_id))).tuples().all())
  47. assert {name: plates[run_id] for name, run_id in ids.items()} == {
  48. "queued": 4,
  49. "reprinted": None,
  50. # Two runs on the archive now, one of them already known: the
  51. # archive's plate is not taken for the other.
  52. "single": None,
  53. "known": 1,
  54. "orphan": None,
  55. }
  56. finally:
  57. await engine.dispose()
  58. @pytest.mark.asyncio
  59. async def test_the_only_run_of_an_archive_gets_the_archives_plate():
  60. engine = create_async_engine("sqlite+aiosqlite:///:memory:", echo=False)
  61. try:
  62. async with engine.begin() as conn:
  63. await conn.run_sync(Base.metadata.create_all)
  64. maker = async_sessionmaker(engine, expire_on_commit=False)
  65. async with maker() as db:
  66. archive = PrintArchive(filename="a.3mf", file_path="a", file_size=1, status="completed", plate_id=2)
  67. db.add(archive)
  68. await db.flush()
  69. run = PrintLogEntry(archive_id=archive.id, status="completed")
  70. db.add(run)
  71. await db.commit()
  72. async with engine.begin() as conn:
  73. await _backfill_print_log_plate_ids(conn)
  74. async with maker() as db:
  75. assert await db.scalar(select(PrintLogEntry.plate_id).where(PrintLogEntry.id == run.id)) == 2
  76. finally:
  77. await engine.dispose()
  78. @pytest.mark.asyncio
  79. async def test_it_runs_once():
  80. """A later dispatch moves the archive's plate to its own run's before
  81. that run is logged; a second pass would give it to the old run."""
  82. engine = create_async_engine("sqlite+aiosqlite:///:memory:", echo=False)
  83. try:
  84. async with engine.begin() as conn:
  85. await conn.run_sync(Base.metadata.create_all)
  86. async with engine.begin() as conn:
  87. await _backfill_print_log_plate_ids(conn) # the first start: nothing to do
  88. maker = async_sessionmaker(engine, expire_on_commit=False)
  89. async with maker() as db:
  90. archive = PrintArchive(filename="a.3mf", file_path="a", file_size=1, status="printing", plate_id=2)
  91. db.add(archive)
  92. await db.flush()
  93. run = PrintLogEntry(archive_id=archive.id, status="completed")
  94. db.add(run)
  95. await db.commit()
  96. async with engine.begin() as conn:
  97. await _backfill_print_log_plate_ids(conn)
  98. async with maker() as db:
  99. assert await db.scalar(select(PrintLogEntry.plate_id).where(PrintLogEntry.id == run.id)) is None
  100. finally:
  101. await engine.dispose()