"""Przypina powierzchnię API - panel jest osobnym klientem, więc kontrakt musi być stabilny.""" from __future__ import annotations import tempfile import unittest from zyrarbot.application import Application from zyrarbot.settings import Settings EXPECTED_ENDPOINTS = { ("get", "/api/status"), ("get", "/api/health"), ("post", "/api/play"), ("post", "/api/play_file"), ("post", "/api/pause"), ("post", "/api/resume"), ("post", "/api/skip"), ("post", "/api/stop"), ("post", "/api/volume"), ("post", "/api/loop"), ("post", "/api/loop_playlist"), ("post", "/api/loop_cycle"), ("post", "/api/jump"), ("post", "/api/remove"), ("post", "/api/reorder"), ("post", "/api/queue/restore"), ("post", "/api/queue/plays"), ("get", "/api/uploads"), ("post", "/api/upload"), ("delete", "/api/uploads/{filename}"), ("post", "/api/connect"), ("post", "/api/disconnect"), ("post", "/api/notification_channel"), ("post", "/api/default_plays"), } class ApiSurfaceTest(unittest.TestCase): @classmethod def setUpClass(cls) -> None: cls._workdir = tempfile.TemporaryDirectory() settings = Settings( discord_token="test", config_dir=f"{cls._workdir.name}/config", uploads_dir=f"{cls._workdir.name}/uploads", static_dir=f"{cls._workdir.name}/static", ) cls.spec = Application(settings).web.openapi() @classmethod def tearDownClass(cls) -> None: cls._workdir.cleanup() def _declared(self) -> set[tuple[str, str]]: return { (method, path) for path, operations in self.spec["paths"].items() for method in operations } def test_all_expected_endpoints_are_declared(self): self.assertEqual(set(), EXPECTED_ENDPOINTS - self._declared()) def test_no_endpoint_added_without_updating_this_test(self): # Panel jest odrębnym klientem - nowa trasa powinna trafić tu świadomie. self.assertEqual(set(), self._declared() - EXPECTED_ENDPOINTS) def test_openapi_document_is_well_formed(self): self.assertTrue(self.spec["openapi"].startswith("3.")) self.assertIn("ŻyrarBOT", self.spec["info"]["title"]) if __name__ == "__main__": unittest.main()