""" Test route registry functionality """ import pytest from local_deep_research.web.routes.route_registry import ( ROUTE_REGISTRY, find_route, get_all_routes, get_routes_by_blueprint, ) class TestRouteRegistry: """Test the route registry module""" def test_route_registry_structure(self): """Test that ROUTE_REGISTRY has the expected structure""" # Check that we have the expected blueprints expected_blueprints = [ "research", "api_v1", "history", "settings", "metrics", ] assert set(ROUTE_REGISTRY.keys()) == set(expected_blueprints) # Check each blueprint has required keys for blueprint_name, blueprint_info in ROUTE_REGISTRY.items(): assert "blueprint" in blueprint_info assert "url_prefix" in blueprint_info assert "routes" in blueprint_info assert isinstance(blueprint_info["routes"], list) # Check each route has the expected format for route in blueprint_info["routes"]: assert len(route) == 4 # (method, path, endpoint, description) method, path, endpoint, description = route assert isinstance(method, str) assert method in ["GET", "POST", "DELETE", "PUT", "PATCH"] assert isinstance(path, str) assert isinstance(endpoint, str) assert isinstance(description, str) def test_get_all_routes(self): """Test get_all_routes function""" all_routes = get_all_routes() # Should return a list assert isinstance(all_routes, list) assert len(all_routes) > 0 # Check structure of returned routes for route in all_routes: assert isinstance(route, dict) assert "method" in route assert "path" in route assert "endpoint" in route assert "description" in route assert "blueprint" in route # Check that paths are properly prefixed api_v1_routes = [r for r in all_routes if r["blueprint"] == "api_v1"] for route in api_v1_routes: assert route["path"].startswith("/api/v1") # Check that research routes are at root level research_routes = [ r for r in all_routes if r["blueprint"] == "research" ] root_route = next( (r for r in research_routes if r["endpoint"] == "research.index"), None, ) assert root_route is not None assert root_route["path"] == "/" def test_get_routes_by_blueprint(self): """Test get_routes_by_blueprint function""" # Test valid blueprint settings_routes = get_routes_by_blueprint("settings") assert isinstance(settings_routes, list) assert len(settings_routes) > 0 # All routes should be from settings blueprint for route in settings_routes: assert route["path"].startswith("/settings") # Test invalid blueprint invalid_routes = get_routes_by_blueprint("invalid_blueprint") assert invalid_routes == [] # Test specific routes settings_page = next( (r for r in settings_routes if r["endpoint"] == "settings_page"), None, ) assert settings_page is not None assert settings_page["path"] == "/settings/" assert settings_page["method"] == "GET" def test_find_route(self): """Test find_route function""" # Test finding routes by pattern api_routes = find_route("/api") assert len(api_routes) > 0 for route in api_routes: assert "/api" in route["path"].lower() # Test finding specific route history_routes = find_route("history") assert len(history_routes) > 0 # Test case insensitive search metrics_routes = find_route("METRICS") assert len(metrics_routes) > 0 # Test pattern not found not_found = find_route("nonexistent_pattern") assert not_found == [] def test_route_uniqueness(self): """Test that route paths are unique within their method""" all_routes = get_all_routes() # Group by method and path route_map = {} for route in all_routes: key = (route["method"], route["path"]) if key in route_map: # Found duplicate pytest.fail( f"Duplicate route found: {route['method']} {route['path']} " f"in {route['blueprint']} and {route_map[key]['blueprint']}" ) route_map[key] = route def test_api_routes_consistency(self): """Test that API routes follow consistent patterns""" all_routes = get_all_routes() api_routes = [r for r in all_routes if "/api" in r["path"]] for route in api_routes: # API routes should use proper REST methods if "get" in route["endpoint"] or "status" in route["endpoint"]: assert route["method"] == "GET", ( f"GET method expected for {route['endpoint']}" ) elif ( "create" in route["endpoint"] or "save" in route["endpoint"] or "update" in route["endpoint"] ): assert route["method"] in ["POST", "PUT", "PATCH"], ( f"POST/PUT/PATCH expected for {route['endpoint']}" ) elif "delete" in route["endpoint"] or "clear" in route["endpoint"]: assert route["method"] in ["DELETE", "POST"], ( f"DELETE/POST expected for {route['endpoint']}" ) def test_research_id_routes(self): """Test that routes with research_id parameter are consistent""" all_routes = get_all_routes() research_id_routes = [ r for r in all_routes if "" in r["path"] or "" in r["path"] ] assert len(research_id_routes) > 0, ( "Should have routes with research_id parameter" ) # Check that research_id routes exist in multiple blueprints blueprints_with_research_id = set( r["blueprint"] for r in research_id_routes ) assert len(blueprints_with_research_id) >= 3, ( "Multiple blueprints should have research_id routes" ) def test_settings_api_routes(self): """Test settings API routes specifically""" settings_routes = get_routes_by_blueprint("settings") # Check for CRUD operations on settings api_routes = [r for r in settings_routes if "/api" in r["path"]] # Should have routes for all CRUD operations methods = set(r["method"] for r in api_routes) assert "GET" in methods assert "POST" in methods assert "DELETE" in methods # Check for specific important routes route_endpoints = [r["endpoint"] for r in api_routes] assert "api_get_all_settings" in route_endpoints assert "api_update_setting" in route_endpoints assert "api_get_available_models" in route_endpoints def test_route_documentation(self): """Test that all routes have descriptions""" all_routes = get_all_routes() for route in all_routes: # Every route should have a non-empty description assert route["description"], ( f"Route {route['method']} {route['path']} missing description" ) assert len(route["description"]) > 5, ( f"Route {route['method']} {route['path']} has too short description" ) def test_blueprint_naming_consistency(self): """Test that blueprint names are consistent""" for blueprint_name, blueprint_info in ROUTE_REGISTRY.items(): # Blueprint field should match the key with _bp suffix (except api_v1) if blueprint_name == "api_v1": assert blueprint_info["blueprint"] == "api_blueprint" else: assert blueprint_info["blueprint"] == f"{blueprint_name}_bp" def test_url_prefix_consistency(self): """Test that URL prefixes match blueprint names""" for blueprint_name, blueprint_info in ROUTE_REGISTRY.items(): if blueprint_name == "research": # Research blueprint is at root assert blueprint_info["url_prefix"] is None elif blueprint_name == "api_v1": assert blueprint_info["url_prefix"] == "/api/v1" else: # Other blueprints should have prefix matching their name assert blueprint_info["url_prefix"] == f"/{blueprint_name}" def test_parameterized_routes(self): """Test routes with parameters""" all_routes = get_all_routes() # Check for consistent parameter naming param_routes = [ r for r in all_routes if "<" in r["path"] and ">" in r["path"] ] for route in param_routes: # Check common parameters if "research_id" in route["path"]: # Should be typed as string (research IDs are UUIDs) assert ( "" in route["path"] or "" in route["path"] ), f"research_id should be typed as string in {route['path']}" if "resource_id" in route["path"]: assert "" in route["path"], ( f"resource_id should be typed as int in {route['path']}" ) def test_special_routes(self): """Test special routes like health checks and documentation""" all_routes = get_all_routes() # Should have a health check endpoint health_routes = [r for r in all_routes if "health" in r["endpoint"]] assert len(health_routes) > 0, ( "Should have at least one health check route" ) # Should have documentation routes doc_routes = [ r for r in all_routes if "documentation" in r["description"].lower() ] assert len(doc_routes) > 0, "Should have documentation routes" def test_metrics_routes(self): """Test metrics blueprint routes""" metrics_routes = get_routes_by_blueprint("metrics") # Should have dashboard and API routes dashboard_routes = [ r for r in metrics_routes if r["method"] == "GET" and "/api" not in r["path"] ] api_routes = [r for r in metrics_routes if "/api" in r["path"]] assert len(dashboard_routes) >= 3, ( "Should have multiple dashboard routes" ) assert len(api_routes) >= 5, "Should have multiple API routes" # Check for essential metrics routes route_paths = [r["path"] for r in metrics_routes] assert "/metrics/" in route_paths assert "/metrics/costs" in route_paths assert "/metrics/api/metrics" in route_paths if __name__ == "__main__": # Run a quick verification when executed directly print("Running route registry verification...") all_routes = get_all_routes() print(f"\nTotal routes: {len(all_routes)}") by_blueprint = {} for route in all_routes: bp = route["blueprint"] by_blueprint[bp] = by_blueprint.get(bp, 0) + 1 print("\nRoutes by blueprint:") for bp, count in sorted(by_blueprint.items()): print(f" {bp}: {count}") print("\nSample routes:") for route in all_routes[:5]: print( f" {route['method']:6} {route['path']:40} - {route['description']}" )