942 lines
30 KiB
Python
942 lines
30 KiB
Python
from typing import Any
|
|
|
|
import pytest
|
|
from fastapi.testclient import TestClient
|
|
from nanoid import generate as generate_nanoid
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
|
|
from src import crud
|
|
from src.models import Peer, Workspace
|
|
|
|
|
|
def test_get_or_create_peer(client: TestClient, sample_data: tuple[Workspace, Peer]):
|
|
test_workspace, _ = sample_data
|
|
name = str(generate_nanoid())
|
|
response = client.post(
|
|
f"/v3/workspaces/{test_workspace.name}/peers",
|
|
json={"name": name, "metadata": {"peer_key": "peer_value"}},
|
|
)
|
|
assert response.status_code in [200, 201]
|
|
data = response.json()
|
|
assert data["id"] == name
|
|
assert data["metadata"] == {"peer_key": "peer_value"}
|
|
assert "id" in data
|
|
|
|
|
|
def test_get_or_create_peer_with_configuration(
|
|
client: TestClient, sample_data: tuple[Workspace, Peer]
|
|
):
|
|
"""Test peer creation with configuration parameter"""
|
|
test_workspace, _ = sample_data
|
|
name = str(generate_nanoid())
|
|
configuration = {"experimental": True, "beta": False}
|
|
|
|
response = client.post(
|
|
f"/v3/workspaces/{test_workspace.name}/peers",
|
|
json={"name": name, "configuration": configuration},
|
|
)
|
|
assert response.status_code in [200, 201]
|
|
data = response.json()
|
|
assert data["id"] == name
|
|
assert data["configuration"] == configuration
|
|
|
|
|
|
def test_get_or_create_peer_with_all_optional_params(
|
|
client: TestClient, sample_data: tuple[Workspace, Peer]
|
|
):
|
|
"""Test peer creation with all optional parameters"""
|
|
test_workspace, _ = sample_data
|
|
name = str(generate_nanoid())
|
|
metadata = {"key": "value", "number": 42}
|
|
configuration = {"feature1": True, "feature2": False}
|
|
|
|
response = client.post(
|
|
f"/v3/workspaces/{test_workspace.name}/peers",
|
|
json={"name": name, "metadata": metadata, "configuration": configuration},
|
|
)
|
|
assert response.status_code in [200, 201]
|
|
data = response.json()
|
|
assert data["id"] == name
|
|
assert data["metadata"] == metadata
|
|
assert data["configuration"] == configuration
|
|
|
|
|
|
def test_get_or_create_existing_peer(
|
|
client: TestClient, sample_data: tuple[Workspace, Peer]
|
|
):
|
|
test_workspace, _ = sample_data
|
|
name = str(generate_nanoid())
|
|
|
|
# Create the peer
|
|
response = client.post(
|
|
f"/v3/workspaces/{test_workspace.name}/peers",
|
|
json={"name": name, "metadata": {"peer_key": "peer_value"}},
|
|
)
|
|
assert response.status_code in [200, 201]
|
|
peer1 = response.json()
|
|
|
|
# Try to create the same peer again - should return existing peer
|
|
response = client.post(
|
|
f"/v3/workspaces/{test_workspace.name}/peers",
|
|
json={"name": name, "metadata": {"peer_key": "peer_value"}},
|
|
)
|
|
assert response.status_code in [200, 201]
|
|
peer2 = response.json()
|
|
|
|
# Both should be the same peer
|
|
assert peer1["id"] == peer2["id"]
|
|
assert peer1["metadata"] == peer2["metadata"]
|
|
|
|
|
|
def test_get_peers(client: TestClient, sample_data: tuple[Workspace, Peer]):
|
|
test_workspace, _ = sample_data
|
|
|
|
# Create a few peers with metadata
|
|
response = client.post(
|
|
f"/v3/workspaces/{test_workspace.name}/peers",
|
|
json={"name": str(generate_nanoid()), "metadata": {"peer_key": "peer_value"}},
|
|
)
|
|
response = client.post(
|
|
f"/v3/workspaces/{test_workspace.name}/peers",
|
|
json={"name": str(generate_nanoid()), "metadata": {"peer_key": "peer_value"}},
|
|
)
|
|
response = client.post(
|
|
f"/v3/workspaces/{test_workspace.name}/peers",
|
|
json={"name": str(generate_nanoid()), "metadata": {"peer_key": "peer_value2"}},
|
|
)
|
|
|
|
# Get all peers
|
|
response = client.post(
|
|
f"/v3/workspaces/{test_workspace.name}/peers/list",
|
|
json={},
|
|
)
|
|
assert response.status_code == 200
|
|
data = response.json()
|
|
assert "items" in data
|
|
assert len(data["items"]) > 0
|
|
|
|
# Get peers with simple filter (backward compatibility)
|
|
response = client.post(
|
|
f"/v3/workspaces/{test_workspace.name}/peers/list",
|
|
json={"filters": {"metadata": {"peer_key": "peer_value"}}},
|
|
)
|
|
assert response.status_code == 200
|
|
data = response.json()
|
|
assert "items" in data
|
|
assert len(data["items"]) == 2
|
|
assert data["items"][0]["metadata"]["peer_key"] == "peer_value"
|
|
|
|
# Test new filter with NOT operator
|
|
response = client.post(
|
|
f"/v3/workspaces/{test_workspace.name}/peers/list",
|
|
json={"filters": {"NOT": [{"metadata": {"peer_key": "peer_value2"}}]}},
|
|
)
|
|
assert response.status_code == 200
|
|
data = response.json()
|
|
assert "items" in data
|
|
# Should find peers that don't have peer_key = "peer_value2"
|
|
# This includes the 2 peers with "peer_value" + the sample peer with empty metadata
|
|
assert len(data["items"]) == 3
|
|
|
|
|
|
def test_get_peers_with_empty_filter(
|
|
client: TestClient, sample_data: tuple[Workspace, Peer]
|
|
):
|
|
"""Test peer listing with empty filter object"""
|
|
test_workspace, _ = sample_data
|
|
|
|
response = client.post(
|
|
f"/v3/workspaces/{test_workspace.name}/peers/list", json={"filters": {}}
|
|
)
|
|
assert response.status_code == 200
|
|
data = response.json()
|
|
assert "items" in data
|
|
assert isinstance(data["items"], list)
|
|
|
|
|
|
def test_get_peers_with_null_filter(
|
|
client: TestClient, sample_data: tuple[Workspace, Peer]
|
|
):
|
|
"""Test peer listing with null filter"""
|
|
test_workspace, _ = sample_data
|
|
|
|
response = client.post(
|
|
f"/v3/workspaces/{test_workspace.name}/peers/list", json={"filters": None}
|
|
)
|
|
assert response.status_code == 200
|
|
data = response.json()
|
|
assert "items" in data
|
|
assert isinstance(data["items"], list)
|
|
|
|
|
|
def test_update_peer(client: TestClient, sample_data: tuple[Workspace, Peer]):
|
|
test_workspace, test_peer = sample_data
|
|
response = client.put(
|
|
f"/v3/workspaces/{test_workspace.name}/peers/{test_peer.name}",
|
|
json={"metadata": {"new_key": "new_value"}},
|
|
)
|
|
assert response.status_code == 200
|
|
data = response.json()
|
|
assert data["metadata"] == {"new_key": "new_value"}
|
|
|
|
|
|
def test_update_peer_with_configuration(
|
|
client: TestClient, sample_data: tuple[Workspace, Peer]
|
|
):
|
|
"""Test peer update with configuration parameter"""
|
|
test_workspace, test_peer = sample_data
|
|
configuration = {"new_feature": True, "legacy_feature": False}
|
|
|
|
response = client.put(
|
|
f"/v3/workspaces/{test_workspace.name}/peers/{test_peer.name}",
|
|
json={"configuration": configuration},
|
|
)
|
|
assert response.status_code == 200
|
|
data = response.json()
|
|
assert data["configuration"] == configuration
|
|
|
|
|
|
def test_update_peer_with_all_optional_params(
|
|
client: TestClient, sample_data: tuple[Workspace, Peer]
|
|
):
|
|
"""Test peer update with both metadata and configuration"""
|
|
test_workspace, test_peer = sample_data
|
|
metadata = {"updated_key": "updated_value", "count": 100}
|
|
configuration = {"experimental": True, "beta": True}
|
|
|
|
response = client.put(
|
|
f"/v3/workspaces/{test_workspace.name}/peers/{test_peer.name}",
|
|
json={"metadata": metadata, "configuration": configuration},
|
|
)
|
|
assert response.status_code == 200
|
|
data = response.json()
|
|
assert data["metadata"] == metadata
|
|
assert data["configuration"] == configuration
|
|
|
|
|
|
def test_update_peer_with_null_metadata(
|
|
client: TestClient, sample_data: tuple[Workspace, Peer]
|
|
):
|
|
"""Test peer update with null metadata"""
|
|
test_workspace, test_peer = sample_data
|
|
|
|
# First set some metadata
|
|
client.put(
|
|
f"/v3/workspaces/{test_workspace.name}/peers/{test_peer.name}",
|
|
json={"metadata": {"temp": "value"}},
|
|
)
|
|
|
|
# Then clear it with null
|
|
response = client.put(
|
|
f"/v3/workspaces/{test_workspace.name}/peers/{test_peer.name}",
|
|
json={"metadata": None},
|
|
)
|
|
assert response.status_code == 200
|
|
data = response.json()
|
|
assert "metadata" in data
|
|
|
|
|
|
def test_update_peer_with_null_configuration(
|
|
client: TestClient, sample_data: tuple[Workspace, Peer]
|
|
):
|
|
"""Test peer update with null configuration"""
|
|
test_workspace, test_peer = sample_data
|
|
|
|
response = client.put(
|
|
f"/v3/workspaces/{test_workspace.name}/peers/{test_peer.name}",
|
|
json={"configuration": None},
|
|
)
|
|
assert response.status_code == 200
|
|
data = response.json()
|
|
assert "configuration" in data
|
|
|
|
|
|
def test_get_sessions_for_peer_no_sessions(
|
|
client: TestClient, sample_data: tuple[Workspace, Peer]
|
|
):
|
|
test_workspace, test_peer = sample_data
|
|
|
|
# Get sessions for the peer
|
|
response = client.post(
|
|
f"/v3/workspaces/{test_workspace.name}/peers/{test_peer.name}/sessions",
|
|
json={},
|
|
)
|
|
assert response.status_code == 200
|
|
data = response.json()
|
|
assert "items" in data
|
|
|
|
|
|
def test_get_sessions_for_peer(client: TestClient, sample_data: tuple[Workspace, Peer]):
|
|
test_workspace, test_peer = sample_data
|
|
|
|
# Create session for the peer
|
|
session_name = str(generate_nanoid())
|
|
create_response = client.post(
|
|
f"/v3/workspaces/{test_workspace.name}/sessions",
|
|
json={"id": session_name, "peer_names": {test_peer.name: {}}},
|
|
)
|
|
assert create_response.status_code in [200, 201]
|
|
created_session = create_response.json()
|
|
assert created_session["id"] == session_name
|
|
|
|
# Now get sessions for the peer and validate the session is returned
|
|
response = client.post(
|
|
f"/v3/workspaces/{test_workspace.name}/peers/{test_peer.name}/sessions",
|
|
)
|
|
assert response.status_code == 200
|
|
data = response.json()
|
|
assert "items" in data
|
|
# Check that the created session is in the returned items
|
|
session_ids = [item["id"] for item in data["items"]]
|
|
assert session_name in session_ids
|
|
assert len(data["items"]) == 1
|
|
|
|
|
|
def test_get_sessions_for_peer_with_empty_filter(
|
|
client: TestClient, sample_data: tuple[Workspace, Peer]
|
|
):
|
|
"""Test getting sessions for peer with empty filter object"""
|
|
test_workspace, test_peer = sample_data
|
|
|
|
response = client.post(
|
|
f"/v3/workspaces/{test_workspace.name}/peers/{test_peer.name}/sessions",
|
|
json={"filters": {}},
|
|
)
|
|
assert response.status_code == 200
|
|
data = response.json()
|
|
assert "items" in data
|
|
assert isinstance(data["items"], list)
|
|
|
|
|
|
def test_chat(
|
|
client: TestClient,
|
|
sample_data: tuple[Workspace, Peer],
|
|
):
|
|
test_workspace, test_peer = sample_data
|
|
target_peer = str(generate_nanoid())
|
|
|
|
# Test chat endpoint
|
|
response = client.post(
|
|
f"/v3/workspaces/{test_workspace.name}/peers/{test_peer.name}/chat",
|
|
json={
|
|
"query": "Hello, how are you?",
|
|
"stream": False,
|
|
"target": target_peer,
|
|
},
|
|
)
|
|
assert response.status_code == 200
|
|
data = response.json()
|
|
assert "content" in data
|
|
|
|
|
|
def test_chat_with_optional_params(
|
|
client: TestClient,
|
|
sample_data: tuple[Workspace, Peer],
|
|
):
|
|
"""Test chat endpoint with optional parameters"""
|
|
|
|
test_workspace, test_peer = sample_data
|
|
session_id = str(generate_nanoid())
|
|
|
|
# Create a session first
|
|
client.post(
|
|
f"/v3/workspaces/{test_workspace.name}/sessions",
|
|
json={"id": session_id, "peer_names": {test_peer.name: {}}},
|
|
)
|
|
|
|
# Test chat without optional parameters
|
|
response = client.post(
|
|
f"/v3/workspaces/{test_workspace.name}/peers/{test_peer.name}/chat",
|
|
json={
|
|
"query": "Hello, how are you?",
|
|
"stream": False,
|
|
"session_id": session_id,
|
|
},
|
|
)
|
|
assert response.status_code == 200
|
|
data = response.json()
|
|
assert "content" in data
|
|
|
|
|
|
def test_get_peer_representation_with_session(
|
|
client: TestClient, sample_data: tuple[Workspace, Peer]
|
|
):
|
|
"""Test peer representation with session_id parameter"""
|
|
test_workspace, test_peer = sample_data
|
|
session_id = str(generate_nanoid())
|
|
|
|
# Create a session first
|
|
client.post(
|
|
f"/v3/workspaces/{test_workspace.name}/sessions",
|
|
json={"id": session_id, "peer_names": {test_peer.name: {}}},
|
|
)
|
|
|
|
# Test representation scoped to session
|
|
response = client.post(
|
|
f"/v3/workspaces/{test_workspace.name}/peers/{test_peer.name}/representation",
|
|
json={
|
|
"session_id": session_id,
|
|
},
|
|
)
|
|
assert response.status_code == 200
|
|
data = response.json()
|
|
assert "representation" in data
|
|
assert isinstance(data["representation"], str)
|
|
|
|
|
|
def test_get_peer_representation_global(
|
|
client: TestClient, sample_data: tuple[Workspace, Peer]
|
|
):
|
|
"""Test peer representation without session_id (global representation)"""
|
|
test_workspace, test_peer = sample_data
|
|
|
|
# Test global representation (no session_id)
|
|
response = client.post(
|
|
f"/v3/workspaces/{test_workspace.name}/peers/{test_peer.name}/representation",
|
|
json={},
|
|
)
|
|
assert response.status_code == 200
|
|
data = response.json()
|
|
assert "representation" in data
|
|
assert isinstance(data["representation"], str)
|
|
|
|
|
|
def test_get_peer_representation_with_target(
|
|
client: TestClient, sample_data: tuple[Workspace, Peer]
|
|
):
|
|
"""Test peer representation with target parameter"""
|
|
test_workspace, test_peer = sample_data
|
|
|
|
# Create a second peer to be the target
|
|
target_peer_name = str(generate_nanoid())
|
|
client.post(
|
|
f"/v3/workspaces/{test_workspace.name}/peers",
|
|
json={"name": target_peer_name, "metadata": {}},
|
|
)
|
|
|
|
# Test representation of target from observer's perspective
|
|
response = client.post(
|
|
f"/v3/workspaces/{test_workspace.name}/peers/{test_peer.name}/representation",
|
|
json={
|
|
"target": target_peer_name,
|
|
},
|
|
)
|
|
assert response.status_code == 200
|
|
data = response.json()
|
|
assert "representation" in data
|
|
assert isinstance(data["representation"], str)
|
|
|
|
|
|
def test_get_peer_representation_with_search_query(
|
|
client: TestClient, sample_data: tuple[Workspace, Peer]
|
|
):
|
|
"""Test peer representation with search_query parameter"""
|
|
test_workspace, test_peer = sample_data
|
|
|
|
# Test representation with semantic search query
|
|
response = client.post(
|
|
f"/v3/workspaces/{test_workspace.name}/peers/{test_peer.name}/representation",
|
|
json={
|
|
"search_query": "What are my interests and hobbies?",
|
|
},
|
|
)
|
|
assert response.status_code == 200
|
|
data = response.json()
|
|
assert "representation" in data
|
|
|
|
|
|
def test_get_peer_representation_with_search_top_k(
|
|
client: TestClient, sample_data: tuple[Workspace, Peer]
|
|
):
|
|
"""Test peer representation with search_top_k parameter"""
|
|
test_workspace, test_peer = sample_data
|
|
|
|
# Test with valid search_top_k values
|
|
for top_k in [1, 10, 50, 100]:
|
|
response = client.post(
|
|
f"/v3/workspaces/{test_workspace.name}/peers/{test_peer.name}/representation",
|
|
json={
|
|
"search_query": "test query",
|
|
"search_top_k": top_k,
|
|
},
|
|
)
|
|
assert response.status_code == 200
|
|
data = response.json()
|
|
assert "representation" in data
|
|
|
|
|
|
def test_get_peer_representation_with_search_max_distance(
|
|
client: TestClient, sample_data: tuple[Workspace, Peer]
|
|
):
|
|
"""Test peer representation with search_max_distance parameter"""
|
|
test_workspace, test_peer = sample_data
|
|
|
|
# Test with valid search_max_distance values (0.0 to 1.0)
|
|
for max_distance in [0.0, 0.5, 0.8, 1.0]:
|
|
response = client.post(
|
|
f"/v3/workspaces/{test_workspace.name}/peers/{test_peer.name}/representation",
|
|
json={
|
|
"search_query": "test query",
|
|
"search_max_distance": max_distance,
|
|
},
|
|
)
|
|
assert response.status_code == 200
|
|
data = response.json()
|
|
assert "representation" in data
|
|
|
|
|
|
def test_get_peer_representation_with_include_most_frequent(
|
|
client: TestClient, sample_data: tuple[Workspace, Peer]
|
|
):
|
|
"""Test peer representation with include_most_frequent parameter"""
|
|
test_workspace, test_peer = sample_data
|
|
|
|
# Test with include_most_frequent=True
|
|
response = client.post(
|
|
f"/v3/workspaces/{test_workspace.name}/peers/{test_peer.name}/representation",
|
|
json={
|
|
"search_query": "test query",
|
|
"include_most_frequent": True,
|
|
},
|
|
)
|
|
assert response.status_code == 200
|
|
data = response.json()
|
|
assert "representation" in data
|
|
|
|
# Test with include_most_frequent=False
|
|
response = client.post(
|
|
f"/v3/workspaces/{test_workspace.name}/peers/{test_peer.name}/representation",
|
|
json={
|
|
"search_query": "test query",
|
|
"include_most_frequent": False,
|
|
},
|
|
)
|
|
assert response.status_code == 200
|
|
data = response.json()
|
|
assert "representation" in data
|
|
|
|
|
|
def test_get_peer_representation_with_max_observations(
|
|
client: TestClient, sample_data: tuple[Workspace, Peer]
|
|
):
|
|
"""Test peer representation with max_observations parameter"""
|
|
test_workspace, test_peer = sample_data
|
|
|
|
# Test with various max_observations values
|
|
for max_obs in [1, 25, 50, 100]:
|
|
response = client.post(
|
|
f"/v3/workspaces/{test_workspace.name}/peers/{test_peer.name}/representation",
|
|
json={
|
|
"search_query": "test query",
|
|
"max_observations": max_obs,
|
|
},
|
|
)
|
|
assert response.status_code == 200
|
|
data = response.json()
|
|
assert "representation" in data
|
|
|
|
|
|
def test_get_peer_representation_with_all_parameters(
|
|
client: TestClient, sample_data: tuple[Workspace, Peer]
|
|
):
|
|
"""Test peer representation with all optional parameters"""
|
|
test_workspace, test_peer = sample_data
|
|
session_id = str(generate_nanoid())
|
|
|
|
# Create a session and target peer
|
|
target_peer_name = str(generate_nanoid())
|
|
client.post(
|
|
f"/v3/workspaces/{test_workspace.name}/peers",
|
|
json={"name": target_peer_name, "metadata": {}},
|
|
)
|
|
client.post(
|
|
f"/v3/workspaces/{test_workspace.name}/sessions",
|
|
json={
|
|
"id": session_id,
|
|
"peer_names": {test_peer.name: {}, target_peer_name: {}},
|
|
},
|
|
)
|
|
|
|
# Test with all parameters
|
|
response = client.post(
|
|
f"/v3/workspaces/{test_workspace.name}/peers/{test_peer.name}/representation",
|
|
json={
|
|
"session_id": session_id,
|
|
"target": target_peer_name,
|
|
"search_query": "What do I know about this peer?",
|
|
"search_top_k": 15,
|
|
"search_max_distance": 0.75,
|
|
"include_most_frequent": True,
|
|
"max_observations": 30,
|
|
},
|
|
)
|
|
assert response.status_code == 200
|
|
data = response.json()
|
|
assert "representation" in data
|
|
assert isinstance(data["representation"], str)
|
|
|
|
|
|
def test_get_peer_representation_boundary_values(
|
|
client: TestClient, sample_data: tuple[Workspace, Peer]
|
|
):
|
|
"""Test peer representation with boundary values for numeric parameters"""
|
|
test_workspace, test_peer = sample_data
|
|
|
|
# Test minimum values
|
|
response = client.post(
|
|
f"/v3/workspaces/{test_workspace.name}/peers/{test_peer.name}/representation",
|
|
json={
|
|
"search_query": "test",
|
|
"search_top_k": 1,
|
|
"search_max_distance": 0.0,
|
|
"max_observations": 1,
|
|
},
|
|
)
|
|
assert response.status_code == 200
|
|
|
|
# Test maximum values
|
|
response = client.post(
|
|
f"/v3/workspaces/{test_workspace.name}/peers/{test_peer.name}/representation",
|
|
json={
|
|
"search_query": "test",
|
|
"search_top_k": 100,
|
|
"search_max_distance": 1.0,
|
|
"max_observations": 100,
|
|
},
|
|
)
|
|
assert response.status_code == 200
|
|
|
|
|
|
def test_get_peer_representation_default_max_observations(
|
|
client: TestClient, sample_data: tuple[Workspace, Peer]
|
|
):
|
|
"""Test that max_observations defaults to 25 when not provided"""
|
|
test_workspace, test_peer = sample_data
|
|
|
|
# Test without max_observations - should use default of 25
|
|
response = client.post(
|
|
f"/v3/workspaces/{test_workspace.name}/peers/{test_peer.name}/representation",
|
|
json={
|
|
"search_query": "test query",
|
|
},
|
|
)
|
|
assert response.status_code == 200
|
|
data = response.json()
|
|
assert "representation" in data
|
|
|
|
|
|
def test_search_peer(client: TestClient, sample_data: tuple[Workspace, Peer]):
|
|
"""Test the peer search functionality"""
|
|
test_workspace, test_peer = sample_data
|
|
|
|
# Add some messages to search through
|
|
client.post(
|
|
f"/v3/workspaces/{test_workspace.name}/peers/{test_peer.name}/sessions/test_session/messages",
|
|
json={
|
|
"messages": [
|
|
{"content": "Search this content", "peer_id": test_peer.name},
|
|
{"content": "Another searchable message", "peer_id": test_peer.name},
|
|
]
|
|
},
|
|
)
|
|
|
|
# Search with a query
|
|
response = client.post(
|
|
f"/v3/workspaces/{test_workspace.name}/peers/{test_peer.name}/search",
|
|
json={"query": "search query", "limit": 10},
|
|
)
|
|
assert response.status_code == 200
|
|
data = response.json()
|
|
|
|
# Response should be a direct list of messages
|
|
assert isinstance(data, list)
|
|
|
|
|
|
def test_search_peer_empty_query(
|
|
client: TestClient, sample_data: tuple[Workspace, Peer]
|
|
):
|
|
"""Test peer search with empty query"""
|
|
test_workspace, test_peer = sample_data
|
|
|
|
# Search with empty query
|
|
response = client.post(
|
|
f"/v3/workspaces/{test_workspace.name}/peers/{test_peer.name}/search",
|
|
json={"query": "", "limit": 10},
|
|
)
|
|
assert response.status_code == 200
|
|
data = response.json()
|
|
|
|
# Response should be a direct list of messages
|
|
assert isinstance(data, list)
|
|
|
|
|
|
def test_search_peer_nonexistent(
|
|
client: TestClient, sample_data: tuple[Workspace, Peer]
|
|
):
|
|
"""Test searching a peer that doesn't exist"""
|
|
test_workspace, _ = sample_data
|
|
nonexistent_peer_id = str(generate_nanoid())
|
|
|
|
response = client.post(
|
|
f"/v3/workspaces/{test_workspace.name}/peers/{nonexistent_peer_id}/search",
|
|
json={"query": "test query", "limit": 10},
|
|
)
|
|
assert response.status_code == 200
|
|
data: list[dict[str, Any]] = response.json()
|
|
assert isinstance(data, list)
|
|
assert len(data) == 0
|
|
|
|
|
|
def test_search_peer_with_messages(
|
|
client: TestClient, sample_data: tuple[Workspace, Peer]
|
|
):
|
|
"""Test peer search with actual messages"""
|
|
test_workspace, test_peer = sample_data
|
|
|
|
# Add some messages to search through
|
|
client.post(
|
|
f"/v3/workspaces/{test_workspace.name}/peers/{test_peer.name}/sessions/test_session/messages",
|
|
json={
|
|
"messages": [
|
|
{"content": "Search this content", "peer_id": test_peer.name},
|
|
{"content": "Another searchable message", "peer_id": test_peer.name},
|
|
]
|
|
},
|
|
)
|
|
|
|
# Search for content
|
|
response = client.post(
|
|
f"/v3/workspaces/{test_workspace.name}/peers/{test_peer.name}/search",
|
|
json={"query": "search", "limit": 10},
|
|
)
|
|
assert response.status_code == 200
|
|
data = response.json()
|
|
|
|
# Response should be a direct list of messages
|
|
assert isinstance(data, list)
|
|
|
|
|
|
def test_search_peer_with_limit(
|
|
client: TestClient, sample_data: tuple[Workspace, Peer]
|
|
):
|
|
"""Test peer search with custom limit"""
|
|
test_workspace, test_peer = sample_data
|
|
|
|
# Add some messages to search through
|
|
client.post(
|
|
f"/v3/workspaces/{test_workspace.name}/peers/{test_peer.name}/sessions/test_session/messages",
|
|
json={
|
|
"messages": [
|
|
{"content": "Search this content", "peer_id": test_peer.name},
|
|
{"content": "Another searchable message", "peer_id": test_peer.name},
|
|
{"content": "More searchable content", "peer_id": test_peer.name},
|
|
]
|
|
},
|
|
)
|
|
|
|
# Search with custom limit
|
|
response = client.post(
|
|
f"/v3/workspaces/{test_workspace.name}/peers/{test_peer.name}/search",
|
|
json={"query": "search", "limit": 2},
|
|
)
|
|
|
|
assert response.status_code == 200
|
|
data: list[dict[str, Any]] = response.json()
|
|
assert isinstance(data, list)
|
|
# Should not exceed the limit
|
|
assert len(data) <= 2
|
|
|
|
|
|
def test_get_peers_with_complex_filter(
|
|
client: TestClient, sample_data: tuple[Workspace, Peer]
|
|
):
|
|
"""Test peer listing with complex filters"""
|
|
test_workspace, _ = sample_data
|
|
|
|
# Create peers with different metadata
|
|
for i in range(3):
|
|
client.post(
|
|
f"/v3/workspaces/{test_workspace.name}/peers",
|
|
json={
|
|
"name": str(generate_nanoid()),
|
|
"metadata": {"index": i, "type": "test"},
|
|
},
|
|
)
|
|
|
|
# Test complex filter combination
|
|
response = client.post(
|
|
f"/v3/workspaces/{test_workspace.name}/peers/list",
|
|
json={
|
|
"filters": {
|
|
"AND": [
|
|
{"metadata": {"type": "test"}},
|
|
{"metadata": {"index": {"gte": 1}}},
|
|
]
|
|
}
|
|
},
|
|
)
|
|
assert response.status_code == 200
|
|
data = response.json()
|
|
# for each peer returned, assert that the metadata["index"] fits our filter
|
|
for peer in data["items"]:
|
|
assert (
|
|
peer["metadata"].get("index", 0) >= 1
|
|
and peer["metadata"].get("type", "") == "test"
|
|
)
|
|
assert "items" in data
|
|
|
|
|
|
def test_update_peer_all_fields(
|
|
client: TestClient, sample_data: tuple[Workspace, Peer]
|
|
):
|
|
"""Test peer update with all possible fields"""
|
|
test_workspace, test_peer = sample_data
|
|
|
|
# Test updating both metadata and configuration
|
|
metadata = {"updated": True, "version": 2}
|
|
configuration = {"features": {"new_feature": True}}
|
|
|
|
response = client.put(
|
|
f"/v3/workspaces/{test_workspace.name}/peers/{test_peer.name}",
|
|
json={"metadata": metadata, "configuration": configuration},
|
|
)
|
|
assert response.status_code == 200
|
|
data = response.json()
|
|
assert data["metadata"] == metadata
|
|
assert data["configuration"] == configuration
|
|
|
|
|
|
def test_get_peer_card(client: TestClient, sample_data: tuple[Workspace, Peer]):
|
|
"""Test the peer cards endpoint"""
|
|
test_workspace, observer_peer = sample_data
|
|
|
|
# Create a second peer (the target/observed peer)
|
|
target_peer_name = str(generate_nanoid())
|
|
response = client.post(
|
|
f"/v3/workspaces/{test_workspace.name}/peers",
|
|
json={"name": target_peer_name},
|
|
)
|
|
assert response.status_code in [200, 201]
|
|
|
|
# Test getting observer's own card (should return null initially)
|
|
response = client.get(
|
|
f"/v3/workspaces/{test_workspace.name}/peers/{observer_peer.name}/card"
|
|
)
|
|
assert response.status_code == 200
|
|
data = response.json()
|
|
assert data["peer_card"] is None
|
|
|
|
# Test getting card for target peer (should return null initially)
|
|
response = client.get(
|
|
f"/v3/workspaces/{test_workspace.name}/peers/{observer_peer.name}/card",
|
|
params={"target": target_peer_name},
|
|
)
|
|
assert response.status_code == 200
|
|
data = response.json()
|
|
assert data["peer_card"] is None
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_get_peer_card_with_data(
|
|
client: TestClient,
|
|
db_session: AsyncSession,
|
|
sample_data: tuple[Workspace, Peer],
|
|
):
|
|
"""Test the peer cards endpoint with actual peer card data"""
|
|
test_workspace, observer_peer = sample_data
|
|
|
|
# Create a second peer (the target/observed peer)
|
|
target_peer_name = str(generate_nanoid())
|
|
response = client.post(
|
|
f"/v3/workspaces/{test_workspace.name}/peers",
|
|
json={"name": target_peer_name},
|
|
)
|
|
assert response.status_code in [200, 201]
|
|
|
|
# Set up peer cards using the database directly
|
|
# Set a self-card for the observer peer
|
|
self_card_content = ["I am a helpful AI assistant", "I enjoy learning about users"]
|
|
await crud.set_peer_card(
|
|
db_session,
|
|
test_workspace.name,
|
|
self_card_content,
|
|
observer=observer_peer.name,
|
|
observed=observer_peer.name,
|
|
)
|
|
|
|
# Set a card for the observer describing the target peer
|
|
target_card_content = ["This peer seems friendly", "They ask good questions"]
|
|
await crud.set_peer_card(
|
|
db_session,
|
|
test_workspace.name,
|
|
target_card_content,
|
|
observer=observer_peer.name,
|
|
observed=target_peer_name,
|
|
)
|
|
|
|
# Test getting observer's own card
|
|
response = client.get(
|
|
f"/v3/workspaces/{test_workspace.name}/peers/{observer_peer.name}/card"
|
|
)
|
|
assert response.status_code == 200
|
|
data = response.json()
|
|
assert data["peer_card"] == self_card_content
|
|
|
|
# Test getting card for target peer
|
|
response = client.get(
|
|
f"/v3/workspaces/{test_workspace.name}/peers/{observer_peer.name}/card",
|
|
params={"target": target_peer_name},
|
|
)
|
|
assert response.status_code == 200
|
|
data = response.json()
|
|
assert data["peer_card"] == target_card_content
|
|
|
|
|
|
def test_set_peer_card(client: TestClient, sample_data: tuple[Workspace, Peer]):
|
|
"""Test setting peer cards via the PUT endpoint."""
|
|
test_workspace, observer_peer = sample_data
|
|
|
|
# Create a target peer
|
|
target_peer_name = str(generate_nanoid())
|
|
response = client.post(
|
|
f"/v3/workspaces/{test_workspace.name}/peers",
|
|
json={"name": target_peer_name},
|
|
)
|
|
assert response.status_code in [200, 201]
|
|
|
|
# Set the observer's own card
|
|
self_card = ["I am a test peer", "I like writing tests"]
|
|
response = client.put(
|
|
f"/v3/workspaces/{test_workspace.name}/peers/{observer_peer.name}/card",
|
|
json={"peer_card": self_card},
|
|
)
|
|
assert response.status_code == 200
|
|
data = response.json()
|
|
assert data["peer_card"] == self_card
|
|
|
|
# Verify with GET
|
|
response = client.get(
|
|
f"/v3/workspaces/{test_workspace.name}/peers/{observer_peer.name}/card"
|
|
)
|
|
assert response.status_code == 200
|
|
assert response.json()["peer_card"] == self_card
|
|
|
|
# Set a card for the target peer
|
|
target_card = ["Target is helpful", "Target knows Python"]
|
|
response = client.put(
|
|
f"/v3/workspaces/{test_workspace.name}/peers/{observer_peer.name}/card",
|
|
params={"target": target_peer_name},
|
|
json={"peer_card": target_card},
|
|
)
|
|
assert response.status_code == 200
|
|
data = response.json()
|
|
assert data["peer_card"] == target_card
|
|
|
|
# Verify with GET
|
|
response = client.get(
|
|
f"/v3/workspaces/{test_workspace.name}/peers/{observer_peer.name}/card",
|
|
params={"target": target_peer_name},
|
|
)
|
|
assert response.status_code == 200
|
|
assert response.json()["peer_card"] == target_card
|