def subscribe(
self,
cb_func: EventCallBackType,
- event_filter: EventType | tuple[EventType] | None = None,
- id_filter: str | tuple[str] | None = None,
+ event_filter: EventType | tuple[EventType, ...] | None = None,
+ id_filter: str | tuple[str, ...] | None = None,
) -> Callable:
"""Add callback to event listeners.
--- /dev/null
+"""Fixtures for testing Music Assistant."""
+
+import logging
+import pathlib
+from collections.abc import AsyncGenerator
+
+import pytest
+
+from music_assistant.server.server import MusicAssistant
+
+
+@pytest.fixture(name="caplog")
+def caplog_fixture(caplog: pytest.LogCaptureFixture) -> pytest.LogCaptureFixture:
+ """Set log level to debug for tests using the caplog fixture."""
+ caplog.set_level(logging.DEBUG)
+ return caplog
+
+
+@pytest.fixture
+async def mass(tmp_path: pathlib.Path) -> AsyncGenerator[MusicAssistant, None]:
+ """Start a Music Assistant in test mode."""
+ storage_path = tmp_path / "root"
+ storage_path.mkdir(parents=True)
+
+ mass = MusicAssistant(storage_path)
+ await mass.start()
+ try:
+ yield mass
+ finally:
+ await mass.stop()
--- /dev/null
+"""Tests for the core Music Assistant server object."""
+
+import asyncio
+
+from music_assistant.common.models.enums import EventType
+from music_assistant.common.models.event import MassEvent
+from music_assistant.server.server import MusicAssistant
+
+
+async def test_start_and_stop_server(mass: MusicAssistant) -> None:
+ """Test that music assistant starts and stops cleanly."""
+ domains = frozenset(p.domain for p in mass.get_provider_manifests())
+ core_providers = frozenset(
+ ("builtin", "cache", "metadata", "music", "player_queues", "players", "streams")
+ )
+ assert domains.issuperset(core_providers)
+
+
+async def test_events(mass: MusicAssistant) -> None:
+ """Test that events sent by signal_event can be seen by subscribe."""
+ filters: list[tuple[EventType | tuple[EventType, ...] | None, str | tuple[str, ...] | None]] = [
+ (None, None),
+ (EventType.UNKNOWN, None),
+ ((EventType.UNKNOWN, EventType.AUTH_SESSION), None),
+ (None, "myid1"),
+ (None, ("myid1", "myid2")),
+ (EventType.UNKNOWN, "myid1"),
+ ]
+
+ for event_filter, id_filter in filters:
+ flag = False
+
+ def _ev(event: MassEvent) -> None:
+ assert event.event == EventType.UNKNOWN
+ assert event.data == "mytestdata"
+ assert event.object_id == "myid1"
+ nonlocal flag
+ flag = True
+
+ remove_cb = mass.subscribe(_ev, event_filter, id_filter)
+
+ mass.signal_event(EventType.UNKNOWN, "myid1", "mytestdata")
+ await asyncio.sleep(0)
+ assert flag is True
+
+ flag = False
+ remove_cb()
+ mass.signal_event(EventType.UNKNOWN)
+ await asyncio.sleep(0)
+ assert flag is False