test_queue_item_printer_change.py 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. """A queued job moved to another printer leaves the old printer's settings behind."""
  2. from __future__ import annotations
  3. import json
  4. import pytest
  5. from httpx import AsyncClient
  6. from sqlalchemy import select
  7. from backend.app.models.print_queue import PrintQueueItem, PrintQueueVariant
  8. pytestmark = [pytest.mark.asyncio, pytest.mark.integration]
  9. RESOLVED_FOR_A = {
  10. "ams_mapping": "[2]",
  11. "skip_filament_check": True,
  12. "nozzle_mapping": json.dumps([1]),
  13. "nozzle_rack_choice": json.dumps({"0": 3}),
  14. }
  15. async def _item(db_session, printer_id: int, archive_id: int, **extra) -> int:
  16. item = PrintQueueItem(
  17. printer_id=printer_id,
  18. archive_id=archive_id,
  19. status="pending",
  20. position=1,
  21. plate_id=2,
  22. use_ams=False,
  23. **{**RESOLVED_FOR_A, **extra},
  24. )
  25. db_session.add(item)
  26. await db_session.commit()
  27. return item.id
  28. async def _row(db_session, item_id: int) -> PrintQueueItem:
  29. db_session.expire_all()
  30. return await db_session.get(PrintQueueItem, item_id)
  31. def _resolved(item: PrintQueueItem) -> tuple:
  32. return item.ams_mapping, item.skip_filament_check, item.nozzle_mapping, item.nozzle_rack_choice
  33. async def test_a_bulk_move_drops_what_was_worked_out_for_the_old_printer(
  34. async_client: AsyncClient, db_session, printer_factory, archive_factory
  35. ):
  36. a, b = await printer_factory(name="A"), await printer_factory(name="B")
  37. a_id, b_id = a.id, b.id
  38. archive_id = (await archive_factory(a_id)).id
  39. moved = await _item(db_session, a_id, archive_id)
  40. stays = await _item(db_session, b_id, archive_id)
  41. model_job = await _item(db_session, a_id, archive_id, target_model="X1C", target_location="Lab")
  42. response = await async_client.patch(
  43. "/api/v1/queue/bulk", json={"item_ids": [moved, stays, model_job], "printer_id": b_id}
  44. )
  45. assert response.status_code == 200, response.text
  46. item = await _row(db_session, moved)
  47. assert item.printer_id == b_id
  48. assert _resolved(item) == (None, False, None, None)
  49. assert (item.plate_id, item.use_ams) == (2, False)
  50. assert _resolved(await _row(db_session, stays)) == tuple(RESOLVED_FOR_A.values())
  51. pinned = await _row(db_session, model_job)
  52. assert (pinned.printer_id, pinned.target_model, pinned.target_location) == (b_id, None, None)
  53. async def test_a_bulk_move_leaves_jobs_with_printer_alternatives_alone(
  54. async_client: AsyncClient, db_session, printer_factory, archive_factory
  55. ):
  56. a, b = await printer_factory(name="A"), await printer_factory(name="B")
  57. a_id, b_id = a.id, b.id
  58. archive_id = (await archive_factory(a_id)).id
  59. item_id = await _item(db_session, a_id, archive_id, target_model="X1C")
  60. from backend.app.models.library import LibraryFile
  61. file = LibraryFile(filename="part.3mf", file_path="part.3mf", file_type="3mf", file_size=1)
  62. db_session.add(file)
  63. await db_session.flush()
  64. db_session.add(PrintQueueVariant(queue_item_id=item_id, position=0, target_model="X1C", library_file_id=file.id))
  65. await db_session.commit()
  66. response = await async_client.patch("/api/v1/queue/bulk", json={"item_ids": [item_id], "printer_id": b_id})
  67. assert response.json()["skipped_count"] == 1
  68. assert (await _row(db_session, item_id)).printer_id == a_id
  69. async def test_editing_a_job_onto_another_printer_keeps_only_what_was_sent_for_it(
  70. async_client: AsyncClient, db_session, printer_factory, archive_factory
  71. ):
  72. a, b = await printer_factory(name="A"), await printer_factory(name="B")
  73. a_id, b_id = a.id, b.id
  74. archive_id = (await archive_factory(a_id)).id
  75. item_id = await _item(db_session, a_id, archive_id)
  76. # What the edit dialog sends: the new printer's mapping, no Print Anyway.
  77. response = await async_client.patch(f"/api/v1/queue/{item_id}", json={"printer_id": b_id, "ams_mapping": [5]})
  78. assert response.status_code == 200, response.text
  79. item = await _row(db_session, item_id)
  80. assert _resolved(item) == ("[5]", False, None, None)
  81. async def test_editing_a_job_on_the_same_printer_keeps_its_settings(
  82. async_client: AsyncClient, db_session, printer_factory, archive_factory
  83. ):
  84. a = await printer_factory(name="A")
  85. a_id = a.id
  86. archive_id = (await archive_factory(a_id)).id
  87. item_id = await _item(db_session, a_id, archive_id)
  88. response = await async_client.patch(f"/api/v1/queue/{item_id}", json={"printer_id": a_id})
  89. assert response.status_code == 200, response.text
  90. assert _resolved(await _row(db_session, item_id)) == tuple(RESOLVED_FOR_A.values())
  91. async def test_copies_of_a_model_job_wait_for_any_printer_of_the_model(
  92. async_client: AsyncClient, db_session, printer_factory, archive_factory
  93. ):
  94. from backend.tests.integration.test_print_batch_orders import _create_order
  95. a = await printer_factory(name="A", model="X1C")
  96. a_id = a.id
  97. archive_id = (await archive_factory(a_id)).id
  98. order = await _create_order(async_client, archive_id, [{"plate_id": 2, "quantity_target": 3}])
  99. # Run 1 as the scheduler leaves it: its model, the printer it picked, and
  100. # what it worked out for that printer.
  101. source_id = await _item(db_session, a_id, archive_id, target_model="X1C", batch_id=order["id"])
  102. response = await async_client.post(f"/api/v1/queue/batches/{order['id']}/dispatch", json={})
  103. assert response.status_code == 200, response.text
  104. db_session.expire_all()
  105. copies = (
  106. (
  107. await db_session.execute(
  108. select(PrintQueueItem)
  109. .where(PrintQueueItem.batch_id == order["id"])
  110. .where(PrintQueueItem.id != source_id)
  111. )
  112. )
  113. .scalars()
  114. .all()
  115. )
  116. assert copies
  117. for copy in copies:
  118. assert (copy.printer_id, copy.target_model) == (None, "X1C")
  119. assert _resolved(copy) == (None, False, None, None)
  120. assert (copy.plate_id, copy.use_ams) == (2, False)