from unittest.mock import AsyncMock, patch from fastapi.testclient import TestClient from nanoid import generate as generate_nanoid from sqlalchemy.ext.asyncio import AsyncSession from src.config import settings from src.models import Peer, Workspace def test_workspace_validations_api(client: TestClient): # Test name too short response = client.post("/v3/workspaces", json={"name": "", "metadata": {}}) assert response.status_code == 422 error = response.json()["detail"][0] assert error["loc"] == ["body", "name"] assert error["msg"] == "String should have at least 1 character" assert error["type"] == "string_too_short" # Test name too long response = client.post("/v3/workspaces", json={"name": "a" * 513, "metadata": {}}) assert response.status_code == 422 error = response.json()["detail"][0] assert error["loc"] == ["body", "name"] assert error["msg"] == "String should have at most 512 characters" assert error["type"] == "string_too_long" # Test invalid metadata type response = client.post( "/v3/workspaces", json={"name": "test", "metadata": "not a dict"} ) assert response.status_code == 422 error = response.json()["detail"][0] assert error["loc"] == ["body", "metadata"] assert error["type"] == "dict_type" def test_peer_validations_api(client: TestClient, sample_data: tuple[Workspace, Peer]): test_workspace, _ = sample_data # Test name too short response = client.post( f"/v3/workspaces/{test_workspace.name}/peers", json={"name": "", "metadata": {}} ) assert response.status_code == 422 error = response.json()["detail"][0] assert error["loc"] == ["body", "name"] assert error["msg"] == "String should have at least 1 character" assert error["type"] == "string_too_short" # Test name too long response = client.post( f"/v3/workspaces/{test_workspace.name}/peers", json={"name": "a" * 513, "metadata": {}}, ) assert response.status_code == 422 error = response.json()["detail"][0] assert error["loc"] == ["body", "name"] assert error["msg"] == "String should have at most 512 characters" assert error["type"] == "string_too_long" def test_message_validations_api( client: TestClient, sample_data: tuple[Workspace, Peer] ): test_workspace, test_peer = sample_data # Create a test session first session_id = str(generate_nanoid()) session_response = client.post( f"/v3/workspaces/{test_workspace.name}/sessions", json={"id": session_id, "peer_names": {test_peer.name: {}}}, ) assert session_response.status_code == 201 # Test content too long response = client.post( f"/v3/workspaces/{test_workspace.name}/sessions/{session_id}/messages", json={ "messages": [ { "content": "a" * (settings.MAX_MESSAGE_SIZE + 1), "peer_id": test_peer.name, "metadata": {}, } ] }, ) assert response.status_code == 422 error = response.json()["detail"][0] assert "content" in str(error["loc"]) assert ( error["msg"] == f"String should have at most {settings.MAX_MESSAGE_SIZE} characters" ) assert error["type"] == "string_too_long" def test_session_validations_api( client: TestClient, sample_data: tuple[Workspace, Peer] ): test_workspace, test_peer = sample_data # Create a test session first session_id = str(generate_nanoid()) session_response = client.post( f"/v3/workspaces/{test_workspace.name}/sessions", json={ "id": session_id, "peer_names": {test_peer.name: {}}, "metadata": {"test_key": "test_value"}, "configuration": {"test_flag": "test_value"}, }, ) assert session_response.status_code == 201 # Test invalid metadata type response = client.put( f"/v3/workspaces/{test_workspace.name}/sessions/{session_id}", json={"metadata": "not a dict"}, ) assert response.status_code == 422 error = response.json()["detail"][0] assert error["loc"] == ["body", "metadata"] assert error["type"] == "dict_type" # Test empty update # This should work but not change the session's metadata or configuration response = client.put( f"/v3/workspaces/{test_workspace.name}/sessions/{session_id}", json={}, ) assert response.status_code == 200 # Test that the session's metadata and configuration are not changed response = client.post( f"/v3/workspaces/{test_workspace.name}/sessions", json={ "id": session_id, }, ) assert response.status_code in [200, 201] data = response.json() assert data["metadata"] == {"test_key": "test_value"} assert data["configuration"] == {"test_flag": "test_value"} @patch("src.routers.peers.tracked_db") def test_agent_query_validations_api( mock_tracked_db: AsyncMock, client: TestClient, sample_data: tuple[Workspace, Peer], db_session: AsyncSession, ): mock_tracked_db.return_value.__aenter__.return_value = db_session test_workspace, test_peer = sample_data # Create a session first since agent query are session-based session_id = str(generate_nanoid()) session_response = client.post( f"/v3/workspaces/{test_workspace.name}/sessions", json={"id": session_id, "peer_names": {test_peer.name: {}}}, ) assert session_response.status_code == 201 # Test valid string query (under 10000 chars) response = client.post( f"/v3/workspaces/{test_workspace.name}/peers/{test_peer.name}/chat", params={"session_id": session_id, "target": "test_target"}, json={"query": "a" * 9999, "stream": False}, ) assert response.status_code == 200 # Test string query too long (over 10000 chars) response = client.post( f"/v3/workspaces/{test_workspace.name}/peers/{test_peer.name}/chat", params={"session_id": session_id, "target": "test_target"}, json={"query": "a" * 10001, "stream": False}, ) assert response.status_code == 422 error = response.json()["detail"][0] assert error["loc"] == ["body", "query"] assert error["msg"] == "String should have at most 10000 characters" assert error["type"] == "string_too_long" # Test that strings over 20 chars are allowed response = client.post( f"/v3/workspaces/{test_workspace.name}/peers/{test_peer.name}/chat", params={"session_id": session_id, "target": "test_target"}, json={"query": "a" * 100, "stream": False}, # 100 chars should be fine ) assert response.status_code == 200 def test_required_field_validations_api( client: TestClient, sample_data: tuple[Workspace, Peer] ): test_workspace, test_peer = sample_data session_id = str(generate_nanoid()) session_response = client.post( f"/v3/workspaces/{test_workspace.name}/sessions", json={"id": session_id, "peer_names": {test_peer.name: {}}}, ) assert session_response.status_code == 201 # Test missing required content in message response = client.post( f"/v3/workspaces/{test_workspace.name}/sessions/{session_id}/messages", json={"messages": [{"peer_id": test_peer.name, "metadata": {}}]}, ) assert response.status_code == 422 error = response.json()["detail"][0] assert "content" in str(error["loc"]) assert error["type"] == "missing" # Test missing required peer_id in message response = client.post( f"/v3/workspaces/{test_workspace.name}/sessions/{session_id}/messages", json={"messages": [{"content": "test", "metadata": {}}]}, ) assert response.status_code == 422 error = response.json()["detail"][0] assert "peer_id" in str(error["loc"]) or "peer_name" in str(error["loc"]) assert error["type"] == "missing" def test_filter_validations_api( client: TestClient, sample_data: tuple[Workspace, Peer] ): test_workspace, test_peer = sample_data # Create a session first session_id = str(generate_nanoid()) session_response = client.post( f"/v3/workspaces/{test_workspace.name}/sessions", json={"id": session_id, "peer_names": {test_peer.name: {}}}, ) assert session_response.status_code == 201 # Test invalid filter type in message list (at session level) response = client.post( f"/v3/workspaces/{test_workspace.name}/sessions/{session_id}/messages/list", json={"filters": "not a dict"}, ) assert response.status_code == 422 error = response.json()["detail"][0] assert error["loc"] == ["body", "filters"] assert error["type"] == "dict_type"