/
/
/
1"""Tests for the core-module config action contract (config/core/invoke_action)."""
2
3import pytest
4from music_assistant_models.config_entries import ConfigActionResult
5from music_assistant_models.enums import ConfigEntryType
6from music_assistant_models.errors import ActionUnavailable
7
8from music_assistant.controllers.cache.constants import CONF_CLEAR_CACHE
9from music_assistant.mass import MusicAssistant
10
11
12async def test_get_entries_exposes_the_action_button(mass: MusicAssistant) -> None:
13 """The plain options render exposes the action button alongside the server defaults."""
14 entries = await mass.config.get_core_config_entries("cache")
15 by_key = {entry.key: entry for entry in entries}
16 assert by_key[CONF_CLEAR_CACHE].type == ConfigEntryType.ACTION
17 assert "log_level" in by_key
18
19
20async def test_invoke_action_runs_side_effect_and_reports_the_outcome(
21 mass: MusicAssistant,
22) -> None:
23 """Invoking an action runs it and reports its outcome, without re-rendering the form."""
24 await mass.cache.set("some_key", "some_value")
25 assert await mass.cache.get("some_key") == "some_value"
26
27 result = await mass.config.invoke_core_config_action("cache", CONF_CLEAR_CACHE)
28
29 assert await mass.cache.get("some_key") is None
30 assert isinstance(result, ConfigActionResult)
31 assert result.translation_key == f"{CONF_CLEAR_CACHE}.result"
32 assert result.translation_owner == "core.cache"
33 assert result.open_url is None
34
35
36async def test_action_result_message_resolves_from_strings_json(mass: MusicAssistant) -> None:
37 """The result's translation key resolves under its stamped owner to the English text."""
38 result = await mass.config.invoke_core_config_action("cache", CONF_CLEAR_CACHE)
39
40 assert isinstance(result, ConfigActionResult)
41 assert (
42 mass.translations.get_translation(
43 f"config_actions.{result.translation_key}", owner=result.translation_owner
44 )
45 == "The cache has been cleared"
46 )
47
48
49async def test_invoke_unknown_action_raises(mass: MusicAssistant) -> None:
50 """An action a core module does not declare is rejected."""
51 with pytest.raises(ActionUnavailable):
52 await mass.config.invoke_core_config_action("cache", "no_such_action")
53
54
55async def test_invoke_action_on_module_without_actions_raises(mass: MusicAssistant) -> None:
56 """A core module that declares no actions at all falls through to the base handler."""
57 with pytest.raises(ActionUnavailable):
58 await mass.config.invoke_core_config_action("streams", "no_such_action")
59