mirror of
https://github.com/OpenHands/OpenHands.git
synced 2025-12-26 13:52:43 +08:00
203 lines
7.0 KiB
Python
203 lines
7.0 KiB
Python
import json
|
|
|
|
import pytest
|
|
|
|
from openhands.storage.conversation.file_conversation_store import FileConversationStore
|
|
from openhands.storage.data_models.conversation_metadata import ConversationMetadata
|
|
from openhands.storage.locations import get_conversation_metadata_filename
|
|
from openhands.storage.memory import InMemoryFileStore
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_load_store():
|
|
store = FileConversationStore(InMemoryFileStore({}))
|
|
expected = ConversationMetadata(
|
|
conversation_id='some-conversation-id',
|
|
user_id='some-user-id',
|
|
selected_repository='some-repo',
|
|
title="Let's talk about trains",
|
|
)
|
|
await store.save_metadata(expected)
|
|
found = await store.get_metadata('some-conversation-id')
|
|
assert expected == found
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_load_int_user_id():
|
|
store = FileConversationStore(
|
|
InMemoryFileStore(
|
|
{
|
|
get_conversation_metadata_filename('some-conversation-id'): json.dumps(
|
|
{
|
|
'conversation_id': 'some-conversation-id',
|
|
'user_id': '67890',
|
|
'selected_repository': 'some-repo',
|
|
'title': "Let's talk about trains",
|
|
'created_at': '2025-01-16T19:51:04.886331Z',
|
|
}
|
|
)
|
|
}
|
|
)
|
|
)
|
|
found = await store.get_metadata('some-conversation-id')
|
|
assert found.user_id == '67890'
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_search_empty():
|
|
store = FileConversationStore(InMemoryFileStore({}))
|
|
result = await store.search()
|
|
assert len(result.results) == 0
|
|
assert result.next_page_id is None
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_search_basic():
|
|
# Create test data with 3 conversations at different dates
|
|
store = FileConversationStore(
|
|
InMemoryFileStore(
|
|
{
|
|
get_conversation_metadata_filename('conv1'): json.dumps(
|
|
{
|
|
'conversation_id': 'conv1',
|
|
'user_id': '123',
|
|
'selected_repository': 'repo1',
|
|
'title': 'First conversation',
|
|
'created_at': '2025-01-16T19:51:04Z',
|
|
}
|
|
),
|
|
get_conversation_metadata_filename('conv2'): json.dumps(
|
|
{
|
|
'conversation_id': 'conv2',
|
|
'user_id': '123',
|
|
'selected_repository': 'repo1',
|
|
'title': 'Second conversation',
|
|
'created_at': '2025-01-17T19:51:04Z',
|
|
}
|
|
),
|
|
get_conversation_metadata_filename('conv3'): json.dumps(
|
|
{
|
|
'conversation_id': 'conv3',
|
|
'user_id': '123',
|
|
'selected_repository': 'repo1',
|
|
'title': 'Third conversation',
|
|
'created_at': '2025-01-15T19:51:04Z',
|
|
}
|
|
),
|
|
}
|
|
)
|
|
)
|
|
|
|
result = await store.search()
|
|
assert len(result.results) == 3
|
|
# Should be sorted by date, newest first
|
|
assert result.results[0].conversation_id == 'conv2'
|
|
assert result.results[1].conversation_id == 'conv1'
|
|
assert result.results[2].conversation_id == 'conv3'
|
|
assert result.next_page_id is None
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_search_pagination():
|
|
# Create test data with 5 conversations
|
|
store = FileConversationStore(
|
|
InMemoryFileStore(
|
|
{
|
|
get_conversation_metadata_filename(f'conv{i}'): json.dumps(
|
|
{
|
|
'conversation_id': f'conv{i}',
|
|
'user_id': '123',
|
|
'selected_repository': 'repo1',
|
|
'title': f'ServerConversation {i}',
|
|
'created_at': f'2025-01-{15 + i}T19:51:04Z',
|
|
}
|
|
)
|
|
for i in range(1, 6)
|
|
}
|
|
)
|
|
)
|
|
|
|
# Test with limit of 2
|
|
result = await store.search(limit=2)
|
|
assert len(result.results) == 2
|
|
assert result.results[0].conversation_id == 'conv5' # newest first
|
|
assert result.results[1].conversation_id == 'conv4'
|
|
assert result.next_page_id is not None
|
|
|
|
# Get next page using the next_page_id
|
|
result2 = await store.search(page_id=result.next_page_id, limit=2)
|
|
assert len(result2.results) == 2
|
|
assert result2.results[0].conversation_id == 'conv3'
|
|
assert result2.results[1].conversation_id == 'conv2'
|
|
assert result2.next_page_id is not None
|
|
|
|
# Get last page
|
|
result3 = await store.search(page_id=result2.next_page_id, limit=2)
|
|
assert len(result3.results) == 1
|
|
assert result3.results[0].conversation_id == 'conv1'
|
|
assert result3.next_page_id is None
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_search_with_invalid_conversation():
|
|
# Test handling of invalid conversation data
|
|
store = FileConversationStore(
|
|
InMemoryFileStore(
|
|
{
|
|
get_conversation_metadata_filename('conv1'): json.dumps(
|
|
{
|
|
'conversation_id': 'conv1',
|
|
'user_id': '123',
|
|
'selected_repository': 'repo1',
|
|
'title': 'Valid conversation',
|
|
'created_at': '2025-01-16T19:51:04Z',
|
|
}
|
|
),
|
|
get_conversation_metadata_filename(
|
|
'conv2'
|
|
): 'invalid json', # Invalid conversation
|
|
}
|
|
)
|
|
)
|
|
|
|
result = await store.search()
|
|
# Should return only the valid conversation
|
|
assert len(result.results) == 1
|
|
assert result.results[0].conversation_id == 'conv1'
|
|
assert result.next_page_id is None
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_get_all_metadata():
|
|
store = FileConversationStore(
|
|
InMemoryFileStore(
|
|
{
|
|
get_conversation_metadata_filename('conv1'): json.dumps(
|
|
{
|
|
'conversation_id': 'conv1',
|
|
'user_id': '123',
|
|
'selected_repository': 'repo1',
|
|
'title': 'First conversation',
|
|
'created_at': '2025-01-16T19:51:04Z',
|
|
}
|
|
),
|
|
get_conversation_metadata_filename('conv2'): json.dumps(
|
|
{
|
|
'conversation_id': 'conv2',
|
|
'user_id': '123',
|
|
'selected_repository': 'repo1',
|
|
'title': 'Second conversation',
|
|
'created_at': '2025-01-17T19:51:04Z',
|
|
}
|
|
),
|
|
}
|
|
)
|
|
)
|
|
|
|
results = await store.get_all_metadata(['conv1', 'conv2'])
|
|
assert len(results) == 2
|
|
assert results[0].conversation_id == 'conv1'
|
|
assert results[0].title == 'First conversation'
|
|
assert results[1].conversation_id == 'conv2'
|
|
assert results[1].title == 'Second conversation'
|