|
|
@@ -3888,6 +3888,10 @@ class TestSetFanSpeedAPI:
|
|
|
printer = await printer_factory(name="P", model="X1C")
|
|
|
mock_client = MagicMock()
|
|
|
mock_client.set_fan_speed.return_value = True
|
|
|
+ # aux2 is presence-gated on the printer reporting airduct part 10, so
|
|
|
+ # give the mock a reported speed. Set explicitly rather than leaning on
|
|
|
+ # MagicMock's auto-attribute, which would satisfy the gate by accident.
|
|
|
+ mock_client.state.left_aux_fan_speed = 0
|
|
|
with patch("backend.app.api.routes.printers.printer_manager") as mock_pm:
|
|
|
mock_pm.get_client.return_value = mock_client
|
|
|
response = await async_client.post(f"/api/v1/printers/{printer.id}/fan-speed?fan={fan_name}&speed=100")
|
|
|
@@ -3895,6 +3899,39 @@ class TestSetFanSpeedAPI:
|
|
|
called_fan_id, called_pwm = mock_client.set_fan_speed.call_args.args
|
|
|
assert called_fan_id == expected_fan_id
|
|
|
|
|
|
+ @pytest.mark.asyncio
|
|
|
+ @pytest.mark.integration
|
|
|
+ async def test_aux2_rejected_when_printer_has_no_left_aux_fan(self, async_client: AsyncClient, printer_factory):
|
|
|
+ """A printer that never reports airduct part 10 must not be sent M106 P10.
|
|
|
+
|
|
|
+ Without the gate the endpoint accepted aux2 for every model, so a POST
|
|
|
+ against an A1 would fire a command for hardware that does not exist.
|
|
|
+ """
|
|
|
+ printer = await printer_factory(name="P", model="A1")
|
|
|
+ mock_client = MagicMock()
|
|
|
+ mock_client.set_fan_speed.return_value = True
|
|
|
+ mock_client.state.left_aux_fan_speed = None
|
|
|
+ with patch("backend.app.api.routes.printers.printer_manager") as mock_pm:
|
|
|
+ mock_pm.get_client.return_value = mock_client
|
|
|
+ response = await async_client.post(f"/api/v1/printers/{printer.id}/fan-speed?fan=aux2&speed=50")
|
|
|
+ assert response.status_code == 400
|
|
|
+ assert "left auxiliary fan" in response.json()["detail"]
|
|
|
+ mock_client.set_fan_speed.assert_not_called()
|
|
|
+
|
|
|
+ @pytest.mark.asyncio
|
|
|
+ @pytest.mark.integration
|
|
|
+ async def test_other_fans_unaffected_by_the_aux2_gate(self, async_client: AsyncClient, printer_factory):
|
|
|
+ """The gate is aux2-only — a base P2S can still drive its built-in fans."""
|
|
|
+ printer = await printer_factory(name="P", model="P2S")
|
|
|
+ mock_client = MagicMock()
|
|
|
+ mock_client.set_fan_speed.return_value = True
|
|
|
+ mock_client.state.left_aux_fan_speed = None
|
|
|
+ with patch("backend.app.api.routes.printers.printer_manager") as mock_pm:
|
|
|
+ mock_pm.get_client.return_value = mock_client
|
|
|
+ for fan_name in ("part", "aux", "chamber"):
|
|
|
+ response = await async_client.post(f"/api/v1/printers/{printer.id}/fan-speed?fan={fan_name}&speed=50")
|
|
|
+ assert response.status_code == 200, fan_name
|
|
|
+
|
|
|
@pytest.mark.asyncio
|
|
|
@pytest.mark.integration
|
|
|
@pytest.mark.parametrize(
|