fix: tests and linters
Panel / Lint, typy i build (pull_request) Successful in 25s
Backend / Testy i kontrakt API (pull_request) Successful in 31s
Backend / Lint i formatowanie (pull_request) Failing after 32s
Backend / Testowy build obrazu (pull_request) Skipped

This commit is contained in:
mmacierzanka committed 2026-10-01 13:59:19 +02:00
1 parent 0b1b448766
commit 56e3ddba8a
7 files changed
+94 -103

No files matched your search

+6 -1
View File
@@ -4,6 +4,7 @@ from __future__ import annotations
import tempfile import tempfile
import unittest import unittest
from unittest.mock import MagicMock
from zyrarbot.application import Application from zyrarbot.application import Application
from zyrarbot.settings import Settings from zyrarbot.settings import Settings
@@ -49,7 +50,11 @@ class ApiSurfaceTest(unittest.TestCase):
uploads_dir=f"{cls._workdir.name}/uploads", uploads_dir=f"{cls._workdir.name}/uploads",
static_dir=f"{cls._workdir.name}/static", static_dir=f"{cls._workdir.name}/static",
) )
cls.spec = Application(settings).web.openapi() persistence = MagicMock()
persistence.config = MagicMock()
persistence.history = MagicMock()
persistence.queues = MagicMock()
cls.spec = Application(settings, persistence=persistence).web.openapi()
@classmethod @classmethod
def tearDownClass(cls) -> None: def tearDownClass(cls) -> None:
+23 -22
View File
@@ -1,32 +1,33 @@
import json from __future__ import annotations
import tempfile
import unittest
from pathlib import Path
from zyrarbot.storage.guild_config_repository import GuildConfigRepository import unittest
from zyrarbot.storage.json_file_store import JsonFileStore from unittest.mock import MagicMock
from zyrarbot.storage.adapters.postgres.guild_config import PostgresGuildConfig
class GuildConfigRepositoryTest(unittest.TestCase): class GuildConfigRepositoryTest(unittest.TestCase):
def test_settings_are_isolated_and_legacy_default_moves_to_first_guild(self): def setUp(self):
with tempfile.TemporaryDirectory() as directory: self.database = MagicMock()
path = Path(directory) / "config.json" self.connection = self.database.connect.return_value.__enter__.return_value
path.write_text(json.dumps({"default_plays": 7, "10": 123}), encoding="utf-8") self.repository = PostgresGuildConfig(self.database, fallback_plays=5)
repository = GuildConfigRepository(JsonFileStore(str(path)), fallback_plays=5)
repository.migrate_legacy(10) def test_default_plays_uses_fallback_when_guild_has_no_override(self):
self.assertEqual(repository.get_default_plays(10), 7) self.connection.execute.return_value.fetchone.return_value = (None,)
self.assertEqual(repository.get_notification_channel_id(10), 123)
self.assertEqual(repository.get_default_plays(20), 5)
repository.set_default_plays(20, 9) self.assertEqual(self.repository.get_default_plays(10), 5)
self.assertEqual(repository.get_default_plays(10), 7)
self.assertEqual(repository.get_default_plays(20), 9)
saved = json.loads(path.read_text(encoding="utf-8")) def test_default_plays_returns_guild_override(self):
self.assertNotIn("default_plays", saved) self.connection.execute.return_value.fetchone.return_value = (7,)
self.assertEqual(saved["10"]["default_plays"], 7)
self.assertEqual(saved["20"]["default_plays"], 9) self.assertEqual(self.repository.get_default_plays(10), 7)
def test_set_default_plays_creates_guild_then_updates_setting(self):
self.repository.set_default_plays(10, 9)
statements = [call.args[0] for call in self.connection.execute.call_args_list]
self.assertIn("INSERT INTO guilds", statements[0])
self.assertIn("UPDATE guilds SET default_plays", statements[1])
if __name__ == "__main__": if __name__ == "__main__":
+31 -34
View File
@@ -1,52 +1,49 @@
import json from __future__ import annotations
import tempfile
import unittest import unittest
from pathlib import Path from unittest.mock import MagicMock
from zyrarbot.music.history_entry import HistoryEntry from zyrarbot.music.history_entry import HistoryEntry
from zyrarbot.storage.history_repository import HistoryRepository from zyrarbot.storage.adapters.postgres.history import PostgresHistory
from zyrarbot.storage.json_file_store import JsonFileStore
class HistoryRepositoryTest(unittest.TestCase): class HistoryRepositoryTest(unittest.TestCase):
def test_history_is_stored_in_separate_files_and_legacy_data_is_migrated(self): def setUp(self):
with tempfile.TemporaryDirectory() as directory: self.database = MagicMock()
legacy_path = Path(directory) / "history.json" self.connection = self.database.connect.return_value.__enter__.return_value
entry = HistoryEntry( self.repository = PostgresHistory(self.database)
def test_list_maps_database_rows_to_history_entries(self):
self.connection.execute.return_value.fetchall.return_value = [
("track-1", "Track", "https://example.test/track", 10, False)
]
self.assertEqual(
self.repository.list(10),
[
HistoryEntry(
id="track-1", id="track-1",
title="Track", title="Track",
url="https://example.test/track", url="https://example.test/track",
duration=10, duration=10,
is_local=False, is_local=False,
filepath=None,
) )
legacy_path.write_text(json.dumps({"10": [entry.to_dict()]}), encoding="utf-8") ],
repository = HistoryRepository(JsonFileStore(str(legacy_path)))
repository.migrate_legacy(10)
self.assertEqual(repository.list(10)[0].id, "track-1")
self.assertEqual(repository.list(20), [])
self.assertTrue((Path(directory) / "history" / "10.json").exists())
self.assertFalse((Path(directory) / "history" / "20.json").exists())
def test_new_entries_are_available_after_repository_reload(self):
with tempfile.TemporaryDirectory() as directory:
store = JsonFileStore(str(Path(directory) / "history.json"))
entry = HistoryEntry(
id="track-2",
title="Another track",
url="https://example.test/another-track",
) )
HistoryRepository(store).add(42, entry) def test_add_ignores_entries_without_a_title(self):
self.repository.add(10, HistoryEntry(id="track-1", title=""))
reloaded = HistoryRepository(store) self.database.connect.assert_not_called()
self.assertEqual(reloaded.list(42), [entry])
persisted = json.loads( def test_add_persists_entry_for_guild(self):
(Path(directory) / "history" / "42.json").read_text(encoding="utf-8") self.connection.execute.return_value.fetchall.return_value = []
) entry = HistoryEntry(id="track-1", title="Track", url="https://example.test/track")
self.assertEqual(persisted["entries"][0]["id"], "track-2")
self.repository.add(10, entry)
statements = [call.args[0] for call in self.connection.execute.call_args_list]
self.assertTrue(any("INSERT INTO history_entries" in statement for statement in statements))
if __name__ == "__main__": if __name__ == "__main__":
+9 -18
View File
@@ -3,12 +3,11 @@
from __future__ import annotations from __future__ import annotations
import asyncio import asyncio
import tempfile
import unittest import unittest
from unittest.mock import MagicMock
from tests.fakes import FakeTrack, build_player from tests.fakes import FakeTrack, build_player
from zyrarbot.music.loop_mode import LoopMode from zyrarbot.music.loop_mode import LoopMode
from zyrarbot.storage.queue_repository import QueueRepository
GUILD = 1 GUILD = 1
@@ -293,12 +292,10 @@ class MusicPlayerQueueTest(unittest.IsolatedAsyncioTestCase):
async def test_restore_replaces_active_queue_without_old_callback_interference(self): async def test_restore_replaces_active_queue_without_old_callback_interference(self):
player, voice_client = build_player() player, voice_client = build_player()
with tempfile.TemporaryDirectory() as directory: player._queues = MagicMock()
player._queues = QueueRepository(directory) player._queues.load.return_value = [
player._queues.save( {"id": "restored", "title": "Restored", "plays_left": 3}
GUILD, ]
[{"id": "restored", "title": "Restored", "plays_left": 3}],
)
async def from_url(url, loop=None): async def from_url(url, loop=None):
return FakeTrack("restored") return FakeTrack("restored")
@@ -324,25 +321,19 @@ class MusicPlayerQueueTest(unittest.IsolatedAsyncioTestCase):
await player.restore_queue(GUILD) await player.restore_queue(GUILD)
def test_save_queue_does_not_overwrite_with_empty_queue(self): def test_save_queue_does_not_overwrite_with_empty_queue(self):
with tempfile.TemporaryDirectory() as directory:
player, _ = build_player() player, _ = build_player()
player._queues = QueueRepository(directory) player._queues = MagicMock()
saved = [{"id": "saved", "title": "Saved", "plays_left": 2}]
player._queues.save(GUILD, saved)
# Kolejka w stanie odtwarzacza jest pusta # Kolejka w stanie odtwarzacza jest pusta
player.state(GUILD).queue = [] player.state(GUILD).queue = []
player.save_queue(GUILD) player.save_queue(GUILD)
# Zapisana wcześniej kolejka powinna pozostać nienaruszona # Zapisana wcześniej kolejka powinna pozostać nienaruszona
self.assertEqual(player._queues.load(GUILD), saved) player._queues.save.assert_not_called()
def test_save_queue_does_not_save_when_all_plays_consumed(self): def test_save_queue_does_not_save_when_all_plays_consumed(self):
with tempfile.TemporaryDirectory() as directory:
player, _ = build_player() player, _ = build_player()
player._queues = QueueRepository(directory) player._queues = MagicMock()
saved = [{"id": "saved", "title": "Saved", "plays_left": 2}]
player._queues.save(GUILD, saved)
# Wszystkie utwory w kolejce mają plays_left = 0 # Wszystkie utwory w kolejce mają plays_left = 0
track = FakeTrack("consumed") track = FakeTrack("consumed")
@@ -351,7 +342,7 @@ class MusicPlayerQueueTest(unittest.IsolatedAsyncioTestCase):
player.save_queue(GUILD) player.save_queue(GUILD)
# Zapisana wcześniej kolejka powinna pozostać nienaruszona # Zapisana wcześniej kolejka powinna pozostać nienaruszona
self.assertEqual(player._queues.load(GUILD), saved) player._queues.save.assert_not_called()
class LoopModeTest(unittest.TestCase): class LoopModeTest(unittest.TestCase):
+22 -27
View File
@@ -1,40 +1,35 @@
import tempfile from __future__ import annotations
import unittest
from pathlib import Path
from zyrarbot.storage.queue_repository import QueueRepository import unittest
from unittest.mock import MagicMock
from zyrarbot.storage.adapters.postgres.queue import PostgresQueue
class QueueRepositoryTest(unittest.TestCase): class QueueRepositoryTest(unittest.TestCase):
def test_snapshots_are_isolated_per_guild(self): def setUp(self):
with tempfile.TemporaryDirectory() as directory: self.database = MagicMock()
repository = QueueRepository(directory) self.connection = self.database.connect.return_value.__enter__.return_value
first = [{"id": "first", "title": "First", "plays_left": 2}] self.repository = PostgresQueue(self.database)
second = [{"id": "second", "title": "Second", "plays_left": 4}]
repository.save(10, first) def test_load_returns_guild_snapshot(self):
repository.save(20, second) snapshot = [{"id": "track-1", "title": "Track", "plays_left": 2}]
self.connection.execute.return_value.fetchone.return_value = (snapshot,)
self.assertEqual(repository.load(10), first) self.assertEqual(self.repository.load(10), snapshot)
self.assertEqual(repository.load(20), second)
self.assertTrue((Path(directory) / "10.json").exists())
self.assertTrue((Path(directory) / "20.json").exists())
def test_save_empty_tracks_does_nothing(self): def test_save_empty_snapshot_does_not_overwrite_saved_queue(self):
with tempfile.TemporaryDirectory() as directory: self.repository.save(10, [])
repository = QueueRepository(directory)
tracks = [{"id": "first", "title": "First", "plays_left": 2}]
repository.save(10, tracks) self.database.connect.assert_not_called()
self.assertEqual(repository.load(10), tracks)
# Próba zapisania pustej listy nie powinna nadpisać poprzedniej def test_save_upserts_snapshot_for_guild(self):
repository.save(10, []) tracks = [{"id": "track-1", "title": "Track", "plays_left": 2}]
self.assertEqual(repository.load(10), tracks)
# Zapis pustej kolejki dla nowego serwera nie powinien tworzyć pliku self.repository.save(10, tracks)
repository.save(20, [])
self.assertFalse(repository.exists(20)) statements = [call.args[0] for call in self.connection.execute.call_args_list]
self.assertTrue(any("INSERT INTO queue_snapshots" in statement for statement in statements))
if __name__ == "__main__": if __name__ == "__main__":
+2
View File
@@ -16,6 +16,7 @@ class ShutdownVoiceCleanupTests(unittest.IsolatedAsyncioTestCase):
self.uploads = MagicMock() self.uploads = MagicMock()
self.config = MagicMock() self.config = MagicMock()
self.history = MagicMock() self.history = MagicMock()
self.migration = MagicMock()
self.bot = MusicBot( self.bot = MusicBot(
self.settings, self.settings,
@@ -23,6 +24,7 @@ class ShutdownVoiceCleanupTests(unittest.IsolatedAsyncioTestCase):
self.uploads, self.uploads,
self.config, self.config,
self.history, self.history,
self.migration,
) )
self.player = MagicMock() self.player = MagicMock()
self.bot.player = self.player self.bot.player = self.player
+1 -1
View File
@@ -2,7 +2,7 @@ import tempfile
import unittest import unittest
from pathlib import Path from pathlib import Path
from zyrarbot.storage.uploads_repository import UploadsRepository from zyrarbot.storage.adapters.filesystem.uploads import UploadsRepository
from zyrarbot.ui.bot.cogs.playback_cog import upload_choices from zyrarbot.ui.bot.cogs.playback_cog import upload_choices