357 lines
13 KiB
Python
357 lines
13 KiB
Python
import pytest
|
|
from fastapi.testclient import TestClient
|
|
|
|
from sdks.python.src.honcho.api_types import QueueStatusResponse
|
|
from sdks.python.src.honcho.client import Honcho
|
|
from sdks.python.src.honcho.message import Message
|
|
from sdks.python.src.honcho.pagination import AsyncPage, SyncPage
|
|
from sdks.python.src.honcho.peer import Peer
|
|
from sdks.python.src.honcho.session import Session
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_client_init(client_fixture: tuple[Honcho, str], client: TestClient):
|
|
"""
|
|
Tests that the Honcho SDK clients can be initialized and that a workspace
|
|
is created on first use.
|
|
"""
|
|
honcho_client, client_type = client_fixture
|
|
|
|
if client_type == "async":
|
|
assert honcho_client.workspace_id == "sdk-test-workspace-async"
|
|
# Use the sync client to avoid mixing ASGI transports in this test.
|
|
honcho_client.get_metadata()
|
|
else:
|
|
assert honcho_client.workspace_id == "sdk-test-workspace-sync"
|
|
honcho_client.get_metadata()
|
|
|
|
# Check all pages to find the workspace
|
|
found_workspace = False
|
|
page = 1
|
|
|
|
while not found_workspace:
|
|
res = client.post("/v3/workspaces/list", json={}, params={"page": page})
|
|
assert res.status_code == 200
|
|
|
|
data = res.json()
|
|
workspaces = data["items"]
|
|
workspace_ids = [w["id"] for w in workspaces]
|
|
|
|
if honcho_client.workspace_id in workspace_ids:
|
|
found_workspace = True
|
|
break
|
|
|
|
# Check if there are more pages
|
|
if page >= data.get("pages", 1) or len(workspaces) == 0:
|
|
break
|
|
|
|
page += 1
|
|
|
|
assert (
|
|
found_workspace
|
|
), f"Workspace {honcho_client.workspace_id} not found in any page of results"
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_workspace_metadata(client_fixture: tuple[Honcho, str]):
|
|
"""
|
|
Tests getting and setting metadata on a workspace.
|
|
"""
|
|
honcho_client, client_type = client_fixture
|
|
|
|
if client_type == "async":
|
|
metadata = await honcho_client.aio.get_metadata()
|
|
assert metadata == {}
|
|
await honcho_client.aio.set_metadata({"foo": "bar"})
|
|
metadata = await honcho_client.aio.get_metadata()
|
|
assert metadata == {"foo": "bar"}
|
|
else:
|
|
metadata = honcho_client.get_metadata()
|
|
assert metadata == {}
|
|
honcho_client.set_metadata({"foo": "bar"})
|
|
metadata = honcho_client.get_metadata()
|
|
assert metadata == {"foo": "bar"}
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_workspaces(client_fixture: tuple[Honcho, str]):
|
|
"""
|
|
Tests listing available workspaces.
|
|
"""
|
|
honcho_client, client_type = client_fixture
|
|
|
|
if client_type == "async":
|
|
workspaces = await honcho_client.aio.workspaces()
|
|
else:
|
|
workspaces = honcho_client.workspaces()
|
|
|
|
# workspaces returns a paginated Page of workspace ID strings
|
|
assert hasattr(workspaces, "items")
|
|
assert isinstance(workspaces.items, list)
|
|
# Each item should be a string (workspace ID)
|
|
for ws_id in workspaces.items:
|
|
assert isinstance(ws_id, str)
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_client_list_peers_and_sessions(
|
|
client_fixture: tuple[Honcho, str],
|
|
):
|
|
"""
|
|
Tests listing peers and sessions at the client level.
|
|
"""
|
|
honcho_client, client_type = client_fixture
|
|
|
|
if client_type == "async":
|
|
peers_page = await honcho_client.aio.peers()
|
|
assert isinstance(peers_page, AsyncPage)
|
|
assert len(peers_page.items) == 0
|
|
|
|
sessions_page = await honcho_client.aio.sessions()
|
|
assert isinstance(sessions_page, AsyncPage)
|
|
assert len(sessions_page.items) == 0
|
|
|
|
peer = await honcho_client.aio.peer(id="test-peer-client")
|
|
assert isinstance(peer, Peer)
|
|
await peer.aio.get_metadata() # Creates the peer
|
|
|
|
peers_page = await honcho_client.aio.peers()
|
|
assert len(peers_page.items) == 1
|
|
|
|
session = await honcho_client.aio.session(id="test-session-client")
|
|
assert isinstance(session, Session)
|
|
await session.aio.get_metadata() # Creates the session
|
|
|
|
sessions_page = await honcho_client.aio.sessions()
|
|
assert len(sessions_page.items) == 1
|
|
else:
|
|
peers_page = honcho_client.peers()
|
|
assert isinstance(peers_page, SyncPage)
|
|
assert len(list(peers_page)) == 0
|
|
|
|
sessions_page = honcho_client.sessions()
|
|
assert isinstance(sessions_page, SyncPage)
|
|
assert len(list(sessions_page)) == 0
|
|
|
|
peer = honcho_client.peer(id="test-peer-client")
|
|
assert isinstance(peer, Peer)
|
|
peer.get_metadata()
|
|
|
|
peers_page = honcho_client.peers()
|
|
assert len(list(peers_page)) == 1
|
|
|
|
session = honcho_client.session(id="test-session-client")
|
|
assert isinstance(session, Session)
|
|
session.get_metadata()
|
|
|
|
sessions_page = honcho_client.sessions()
|
|
assert len(list(sessions_page)) == 1
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_workspace_search(client_fixture: tuple[Honcho, str]):
|
|
"""
|
|
Tests searching for messages within a workspace.
|
|
"""
|
|
honcho_client, client_type = client_fixture
|
|
search_query = "a unique message for workspace search"
|
|
|
|
if client_type == "async":
|
|
session = await honcho_client.aio.session(id="search-session-ws")
|
|
assert isinstance(session, Session)
|
|
user = await honcho_client.aio.peer(id="search-user-ws")
|
|
assert isinstance(user, Peer)
|
|
await session.aio.add_messages([user.message(search_query)])
|
|
|
|
search_results = await honcho_client.aio.search(search_query)
|
|
assert isinstance(search_results, list)
|
|
assert len(search_results) >= 1
|
|
assert search_query in search_results[0].content
|
|
else:
|
|
session = honcho_client.session(id="search-session-ws")
|
|
assert isinstance(session, Session)
|
|
user = honcho_client.peer(id="search-user-ws")
|
|
assert isinstance(user, Peer)
|
|
session.add_messages([user.message(search_query)])
|
|
|
|
search_results = honcho_client.search(search_query)
|
|
assert isinstance(search_results, list)
|
|
assert len(search_results) >= 1
|
|
assert search_query in search_results[0].content
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_get_queue_status(client_fixture: tuple[Honcho, str]):
|
|
"""
|
|
Tests getting queue status with various parameter combinations.
|
|
"""
|
|
honcho_client, client_type = client_fixture
|
|
|
|
def assert_queue_status(status: QueueStatusResponse) -> None:
|
|
assert status.total_work_units >= 0
|
|
assert status.completed_work_units >= 0
|
|
assert status.in_progress_work_units >= 0
|
|
assert status.pending_work_units >= 0
|
|
assert status.total_work_units == (
|
|
status.completed_work_units
|
|
+ status.in_progress_work_units
|
|
+ status.pending_work_units
|
|
)
|
|
|
|
if status.sessions is not None:
|
|
for session_status in status.sessions.values():
|
|
assert session_status.total_work_units == (
|
|
session_status.completed_work_units
|
|
+ session_status.in_progress_work_units
|
|
+ session_status.pending_work_units
|
|
)
|
|
|
|
if client_type == "async":
|
|
# Test with no parameters - this should work in the SDK even though API requires at least one
|
|
status = await honcho_client.aio.queue_status()
|
|
assert isinstance(status, QueueStatusResponse)
|
|
assert_queue_status(status)
|
|
|
|
# Test with peer_id only
|
|
peer = await honcho_client.aio.peer(id="test-peer-queue-status")
|
|
await peer.aio.get_metadata() # Create the peer
|
|
status = await honcho_client.aio.queue_status(observer=peer.id)
|
|
assert isinstance(status, QueueStatusResponse)
|
|
assert_queue_status(status)
|
|
|
|
# Test with session_id only
|
|
session = await honcho_client.aio.session(id="test-session-queue-status")
|
|
await session.aio.get_metadata() # Create the session
|
|
status = await honcho_client.aio.queue_status(session=session.id)
|
|
assert isinstance(status, QueueStatusResponse)
|
|
assert_queue_status(status)
|
|
|
|
# Test with both peer and session
|
|
status = await honcho_client.aio.queue_status(
|
|
observer=peer.id, session=session.id
|
|
)
|
|
assert isinstance(status, QueueStatusResponse)
|
|
assert_queue_status(status)
|
|
|
|
# Test with sender
|
|
status = await honcho_client.aio.queue_status(observer=peer.id, sender=peer.id)
|
|
assert isinstance(status, QueueStatusResponse)
|
|
assert_queue_status(status)
|
|
else:
|
|
# Test with no parameters
|
|
status = honcho_client.queue_status()
|
|
assert isinstance(status, QueueStatusResponse)
|
|
assert_queue_status(status)
|
|
|
|
# Test with peer_id only
|
|
peer = honcho_client.peer(id="test-peer-queue-status")
|
|
peer.get_metadata() # Create the peer
|
|
status = honcho_client.queue_status(observer=peer.id)
|
|
assert isinstance(status, QueueStatusResponse)
|
|
assert_queue_status(status)
|
|
|
|
# Test with session_id only
|
|
session = honcho_client.session(id="test-session-queue-status")
|
|
session.get_metadata() # Create the session
|
|
status = honcho_client.queue_status(session=session.id)
|
|
assert isinstance(status, QueueStatusResponse)
|
|
assert_queue_status(status)
|
|
|
|
# Test with both peer and session
|
|
status = honcho_client.queue_status(observer=peer.id, session=session.id)
|
|
assert isinstance(status, QueueStatusResponse)
|
|
assert_queue_status(status)
|
|
|
|
# Test with sender
|
|
status = honcho_client.queue_status(observer=peer.id, sender=peer.id)
|
|
assert isinstance(status, QueueStatusResponse)
|
|
assert_queue_status(status)
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_update_message_with_message_object(
|
|
client_fixture: tuple[Honcho, str],
|
|
):
|
|
"""
|
|
Tests updating message metadata using a Message object.
|
|
"""
|
|
honcho_client, client_type = client_fixture
|
|
|
|
if client_type == "async":
|
|
session = await honcho_client.aio.session(id="test-update-msg-session")
|
|
peer = await honcho_client.aio.peer(id="test-update-msg-peer")
|
|
|
|
# Create a message
|
|
await session.aio.add_messages([peer.message("test message")])
|
|
messages = await session.aio.messages()
|
|
assert len(messages) >= 1
|
|
message = messages[0]
|
|
assert isinstance(message, Message)
|
|
|
|
# Update using Message object
|
|
updated = await session.aio.update_message(message, {"key": "value"})
|
|
assert isinstance(updated, Message)
|
|
assert updated.metadata == {"key": "value"}
|
|
assert updated.id == message.id
|
|
else:
|
|
session = honcho_client.session(id="test-update-msg-session")
|
|
peer = honcho_client.peer(id="test-update-msg-peer")
|
|
|
|
# Create a message
|
|
session.add_messages([peer.message("test message")])
|
|
messages = session.messages()
|
|
assert len(messages) >= 1
|
|
message = messages[0]
|
|
assert isinstance(message, Message)
|
|
|
|
# Update using Message object
|
|
updated = session.update_message(message, {"key": "value"})
|
|
assert isinstance(updated, Message)
|
|
assert updated.metadata == {"key": "value"}
|
|
assert updated.id == message.id
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_update_message_with_message_id(
|
|
client_fixture: tuple[Honcho, str],
|
|
):
|
|
"""
|
|
Tests updating message metadata using message_id string.
|
|
"""
|
|
honcho_client, client_type = client_fixture
|
|
|
|
if client_type == "async":
|
|
session = await honcho_client.aio.session(id="test-update-msg-id-session")
|
|
peer = await honcho_client.aio.peer(id="test-update-msg-id-peer")
|
|
|
|
# Create a message
|
|
await session.aio.add_messages([peer.message("test message")])
|
|
|
|
messages = await session.aio.messages()
|
|
assert len(messages) >= 1
|
|
message = messages[0]
|
|
assert message.metadata == {}
|
|
|
|
# Update using message_id string
|
|
updated = await session.aio.update_message(message.id, {"updated": True})
|
|
assert isinstance(updated, Message)
|
|
assert updated.metadata == {"updated": True}
|
|
assert updated.id == message.id
|
|
else:
|
|
session = honcho_client.session(id="test-update-msg-id-session")
|
|
peer = honcho_client.peer(id="test-update-msg-id-peer")
|
|
|
|
# Create a message
|
|
messages = session.add_messages([peer.message("test message")])
|
|
|
|
messages = session.messages()
|
|
assert len(messages) >= 1
|
|
message = messages[0]
|
|
assert message.metadata == {}
|
|
|
|
# Update using message_id string
|
|
updated = session.update_message(message.id, {"updated": True})
|
|
assert isinstance(updated, Message)
|
|
assert updated.metadata == {"updated": True}
|
|
assert updated.id == message.id
|