420 lines
12 KiB
Python
420 lines
12 KiB
Python
import pytest
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
|
|
from src import models
|
|
from src.crud.peer_card import construct_peer_card_label, get_peer_card, set_peer_card
|
|
from src.exceptions import ResourceNotFoundException
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_peer_card_get_set_roundtrip(
|
|
db_session: AsyncSession, sample_data: tuple[models.Workspace, models.Peer]
|
|
):
|
|
"""Roundtrip set/get for peer card on a valid peer."""
|
|
workspace, peer = sample_data
|
|
|
|
# Initially absent
|
|
assert (
|
|
await get_peer_card(
|
|
db_session, workspace.name, observer=peer.name, observed=peer.name
|
|
)
|
|
is None
|
|
)
|
|
|
|
# Set and read back
|
|
value_1 = ["Initial peer card text"]
|
|
await set_peer_card(
|
|
db_session,
|
|
workspace.name,
|
|
value_1,
|
|
observer=peer.name,
|
|
observed=peer.name,
|
|
)
|
|
assert (
|
|
await get_peer_card(
|
|
db_session, workspace.name, observer=peer.name, observed=peer.name
|
|
)
|
|
== value_1
|
|
)
|
|
|
|
# Update and read back
|
|
value_2 = ["Updated peer card text", "Another line"]
|
|
await set_peer_card(
|
|
db_session, workspace.name, value_2, observer=peer.name, observed=peer.name
|
|
)
|
|
assert (
|
|
await get_peer_card(
|
|
db_session, workspace.name, observer=peer.name, observed=peer.name
|
|
)
|
|
== value_2
|
|
)
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_get_peer_card_missing_peer_raises(
|
|
db_session: AsyncSession, sample_data: tuple[models.Workspace, models.Peer]
|
|
):
|
|
"""Getting a peer card for a non-existent peer should raise ResourceNotFoundException."""
|
|
workspace, _existing_peer = sample_data
|
|
with pytest.raises(ResourceNotFoundException):
|
|
await get_peer_card(
|
|
db_session,
|
|
workspace.name,
|
|
observer="missing-peer",
|
|
observed="missing-peer",
|
|
)
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_get_peer_card_missing_workspace_raises(
|
|
db_session: AsyncSession, sample_data: tuple[models.Workspace, models.Peer]
|
|
):
|
|
"""Getting a peer card for a non-existent workspace should raise ResourceNotFoundException."""
|
|
_workspace, peer = sample_data
|
|
with pytest.raises(ResourceNotFoundException):
|
|
await get_peer_card(
|
|
db_session,
|
|
"missing-workspace",
|
|
observer=peer.name,
|
|
observed=peer.name,
|
|
)
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_peer_card_empty_list(
|
|
db_session: AsyncSession, sample_data: tuple[models.Workspace, models.Peer]
|
|
):
|
|
"""Setting and getting an empty peer card should work."""
|
|
workspace, peer = sample_data
|
|
|
|
empty_card: list[str] = []
|
|
await set_peer_card(
|
|
db_session,
|
|
workspace.name,
|
|
empty_card,
|
|
observer=peer.name,
|
|
observed=peer.name,
|
|
)
|
|
assert (
|
|
await get_peer_card(
|
|
db_session, workspace.name, observer=peer.name, observed=peer.name
|
|
)
|
|
== empty_card
|
|
)
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_peer_card_multiple_lines(
|
|
db_session: AsyncSession, sample_data: tuple[models.Workspace, models.Peer]
|
|
):
|
|
"""Peer card should support multiple lines."""
|
|
workspace, peer = sample_data
|
|
|
|
multi_line_card = [
|
|
"First observation about the peer",
|
|
"Second observation about the peer",
|
|
"Third observation about the peer",
|
|
"Fourth observation about the peer",
|
|
]
|
|
await set_peer_card(
|
|
db_session,
|
|
workspace.name,
|
|
multi_line_card,
|
|
observer=peer.name,
|
|
observed=peer.name,
|
|
)
|
|
result = await get_peer_card(
|
|
db_session, workspace.name, observer=peer.name, observed=peer.name
|
|
)
|
|
assert result is not None
|
|
assert result == multi_line_card
|
|
assert len(result) == 4
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_peer_card_different_observer_observed(
|
|
db_session: AsyncSession, sample_data: tuple[models.Workspace, models.Peer]
|
|
):
|
|
"""Test peer card with different observer and observed peers."""
|
|
workspace, peer1 = sample_data
|
|
|
|
# Create second peer
|
|
peer2 = models.Peer(name="test-peer-2", workspace_name=workspace.name)
|
|
db_session.add(peer2)
|
|
await db_session.flush()
|
|
|
|
# Peer1 observes peer2
|
|
card_1_to_2 = ["Peer 1's observation of peer 2"]
|
|
await set_peer_card(
|
|
db_session,
|
|
workspace.name,
|
|
card_1_to_2,
|
|
observer=peer1.name,
|
|
observed=peer2.name,
|
|
)
|
|
|
|
# Peer2 observes peer1
|
|
card_2_to_1 = ["Peer 2's observation of peer 1"]
|
|
await set_peer_card(
|
|
db_session,
|
|
workspace.name,
|
|
card_2_to_1,
|
|
observer=peer2.name,
|
|
observed=peer1.name,
|
|
)
|
|
|
|
# Verify each card is independent
|
|
assert (
|
|
await get_peer_card(
|
|
db_session, workspace.name, observer=peer1.name, observed=peer2.name
|
|
)
|
|
== card_1_to_2
|
|
)
|
|
assert (
|
|
await get_peer_card(
|
|
db_session, workspace.name, observer=peer2.name, observed=peer1.name
|
|
)
|
|
== card_2_to_1
|
|
)
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_peer_card_self_and_other_observations(
|
|
db_session: AsyncSession, sample_data: tuple[models.Workspace, models.Peer]
|
|
):
|
|
"""Test that a peer can have both a self-observation and observations of others."""
|
|
workspace, peer1 = sample_data
|
|
|
|
# Create second peer
|
|
peer2 = models.Peer(name="test-peer-2", workspace_name=workspace.name)
|
|
db_session.add(peer2)
|
|
await db_session.flush()
|
|
|
|
# Peer1's self-observation
|
|
self_card = ["Self observation"]
|
|
await set_peer_card(
|
|
db_session,
|
|
workspace.name,
|
|
self_card,
|
|
observer=peer1.name,
|
|
observed=peer1.name,
|
|
)
|
|
|
|
# Peer1's observation of peer2
|
|
other_card = ["Observation of other peer"]
|
|
await set_peer_card(
|
|
db_session,
|
|
workspace.name,
|
|
other_card,
|
|
observer=peer1.name,
|
|
observed=peer2.name,
|
|
)
|
|
|
|
# Both should be retrievable independently
|
|
assert (
|
|
await get_peer_card(
|
|
db_session, workspace.name, observer=peer1.name, observed=peer1.name
|
|
)
|
|
== self_card
|
|
)
|
|
assert (
|
|
await get_peer_card(
|
|
db_session, workspace.name, observer=peer1.name, observed=peer2.name
|
|
)
|
|
== other_card
|
|
)
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_peer_card_multiple_observers_same_observed(
|
|
db_session: AsyncSession, sample_data: tuple[models.Workspace, models.Peer]
|
|
):
|
|
"""Test that multiple peers can observe the same peer with different cards."""
|
|
workspace, peer1 = sample_data
|
|
|
|
# Create two more peers
|
|
peer2 = models.Peer(name="test-peer-2", workspace_name=workspace.name)
|
|
peer3 = models.Peer(name="test-peer-3", workspace_name=workspace.name)
|
|
db_session.add_all([peer2, peer3])
|
|
await db_session.flush()
|
|
|
|
# Both peer2 and peer3 observe peer1
|
|
card_2_to_1 = ["Peer 2's view of peer 1"]
|
|
card_3_to_1 = ["Peer 3's view of peer 1"]
|
|
|
|
await set_peer_card(
|
|
db_session,
|
|
workspace.name,
|
|
card_2_to_1,
|
|
observer=peer2.name,
|
|
observed=peer1.name,
|
|
)
|
|
await set_peer_card(
|
|
db_session,
|
|
workspace.name,
|
|
card_3_to_1,
|
|
observer=peer3.name,
|
|
observed=peer1.name,
|
|
)
|
|
|
|
# Each observer should have their own independent card
|
|
assert (
|
|
await get_peer_card(
|
|
db_session, workspace.name, observer=peer2.name, observed=peer1.name
|
|
)
|
|
== card_2_to_1
|
|
)
|
|
assert (
|
|
await get_peer_card(
|
|
db_session, workspace.name, observer=peer3.name, observed=peer1.name
|
|
)
|
|
== card_3_to_1
|
|
)
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_peer_card_update_does_not_affect_others(
|
|
db_session: AsyncSession, sample_data: tuple[models.Workspace, models.Peer]
|
|
):
|
|
"""Test that updating one peer card doesn't affect other peer cards."""
|
|
workspace, peer1 = sample_data
|
|
|
|
# Create second peer
|
|
peer2 = models.Peer(name="test-peer-2", workspace_name=workspace.name)
|
|
db_session.add(peer2)
|
|
await db_session.flush()
|
|
|
|
# Set initial cards
|
|
card_1 = ["Peer 1 self observation"]
|
|
card_2 = ["Peer 1's observation of peer 2"]
|
|
|
|
await set_peer_card(
|
|
db_session,
|
|
workspace.name,
|
|
card_1,
|
|
observer=peer1.name,
|
|
observed=peer1.name,
|
|
)
|
|
await set_peer_card(
|
|
db_session,
|
|
workspace.name,
|
|
card_2,
|
|
observer=peer1.name,
|
|
observed=peer2.name,
|
|
)
|
|
|
|
# Update one card
|
|
new_card_1 = ["Updated self observation"]
|
|
await set_peer_card(
|
|
db_session,
|
|
workspace.name,
|
|
new_card_1,
|
|
observer=peer1.name,
|
|
observed=peer1.name,
|
|
)
|
|
|
|
# Verify only the updated card changed
|
|
assert (
|
|
await get_peer_card(
|
|
db_session, workspace.name, observer=peer1.name, observed=peer1.name
|
|
)
|
|
== new_card_1
|
|
)
|
|
assert (
|
|
await get_peer_card(
|
|
db_session, workspace.name, observer=peer1.name, observed=peer2.name
|
|
)
|
|
== card_2
|
|
)
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_peer_card_special_characters(
|
|
db_session: AsyncSession, sample_data: tuple[models.Workspace, models.Peer]
|
|
):
|
|
"""Test that peer cards handle special characters correctly."""
|
|
workspace, peer = sample_data
|
|
|
|
special_card = [
|
|
"Line with special chars: @#$%^&*()",
|
|
"Line with unicode: 你好世界 🌍",
|
|
"Line with quotes: \"double\" and 'single'",
|
|
"Line with newlines embedded\\n",
|
|
]
|
|
await set_peer_card(
|
|
db_session,
|
|
workspace.name,
|
|
special_card,
|
|
observer=peer.name,
|
|
observed=peer.name,
|
|
)
|
|
result = await get_peer_card(
|
|
db_session, workspace.name, observer=peer.name, observed=peer.name
|
|
)
|
|
assert result == special_card
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_peer_card_large_content(
|
|
db_session: AsyncSession, sample_data: tuple[models.Workspace, models.Peer]
|
|
):
|
|
"""Test that peer cards can handle large amounts of content."""
|
|
workspace, peer = sample_data
|
|
|
|
# Create a large peer card with many observations
|
|
large_card = [f"Observation number {i}" for i in range(100)]
|
|
await set_peer_card(
|
|
db_session,
|
|
workspace.name,
|
|
large_card,
|
|
observer=peer.name,
|
|
observed=peer.name,
|
|
)
|
|
result = await get_peer_card(
|
|
db_session, workspace.name, observer=peer.name, observed=peer.name
|
|
)
|
|
assert result == large_card
|
|
assert result is not None
|
|
assert len(result) == 100
|
|
|
|
|
|
def test_construct_helpers_labels():
|
|
"""Helper label constructors return expected values."""
|
|
assert construct_peer_card_label(observer="a", observed="a") == "peer_card"
|
|
assert construct_peer_card_label(observer="a", observed="b") == "b_peer_card"
|
|
|
|
|
|
def test_construct_peer_card_label_with_special_chars():
|
|
"""Test label construction with special characters in peer names."""
|
|
# Test with dashes and underscores
|
|
assert (
|
|
construct_peer_card_label(observer="peer-1", observed="peer-2")
|
|
== "peer-2_peer_card"
|
|
)
|
|
assert (
|
|
construct_peer_card_label(observer="peer_1", observed="peer_2")
|
|
== "peer_2_peer_card"
|
|
)
|
|
|
|
# Test with same observer and observed with special chars
|
|
assert (
|
|
construct_peer_card_label(observer="peer-1", observed="peer-1") == "peer_card"
|
|
)
|
|
|
|
|
|
def test_construct_peer_card_label_edge_cases():
|
|
"""Test label construction edge cases."""
|
|
# Test with empty strings (though this shouldn't happen in practice)
|
|
assert construct_peer_card_label(observer="", observed="") == "peer_card"
|
|
assert construct_peer_card_label(observer="a", observed="") == "_peer_card"
|
|
|
|
# Test with very long peer names
|
|
long_name = "a" * 100
|
|
assert (
|
|
construct_peer_card_label(observer=long_name, observed=long_name) == "peer_card"
|
|
)
|
|
assert (
|
|
construct_peer_card_label(observer="a", observed=long_name)
|
|
== f"{long_name}_peer_card"
|
|
)
|