/
/
/
1"""Unit tests for the config dry-run differ."""
2
3from __future__ import annotations
4
5from music_assistant_models.config_entries import ConfigEntry
6from music_assistant_models.constants import SECURE_STRING_SUBSTITUTE
7from music_assistant_models.enums import ConfigEntryType
8
9from music_assistant.providers.fastmcp_server.config_io.differ import compute_diff
10
11
12def _entries() -> dict[str, ConfigEntry]:
13 return {
14 "log_level": ConfigEntry(key="log_level", type=ConfigEntryType.STRING, label="L"),
15 "token": ConfigEntry(key="token", type=ConfigEntryType.SECURE_STRING, label="T"),
16 }
17
18
19def test_diff_computes_before_after_per_key() -> None:
20 """Test that diff records before/after per key for non-secret values."""
21 diff = compute_diff(
22 target_type="provider",
23 target_id="p1",
24 entries=_entries(),
25 current={"log_level": "INFO"},
26 proposed={"log_level": "DEBUG"},
27 )
28 assert diff.target_type == "provider"
29 change = next(c for c in diff.changes if c.key == "log_level")
30 assert change.before == "INFO"
31 assert change.after == "DEBUG"
32 assert change.secret is False
33
34
35def test_diff_masks_secret_values_both_sides() -> None:
36 """Test that secret values are masked on both before and after sides."""
37 diff = compute_diff(
38 target_type="provider",
39 target_id="p1",
40 entries=_entries(),
41 current={"token": "old-secret"},
42 proposed={"token": "new-secret"},
43 )
44 change = next(c for c in diff.changes if c.key == "token")
45 assert change.secret is True
46 assert change.before == SECURE_STRING_SUBSTITUTE
47 assert change.after == SECURE_STRING_SUBSTITUTE
48 assert "old-secret" not in str(diff)
49 assert "new-secret" not in str(diff)
50