from __future__ import annotations import unittest from collections import Counter from inspect import signature from govoplan_files.backend.router import router from govoplan_files.backend.routes.assets import router as assets_router from govoplan_files.backend.routes.connector_io import router as connector_io_router from govoplan_files.backend.routes.connector_profiles import router as connector_profiles_router from govoplan_files.backend.routes.connector_settings import router as connector_settings_router from govoplan_files.backend.routes.folders import router as folders_router from govoplan_files.backend.routes.listing import router as listing_router from govoplan_files.backend.routes.shares import router as shares_router from govoplan_files.backend.routes.spaces import router as spaces_router from govoplan_files.backend.routes.transfers import router as transfers_router from govoplan_files.backend.routes.uploads import router as uploads_router class FilesRouterContractTests(unittest.TestCase): @staticmethod def _operation_keys(candidate_router) -> list[tuple[str, str]]: return [ (method, route.path) for route in candidate_router.routes for method in sorted(route.methods or ()) ] def test_composed_router_contains_every_workflow_operation_once(self) -> None: workflow_routers = ( spaces_router, folders_router, listing_router, uploads_router, connector_settings_router, connector_io_router, connector_profiles_router, assets_router, shares_router, transfers_router, ) expected = [ operation for workflow_router in workflow_routers for operation in self._operation_keys(workflow_router) ] actual = self._operation_keys(router) self.assertEqual(expected, actual) self.assertEqual(41, len(actual)) self.assertFalse( [operation for operation, count in Counter(actual).items() if count > 1] ) def test_connector_routes_keep_existing_api_paths(self) -> None: routes = {(tuple(sorted(route.methods or ())), route.path) for route in router.routes} expected = { (("GET",), "/files/connectors/providers"), (("GET",), "/files/connectors/settings/delta"), (("GET",), "/files/connectors/profiles"), (("POST",), "/files/connectors/profiles"), (("GET",), "/files/connectors/profiles/{profile_id}/browse"), (("POST",), "/files/connectors/profiles/{profile_id}/import"), (("POST",), "/files/connectors/profiles/{profile_id}/sync"), (("GET",), "/files/connectors/credentials"), (("POST",), "/files/connectors/credentials"), (("GET",), "/files/connector-spaces"), (("POST",), "/files/connector-spaces"), } self.assertTrue(expected.issubset(routes)) def test_bulk_organize_routes_keep_existing_api_paths(self) -> None: routes = {(tuple(sorted(route.methods or ())), route.path) for route in router.routes} self.assertIn((("POST",), "/files/bulk-rename"), routes) self.assertIn((("POST",), "/files/transfer"), routes) def test_file_listing_exposes_structured_property_filters(self) -> None: route = next( route for route in listing_router.routes if route.path == "/files" and "GET" in (route.methods or ()) ) parameters = signature(route.endpoint).parameters self.assertIn("campaign_usage", parameters) self.assertIn("audit_relevant", parameters) self.assertIn("total", route.response_model.model_fields) if __name__ == "__main__": unittest.main()