| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126 |
- """Preserved built-in assignments must stay preserved (#2812).
- The mode toggle no longer deletes them. That is only worth anything if the rest
- of the app leaves them alone while Spoolman mode is active — otherwise they are
- destroyed just as completely, only more slowly.
- The auto-unlink pass in ``on_ams_change`` is the one that matters: it ends in
- ``db.delete`` for every assignment whose slot no longer matches the fingerprint
- it recorded, which is precisely what happens once the user starts loading
- different filament under the other mode.
- """
- from unittest.mock import AsyncMock, MagicMock, patch
- import pytest
- from httpx import AsyncClient
- from sqlalchemy import select
- from sqlalchemy.ext.asyncio import AsyncSession
- from backend.app.models.settings import Settings
- from backend.app.models.spool import Spool
- from backend.app.models.spool_assignment import SpoolAssignment
- def _status(ams_data):
- status = MagicMock()
- status.raw_data = {"ams": ams_data, "vt_tray": []}
- status.gcode_state = "IDLE"
- return status
- async def _run_ams_change(printer_id: int, ams_data: list):
- from backend.app.main import on_ams_change
- status = _status(ams_data)
- with (
- patch("backend.app.main.printer_manager") as pm_main,
- patch("backend.app.services.printer_manager.printer_manager") as pm_inv,
- patch("backend.app.main.mqtt_relay") as relay,
- patch("backend.app.main.ws_manager") as ws,
- ):
- pm_main.get_printer.return_value = MagicMock(name="P", serial_number="SER")
- pm_main.get_status.return_value = status
- pm_main.get_client.return_value = MagicMock()
- pm_main.get_model.return_value = "X1C"
- pm_inv.get_status.return_value = status
- pm_inv.get_client.return_value = MagicMock()
- relay.on_ams_change = AsyncMock()
- ws.send_printer_status = AsyncMock()
- ws.broadcast = AsyncMock()
- await on_ams_change(printer_id, ams_data)
- class TestAutoUnlinkRespectsTheActiveMode:
- @pytest.mark.asyncio
- @pytest.mark.integration
- async def test_spoolman_mode_does_not_unlink_built_in_assignments(
- self, async_client: AsyncClient, printer_factory, db_session: AsyncSession
- ):
- """The slot now holds something else entirely — a stale fingerprint by
- every measure. In built-in mode that is a genuine unlink. In Spoolman
- mode these rows are the user's preserved configuration, waiting for
- them to switch back, and nothing here is entitled to delete them."""
- printer = await printer_factory(name="P1S")
- spool = Spool(material="PLA", rgba="FF0000FF")
- db_session.add(spool)
- await db_session.flush()
- db_session.add(Settings(key="spoolman_enabled", value="true"))
- db_session.add(
- SpoolAssignment(
- spool_id=spool.id,
- printer_id=printer.id,
- ams_id=0,
- tray_id=0,
- fingerprint_color="FF0000FF",
- fingerprint_type="PLA",
- )
- )
- await db_session.commit()
- await _run_ams_change(
- printer.id,
- [{"id": 0, "tray": [{"id": 0, "tray_type": "PETG", "tray_color": "00FF00FF", "state": 11}]}],
- )
- rows = (
- (await db_session.execute(select(SpoolAssignment).where(SpoolAssignment.printer_id == printer.id)))
- .scalars()
- .all()
- )
- assert len(rows) == 1
- @pytest.mark.asyncio
- @pytest.mark.integration
- async def test_built_in_mode_still_unlinks_a_stale_assignment(
- self, async_client: AsyncClient, printer_factory, db_session: AsyncSession
- ):
- """The guard must not switch the feature off for the mode that owns it."""
- printer = await printer_factory(name="P1S")
- spool = Spool(material="PLA", rgba="FF0000FF")
- db_session.add(spool)
- await db_session.flush()
- db_session.add(Settings(key="spoolman_enabled", value="false"))
- db_session.add(
- SpoolAssignment(
- spool_id=spool.id,
- printer_id=printer.id,
- ams_id=0,
- tray_id=0,
- fingerprint_color="FF0000FF",
- fingerprint_type="PLA",
- )
- )
- await db_session.commit()
- await _run_ams_change(
- printer.id,
- [{"id": 0, "tray": [{"id": 0, "tray_type": "PETG", "tray_color": "00FF00FF", "state": 11}]}],
- )
- rows = (
- (await db_session.execute(select(SpoolAssignment).where(SpoolAssignment.printer_id == printer.id)))
- .scalars()
- .all()
- )
- assert rows == []
|