test(agents): add validation tests for category and display fields
Added comprehensive unit and API tests to validate AgentType category and display fields: - Category validation for valid, null, and invalid values - Icon, color, and sort_order field constraints - Typical tasks and collaboration hints handling (stripping, removing empty strings, normalization) - New API tests for field creation, filtering, updating, and grouping
This commit is contained in:
@@ -745,3 +745,230 @@ class TestAgentTypeInstanceCount:
|
||||
for agent_type in data["data"]:
|
||||
assert "instance_count" in agent_type
|
||||
assert isinstance(agent_type["instance_count"], int)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
class TestAgentTypeCategoryFields:
|
||||
"""Tests for agent type category and display fields."""
|
||||
|
||||
async def test_create_agent_type_with_category_fields(
|
||||
self, client, superuser_token
|
||||
):
|
||||
"""Test creating agent type with all category and display fields."""
|
||||
unique_slug = f"category-type-{uuid.uuid4().hex[:8]}"
|
||||
response = await client.post(
|
||||
"/api/v1/agent-types",
|
||||
json={
|
||||
"name": "Categorized Agent Type",
|
||||
"slug": unique_slug,
|
||||
"description": "An agent type with category fields",
|
||||
"expertise": ["python"],
|
||||
"personality_prompt": "You are a helpful assistant.",
|
||||
"primary_model": "claude-opus-4-5-20251101",
|
||||
# Category and display fields
|
||||
"category": "development",
|
||||
"icon": "code",
|
||||
"color": "#3B82F6",
|
||||
"sort_order": 10,
|
||||
"typical_tasks": ["Write code", "Review PRs"],
|
||||
"collaboration_hints": ["backend-engineer", "qa-engineer"],
|
||||
},
|
||||
headers={"Authorization": f"Bearer {superuser_token}"},
|
||||
)
|
||||
|
||||
assert response.status_code == status.HTTP_201_CREATED
|
||||
data = response.json()
|
||||
|
||||
assert data["category"] == "development"
|
||||
assert data["icon"] == "code"
|
||||
assert data["color"] == "#3B82F6"
|
||||
assert data["sort_order"] == 10
|
||||
assert data["typical_tasks"] == ["Write code", "Review PRs"]
|
||||
assert data["collaboration_hints"] == ["backend-engineer", "qa-engineer"]
|
||||
|
||||
async def test_create_agent_type_with_nullable_category(
|
||||
self, client, superuser_token
|
||||
):
|
||||
"""Test creating agent type with null category."""
|
||||
unique_slug = f"null-category-{uuid.uuid4().hex[:8]}"
|
||||
response = await client.post(
|
||||
"/api/v1/agent-types",
|
||||
json={
|
||||
"name": "Uncategorized Agent",
|
||||
"slug": unique_slug,
|
||||
"expertise": ["general"],
|
||||
"personality_prompt": "You are a helpful assistant.",
|
||||
"primary_model": "claude-opus-4-5-20251101",
|
||||
"category": None,
|
||||
},
|
||||
headers={"Authorization": f"Bearer {superuser_token}"},
|
||||
)
|
||||
|
||||
assert response.status_code == status.HTTP_201_CREATED
|
||||
data = response.json()
|
||||
assert data["category"] is None
|
||||
|
||||
async def test_create_agent_type_invalid_color_format(
|
||||
self, client, superuser_token
|
||||
):
|
||||
"""Test that invalid color format is rejected."""
|
||||
unique_slug = f"invalid-color-{uuid.uuid4().hex[:8]}"
|
||||
response = await client.post(
|
||||
"/api/v1/agent-types",
|
||||
json={
|
||||
"name": "Invalid Color Agent",
|
||||
"slug": unique_slug,
|
||||
"expertise": ["python"],
|
||||
"personality_prompt": "You are a helpful assistant.",
|
||||
"primary_model": "claude-opus-4-5-20251101",
|
||||
"color": "not-a-hex-color",
|
||||
},
|
||||
headers={"Authorization": f"Bearer {superuser_token}"},
|
||||
)
|
||||
|
||||
assert response.status_code == status.HTTP_422_UNPROCESSABLE_ENTITY
|
||||
|
||||
async def test_create_agent_type_invalid_category(self, client, superuser_token):
|
||||
"""Test that invalid category value is rejected."""
|
||||
unique_slug = f"invalid-category-{uuid.uuid4().hex[:8]}"
|
||||
response = await client.post(
|
||||
"/api/v1/agent-types",
|
||||
json={
|
||||
"name": "Invalid Category Agent",
|
||||
"slug": unique_slug,
|
||||
"expertise": ["python"],
|
||||
"personality_prompt": "You are a helpful assistant.",
|
||||
"primary_model": "claude-opus-4-5-20251101",
|
||||
"category": "not_a_valid_category",
|
||||
},
|
||||
headers={"Authorization": f"Bearer {superuser_token}"},
|
||||
)
|
||||
|
||||
assert response.status_code == status.HTTP_422_UNPROCESSABLE_ENTITY
|
||||
|
||||
async def test_update_agent_type_category_fields(
|
||||
self, client, superuser_token, test_agent_type
|
||||
):
|
||||
"""Test updating category and display fields."""
|
||||
agent_type_id = test_agent_type["id"]
|
||||
|
||||
response = await client.patch(
|
||||
f"/api/v1/agent-types/{agent_type_id}",
|
||||
json={
|
||||
"category": "ai_ml",
|
||||
"icon": "brain",
|
||||
"color": "#8B5CF6",
|
||||
"sort_order": 50,
|
||||
"typical_tasks": ["Train models", "Analyze data"],
|
||||
"collaboration_hints": ["data-scientist"],
|
||||
},
|
||||
headers={"Authorization": f"Bearer {superuser_token}"},
|
||||
)
|
||||
|
||||
assert response.status_code == status.HTTP_200_OK
|
||||
data = response.json()
|
||||
|
||||
assert data["category"] == "ai_ml"
|
||||
assert data["icon"] == "brain"
|
||||
assert data["color"] == "#8B5CF6"
|
||||
assert data["sort_order"] == 50
|
||||
assert data["typical_tasks"] == ["Train models", "Analyze data"]
|
||||
assert data["collaboration_hints"] == ["data-scientist"]
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
class TestAgentTypeCategoryFilter:
|
||||
"""Tests for agent type category filtering."""
|
||||
|
||||
async def test_list_agent_types_filter_by_category(
|
||||
self, client, superuser_token, user_token
|
||||
):
|
||||
"""Test filtering agent types by category."""
|
||||
# Create agent types in different categories
|
||||
for cat in ["development", "design"]:
|
||||
unique_slug = f"filter-test-{cat}-{uuid.uuid4().hex[:8]}"
|
||||
await client.post(
|
||||
"/api/v1/agent-types",
|
||||
json={
|
||||
"name": f"Filter Test {cat.capitalize()}",
|
||||
"slug": unique_slug,
|
||||
"expertise": ["python"],
|
||||
"personality_prompt": "Test prompt",
|
||||
"primary_model": "claude-opus-4-5-20251101",
|
||||
"category": cat,
|
||||
},
|
||||
headers={"Authorization": f"Bearer {superuser_token}"},
|
||||
)
|
||||
|
||||
# Filter by development category
|
||||
response = await client.get(
|
||||
"/api/v1/agent-types",
|
||||
params={"category": "development"},
|
||||
headers={"Authorization": f"Bearer {user_token}"},
|
||||
)
|
||||
|
||||
assert response.status_code == status.HTTP_200_OK
|
||||
data = response.json()
|
||||
|
||||
# All returned types should have development category
|
||||
for agent_type in data["data"]:
|
||||
assert agent_type["category"] == "development"
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
class TestAgentTypeGroupedEndpoint:
|
||||
"""Tests for the grouped by category endpoint."""
|
||||
|
||||
async def test_list_agent_types_grouped(self, client, superuser_token, user_token):
|
||||
"""Test getting agent types grouped by category."""
|
||||
# Create agent types in different categories
|
||||
categories = ["development", "design", "quality"]
|
||||
for cat in categories:
|
||||
unique_slug = f"grouped-test-{cat}-{uuid.uuid4().hex[:8]}"
|
||||
await client.post(
|
||||
"/api/v1/agent-types",
|
||||
json={
|
||||
"name": f"Grouped Test {cat.capitalize()}",
|
||||
"slug": unique_slug,
|
||||
"expertise": ["python"],
|
||||
"personality_prompt": "Test prompt",
|
||||
"primary_model": "claude-opus-4-5-20251101",
|
||||
"category": cat,
|
||||
"sort_order": 10,
|
||||
},
|
||||
headers={"Authorization": f"Bearer {superuser_token}"},
|
||||
)
|
||||
|
||||
# Get grouped agent types
|
||||
response = await client.get(
|
||||
"/api/v1/agent-types/grouped",
|
||||
headers={"Authorization": f"Bearer {user_token}"},
|
||||
)
|
||||
|
||||
assert response.status_code == status.HTTP_200_OK
|
||||
data = response.json()
|
||||
|
||||
# Should be a dict with category keys
|
||||
assert isinstance(data, dict)
|
||||
|
||||
# Check that at least one of our created categories exists
|
||||
assert any(cat in data for cat in categories)
|
||||
|
||||
async def test_list_agent_types_grouped_filter_inactive(
|
||||
self, client, superuser_token, user_token
|
||||
):
|
||||
"""Test grouped endpoint with is_active filter."""
|
||||
response = await client.get(
|
||||
"/api/v1/agent-types/grouped",
|
||||
params={"is_active": False},
|
||||
headers={"Authorization": f"Bearer {user_token}"},
|
||||
)
|
||||
|
||||
assert response.status_code == status.HTTP_200_OK
|
||||
data = response.json()
|
||||
assert isinstance(data, dict)
|
||||
|
||||
async def test_list_agent_types_grouped_unauthenticated(self, client):
|
||||
"""Test that unauthenticated users cannot access grouped endpoint."""
|
||||
response = await client.get("/api/v1/agent-types/grouped")
|
||||
assert response.status_code == status.HTTP_401_UNAUTHORIZED
|
||||
|
||||
Reference in New Issue
Block a user