/
/
/
1"""End-to-end tests for the CONFIG_WRITE_PLAYER tool group."""
2# ruff: noqa: D103
3# D103: test functions don't need docstrings.
4# PLC0415: mock reconfiguration inside test bodies requires deferred imports.
5
6from __future__ import annotations
7
8from typing import Any
9
10import pytest
11from fastmcp import Client
12from fastmcp.exceptions import ToolError
13
14
15async def test_set_player_value_persists(mounted_config: Any, mock_config_targets: Any) -> None:
16 async with Client(mounted_config) as client:
17 result = await client.call_tool(
18 "config_set_player_value",
19 {"player_id": "kitchen", "key": "log_level", "value": "DEBUG"},
20 )
21 mock_config_targets.config.save_player_config.assert_awaited_once()
22 assert result.data.applied is True
23
24
25async def test_save_player_bulk_persists(mounted_config: Any, mock_config_targets: Any) -> None:
26 async with Client(mounted_config) as client:
27 result = await client.call_tool(
28 "config_save_player",
29 {"player_id": "kitchen", "values": {"log_level": "DEBUG", "http_port": 8095}},
30 )
31 mock_config_targets.config.save_player_config.assert_awaited_once()
32 assert result.data.applied is True
33
34
35async def test_save_dsp_persists(mounted_config: Any, mock_config_targets: Any) -> None:
36 async with Client(mounted_config) as client:
37 result = await client.call_tool(
38 "config_save_dsp",
39 {
40 "player_id": "kitchen",
41 "dsp": {"enabled": True, "input_gain": 0.0, "output_gain": 0.0, "filters": []},
42 },
43 )
44 mock_config_targets.config.save_dsp_config.assert_awaited_once()
45 assert result.data.applied is True
46
47
48async def test_save_dsp_dry_run_no_persist(mounted_config: Any, mock_config_targets: Any) -> None:
49 async with Client(mounted_config) as client:
50 result = await client.call_tool(
51 "config_save_dsp",
52 {
53 "player_id": "kitchen",
54 "dsp": {"enabled": True, "input_gain": 0.0, "output_gain": 0.0, "filters": []},
55 "dry_run": True,
56 },
57 )
58 assert result.data.applied is False
59 mock_config_targets.config.save_dsp_config.assert_not_called()
60
61
62async def test_save_player_payload_over_64kb_rejected(
63 mounted_config: Any,
64 mock_config_targets: Any, # noqa: ARG001
65) -> None:
66 big = {"log_level": "x" * (65 * 1024)}
67 async with Client(mounted_config) as client:
68 with pytest.raises(ToolError, match="64 KB"):
69 await client.call_tool("config_save_player", {"player_id": "kitchen", "values": big})
70
71
72async def test_save_dsp_invalid_payload_rejected(
73 mounted_config: Any,
74 mock_config_targets: Any, # noqa: ARG001
75) -> None:
76 # input_gain way out of DSPConfig's -60..60 range â DSPConfig.from_dict or
77 # .validate() should surface as ToolError (not a raw exception).
78 async with Client(mounted_config) as client:
79 with pytest.raises(ToolError):
80 await client.call_tool(
81 "config_save_dsp",
82 {"player_id": "kitchen", "dsp": {"enabled": True, "input_gain": 999.0}},
83 )
84