/
/
/
1"""
2Benchmarks for hot-path string/parsing helpers.
3
4These helpers run on every media item during library sync, matching and metadata
5parsing, so they sit squarely on the performance-critical path. They are pure,
6CPU-bound functions, which makes them a good fit for CodSpeed's deterministic
7simulation instrument.
8"""
9
10from __future__ import annotations
11
12from typing import TYPE_CHECKING
13
14from music_assistant_models.helpers import create_safe_string
15
16from music_assistant.helpers.compare import (
17 compare_strings,
18 compare_version,
19 loose_compare_strings,
20)
21from music_assistant.helpers.json import json_dumps, json_loads
22from music_assistant.helpers.util import (
23 clean_stream_title,
24 parse_title_and_version,
25 sanitize_http_header_value,
26)
27
28if TYPE_CHECKING:
29 from pytest_codspeed import BenchmarkFixture
30
31# A representative mix of real-world track/album titles as they arrive from
32# streaming providers: plain titles, featurings, remaster suffixes, bracketed
33# version info and accented / non-ASCII characters.
34SAMPLE_TITLES = [
35 "Bohemian Rhapsody",
36 "Blinding Lights (Official Music Video)",
37 "Smells Like Teen Spirit - Remastered 2021",
38 "One More Time (feat. Romanthony)",
39 "Björk - Jóga",
40 "Take On Me [Extended Version]",
41 "Stairway to Heaven (Live at MSG)",
42 "Get Lucky (Radio Edit) [feat. Pharrell Williams]",
43 "Numb / Encore",
44 "SÃ, señor - Acoustic",
45]
46
47SAMPLE_VERSIONS = [
48 ("Remastered 2011", "2011 Remaster"),
49 ("Deluxe Edition", "Deluxe"),
50 ("", "original soundtrack"),
51 ("Radio Edit", "radio version"),
52 ("Live", "Live Version"),
53]
54
55SAMPLE_STREAM_TITLES = [
56 "StreamTitle='AC/DC - Thunderstruck';StreamUrl='';",
57 'text="Daft Punk - Around the World" song_spot="M"',
58 "The Beatles - Here Comes the Sun",
59 'title="Adele - Hello" artist="Adele"',
60 "Now playing: Coldplay - Yellow on Radio X - advert.com",
61]
62
63
64def test_compare_strings_strict(benchmark: BenchmarkFixture) -> None:
65 """Exact (strict) string comparison across the sample title set."""
66
67 def run() -> int:
68 matches = 0
69 for base in SAMPLE_TITLES:
70 for alt in SAMPLE_TITLES:
71 if compare_strings(base, alt, strict=True):
72 matches += 1
73 return matches
74
75 benchmark(run)
76
77
78def test_compare_strings_fuzzy(benchmark: BenchmarkFixture) -> None:
79 """Fuzzy string comparison (difflib path) across the sample title set."""
80
81 def run() -> int:
82 matches = 0
83 for base in SAMPLE_TITLES:
84 for alt in SAMPLE_TITLES:
85 if compare_strings(base, alt, strict=False):
86 matches += 1
87 return matches
88
89 benchmark(run)
90
91
92def test_create_safe_string(benchmark: BenchmarkFixture) -> None:
93 """Unicode normalization + regex cleanup used before every compare."""
94
95 def run() -> list[str]:
96 return [create_safe_string(title) for title in SAMPLE_TITLES]
97
98 benchmark(run)
99
100
101def test_loose_compare_strings(benchmark: BenchmarkFixture) -> None:
102 """Partial-match comparison used to group versions of the same item."""
103
104 def run() -> int:
105 matches = 0
106 for base in SAMPLE_TITLES:
107 for alt in SAMPLE_TITLES:
108 if loose_compare_strings(base, alt):
109 matches += 1
110 return matches
111
112 benchmark(run)
113
114
115def test_compare_version(benchmark: BenchmarkFixture) -> None:
116 """Version string comparison across a mix of representative pairs."""
117
118 def run() -> int:
119 return sum(compare_version(base, alt) for base, alt in SAMPLE_VERSIONS)
120
121 benchmark(run)
122
123
124def test_parse_title_and_version(benchmark: BenchmarkFixture) -> None:
125 """Standard title/version splitting run on every parsed media item."""
126
127 def run() -> list[tuple[str, str]]:
128 return [parse_title_and_version(title) for title in SAMPLE_TITLES]
129
130 benchmark(run)
131
132
133def test_parse_title_and_version_for_search(benchmark: BenchmarkFixture) -> None:
134 """Aggressive title stripping used to build search queries."""
135
136 def run() -> list[tuple[str, str]]:
137 return [parse_title_and_version(title, strip_for_search=True) for title in SAMPLE_TITLES]
138
139 benchmark(run)
140
141
142def test_clean_stream_title(benchmark: BenchmarkFixture) -> None:
143 """Radio StreamTitle parsing, executed for every ICY metadata update."""
144
145 def run() -> list[str]:
146 return [clean_stream_title(line) for line in SAMPLE_STREAM_TITLES]
147
148 benchmark(run)
149
150
151def test_sanitize_http_header_value(benchmark: BenchmarkFixture) -> None:
152 """Header sanitization applied to track metadata on every stream request."""
153
154 def run() -> list[str]:
155 return [sanitize_http_header_value(title) for title in SAMPLE_TITLES]
156
157 benchmark(run)
158
159
160def test_json_dumps(benchmark: BenchmarkFixture) -> None:
161 """orjson-backed serialization used across the API and cache layers."""
162 payload = {
163 "items": [
164 {
165 "item_id": str(idx),
166 "name": title,
167 "provider": "spotify",
168 "media_type": "track",
169 "duration": 180 + idx,
170 "artists": ["Some Artist", "Another Artist"],
171 "metadata": {"explicit": bool(idx % 2), "popularity": idx * 3},
172 }
173 for idx, title in enumerate(SAMPLE_TITLES)
174 ]
175 }
176
177 benchmark(lambda: json_dumps(payload))
178
179
180def test_json_loads(benchmark: BenchmarkFixture) -> None:
181 """orjson-backed deserialization of a representative API payload."""
182 payload = {
183 "items": [
184 {
185 "item_id": str(idx),
186 "name": title,
187 "provider": "spotify",
188 "media_type": "track",
189 "duration": 180 + idx,
190 }
191 for idx, title in enumerate(SAMPLE_TITLES)
192 ]
193 }
194 raw = json_dumps(payload)
195
196 benchmark(lambda: json_loads(raw))
197