Files
replypier/backend/tests/api/test_agent_workflow.py
T
WangShen007 20fef2b9f3 chore: settle product naming across app, widget and deployments
One word everywhere: ReplyPier in UI copy, package and image names, the
replypier.site domains (app/api/docs/help), REPLYPIER_* settings and the
--rp-* design tokens.

- public widget API is window.ReplyPier with replypierId / replypierBaseUrl /
  replypierConfig / replypierToken, loader at webclient/replypier.min.js;
  both bundles rebuilt from source
- NOTICE, llms.txt, CONTRIBUTING, HELP_CENTER_INFRA and the demo runtime
  config rewritten; the demo config ships no third-party keys
- migration adds the ReplyPier managed model value to the AI model enum
- local compose project, database, role, volume and Docker network carry the
  same name
2026-10-26 00:57:22 +08:00

277 lines
8.7 KiB
Python

"""
Copyright 2024-2026 ReplyPier
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
"""
import pytest
from fastapi.testclient import TestClient
from fastapi import FastAPI
from app.models.user import User
from app.models.agent import Agent, AgentType
from app.models.role import Role
from app.models.permission import Permission, role_permissions
from app.models.organization import Organization
from app.models.workflow import Workflow, WorkflowStatus
from uuid import uuid4
from app.api import agent as agent_router
from app.core.auth import get_current_user, require_permissions, get_unified_auth
from app.database import get_db
# Create a test FastAPI app
app = FastAPI()
app.include_router(
agent_router.router,
prefix="/api/agents",
tags=["agent"]
)
@pytest.fixture
def test_permissions(db) -> list[Permission]:
"""Create test permissions"""
permissions = []
for name in ["manage_agents", "view_all"]:
perm = Permission(
name=name,
description=f"Test permission for {name}"
)
db.add(perm)
permissions.append(perm)
db.commit()
for p in permissions:
db.refresh(p)
return permissions
@pytest.fixture
def test_role(db, test_organization_id, test_permissions) -> Role:
"""Create a test role with required permissions"""
role = Role(
name="Test Role",
description="Test Role Description",
organization_id=test_organization_id,
is_default=True
)
db.add(role)
db.commit()
# Associate permissions with role using the role_permissions table
for perm in test_permissions:
db.execute(
role_permissions.insert().values(
role_id=role.id,
permission_id=perm.id
)
)
db.commit()
db.refresh(role)
return role
@pytest.fixture
def test_user(db, test_organization_id, test_role) -> User:
"""Create a test user with required permissions"""
user = User(
id=uuid4(),
email="test@example.com",
hashed_password="hashed_password",
is_active=True,
organization_id=test_organization_id,
full_name="Test User",
role_id=test_role.id
)
db.add(user)
db.commit()
db.refresh(user)
return user
@pytest.fixture
def test_agent(db, test_user) -> Agent:
"""Create a test agent"""
agent = Agent(
id=uuid4(),
name="Test Agent",
display_name="Test Display Name",
description="Test Description",
agent_type=AgentType.CUSTOMER_SUPPORT,
instructions=["Test instruction"], # Using the correct field name
is_active=True,
organization_id=test_user.organization_id,
transfer_to_human=True,
use_workflow=False
)
db.add(agent)
db.commit()
db.refresh(agent)
return agent
@pytest.fixture
def test_workflow(db, test_user, test_agent) -> Workflow:
"""Create a test workflow"""
workflow = Workflow(
id=uuid4(),
name="Test Workflow",
description="Test workflow description",
status=WorkflowStatus.PUBLISHED,
version=1,
is_template=False,
default_language="en",
canvas_data={},
settings={},
organization_id=test_user.organization_id,
agent_id=test_agent.id,
created_by=test_user.id
)
db.add(workflow)
db.commit()
db.refresh(workflow)
return workflow
@pytest.fixture
def client(db, test_user) -> TestClient:
"""Create test client with mocked dependencies"""
async def override_get_current_user():
return test_user
async def override_require_permissions(*args, **kwargs):
return test_user
async def override_get_unified_auth():
# Authentication only — see the note in tests/api/test_agent.py.
db.refresh(test_user)
db.refresh(test_user.role)
return {
"auth_type": "jwt",
"organization_id": test_user.organization_id, # Keep as UUID
"user_id": test_user.id,
"current_user": test_user
}
def override_get_db():
try:
yield db
finally:
pass
app.dependency_overrides[get_current_user] = override_get_current_user
app.dependency_overrides[require_permissions] = override_require_permissions
app.dependency_overrides[get_unified_auth] = override_get_unified_auth
app.dependency_overrides[get_db] = override_get_db
return TestClient(app)
class TestAgentWorkflowAPI:
def test_create_agent_with_workflow_disabled(self, client, test_user):
"""Test creating an agent with workflow disabled"""
agent_data = {
"name": "New Agent",
"display_name": "New Agent Display",
"description": "New agent description",
"agent_type": "customer_support",
"instructions": ["New agent instruction"],
"is_active": True,
"transfer_to_human": True,
"use_workflow": False
}
response = client.post("/api/agents", json=agent_data)
assert response.status_code == 201
data = response.json()
assert data["name"] == agent_data["name"]
assert data["use_workflow"] is False
assert data["active_workflow_id"] is None
def test_update_agent_enable_workflow(self, client, test_agent, test_workflow):
"""Test updating an agent to enable workflow"""
update_data = {
"use_workflow": True,
"active_workflow_id": str(test_workflow.id)
}
response = client.put(f"/api/agents/{test_agent.id}", json=update_data)
assert response.status_code == 200
data = response.json()
assert data["use_workflow"] is True
assert data["active_workflow_id"] == str(test_workflow.id)
def test_update_agent_disable_workflow(self, client, test_agent, test_workflow):
"""Test updating an agent to disable workflow"""
# First enable workflow
test_agent.use_workflow = True
test_agent.active_workflow_id = test_workflow.id
update_data = {
"use_workflow": False,
"active_workflow_id": None
}
response = client.put(f"/api/agents/{test_agent.id}", json=update_data)
assert response.status_code == 200
data = response.json()
assert data["use_workflow"] is False
assert data["active_workflow_id"] is None
def test_update_agent_workflow_without_id(self, client, test_agent):
"""Test updating an agent to use workflow without providing workflow ID"""
update_data = {
"use_workflow": True
# Missing active_workflow_id
}
response = client.put(f"/api/agents/{test_agent.id}", json=update_data)
# This should either fail validation or default to None
# The exact behavior depends on your API implementation
assert response.status_code in [200, 422]
def test_get_agent_with_workflow(self, client, test_agent, test_workflow):
"""Test getting an agent that has workflow enabled"""
# Set up agent with workflow
test_agent.use_workflow = True
test_agent.active_workflow_id = test_workflow.id
response = client.get(f"/api/agents/{test_agent.id}")
assert response.status_code == 200
data = response.json()
assert data["use_workflow"] is True
assert data["active_workflow_id"] == str(test_workflow.id)
def test_list_agents_with_workflow(self, client, test_agent, test_workflow):
"""Test listing agents, including those with workflows"""
# Set up agent with workflow
test_agent.use_workflow = True
test_agent.active_workflow_id = test_workflow.id
response = client.get("/api/agents/list")
assert response.status_code == 200
data = response.json()
assert len(data) >= 1
# Find our test agent in the response
agent_data = next((agent for agent in data if agent["id"] == str(test_agent.id)), None)
assert agent_data is not None
assert agent_data["use_workflow"] is True
assert agent_data["active_workflow_id"] == str(test_workflow.id)