flakestorm/tests/test_adapters.py

465 lines
16 KiB
Python

"""Tests for agent adapters."""
import pytest
class TestHTTPAgentAdapter:
"""Tests for HTTP agent adapter."""
def test_adapter_creation(self):
"""Test adapter can be created."""
from flakestorm.core.protocol import HTTPAgentAdapter
adapter = HTTPAgentAdapter(
endpoint="http://localhost:8000/chat",
timeout=30000, # 30 seconds in milliseconds
)
assert adapter is not None
assert adapter.endpoint == "http://localhost:8000/chat"
def test_adapter_has_invoke_method(self):
"""Adapter has invoke method."""
from flakestorm.core.protocol import HTTPAgentAdapter
adapter = HTTPAgentAdapter(endpoint="http://localhost:8000/chat")
assert hasattr(adapter, "invoke")
assert callable(adapter.invoke)
def test_timeout_conversion(self):
"""Timeout is converted to seconds."""
from flakestorm.core.protocol import HTTPAgentAdapter
adapter = HTTPAgentAdapter(
endpoint="http://localhost:8000/chat",
timeout=30000,
)
# Timeout should be stored in seconds
assert adapter.timeout == 30.0
def test_custom_headers(self):
"""Custom headers can be set."""
from flakestorm.core.protocol import HTTPAgentAdapter
headers = {"Authorization": "Bearer token123"}
adapter = HTTPAgentAdapter(
endpoint="http://localhost:8000/chat",
headers=headers,
)
assert adapter.headers == headers
class TestPythonAgentAdapter:
"""Tests for Python function adapter."""
def test_adapter_creation_with_callable(self):
"""Test adapter can be created with a callable."""
from flakestorm.core.protocol import PythonAgentAdapter
def my_agent(input: str) -> str:
return f"Response to: {input}"
adapter = PythonAgentAdapter(my_agent)
assert adapter is not None
assert adapter.agent == my_agent
def test_adapter_has_invoke_method(self):
"""Adapter has invoke method."""
from flakestorm.core.protocol import PythonAgentAdapter
def my_agent(input: str) -> str:
return f"Response to: {input}"
adapter = PythonAgentAdapter(my_agent)
assert hasattr(adapter, "invoke")
assert callable(adapter.invoke)
class TestLangChainAgentAdapter:
"""Tests for LangChain agent adapter."""
@pytest.fixture
def langchain_config(self):
"""Create a test LangChain agent config."""
from flakestorm.core.config import AgentConfig, AgentType
return AgentConfig(
endpoint="my_agent:chain",
type=AgentType.LANGCHAIN,
timeout=60000, # 60 seconds in milliseconds
)
def test_adapter_creation(self, langchain_config):
"""Test adapter can be created."""
from flakestorm.core.protocol import LangChainAgentAdapter
adapter = LangChainAgentAdapter(langchain_config)
assert adapter is not None
class TestAgentAdapterFactory:
"""Tests for adapter factory function."""
def test_creates_http_adapter(self):
"""Factory creates HTTP adapter for HTTP type."""
from flakestorm.core.config import AgentConfig, AgentType
from flakestorm.core.protocol import HTTPAgentAdapter, create_agent_adapter
config = AgentConfig(
endpoint="http://localhost:8000/chat",
type=AgentType.HTTP,
)
adapter = create_agent_adapter(config)
assert isinstance(adapter, HTTPAgentAdapter)
def test_creates_python_adapter(self):
"""Python adapter can be created with a callable."""
from flakestorm.core.protocol import PythonAgentAdapter
def my_agent(input: str) -> str:
return f"Response: {input}"
adapter = PythonAgentAdapter(my_agent)
assert isinstance(adapter, PythonAgentAdapter)
def test_creates_langchain_adapter(self):
"""Factory creates LangChain adapter for LangChain type."""
from flakestorm.core.config import AgentConfig, AgentType
from flakestorm.core.protocol import LangChainAgentAdapter, create_agent_adapter
config = AgentConfig(
endpoint="my_agent:chain",
type=AgentType.LANGCHAIN,
)
adapter = create_agent_adapter(config)
assert isinstance(adapter, LangChainAgentAdapter)
class TestAgentResponse:
"""Tests for AgentResponse data class."""
def test_response_creation(self):
"""Test AgentResponse can be created."""
from flakestorm.core.protocol import AgentResponse
response = AgentResponse(
output="Hello, world!",
latency_ms=150.5,
)
assert response.output == "Hello, world!"
assert response.latency_ms == 150.5
def test_response_with_error(self):
"""Test AgentResponse with error."""
from flakestorm.core.protocol import AgentResponse
response = AgentResponse(
output="",
latency_ms=100.0,
error="Connection timeout",
)
assert response.error == "Connection timeout"
assert not response.success
def test_response_success_property(self):
"""Test AgentResponse success property."""
from flakestorm.core.protocol import AgentResponse
# Success case
success_response = AgentResponse(
output="Response",
latency_ms=100.0,
)
assert success_response.success is True
# Error case
error_response = AgentResponse(
output="",
latency_ms=100.0,
error="Failed",
)
assert error_response.success is False
class TestStructuredInputParser:
"""Tests for structured input parsing."""
def test_parse_colon_format(self):
"""Test parsing key:value format."""
from flakestorm.core.protocol import parse_structured_input
input_text = "Industry: Fitness tech\nProduct: AI trainer"
result = parse_structured_input(input_text)
assert result["industry"] == "Fitness tech"
assert result["product"] == "AI trainer"
def test_parse_equals_format(self):
"""Test parsing key=value format."""
from flakestorm.core.protocol import parse_structured_input
input_text = "Industry=Fitness tech\nProduct=AI trainer"
result = parse_structured_input(input_text)
assert result["industry"] == "Fitness tech"
assert result["product"] == "AI trainer"
def test_parse_dash_format(self):
"""Test parsing key - value format."""
from flakestorm.core.protocol import parse_structured_input
input_text = "Industry - Fitness tech\nProduct - AI trainer"
result = parse_structured_input(input_text)
assert result["industry"] == "Fitness tech"
assert result["product"] == "AI trainer"
def test_parse_multiline(self):
"""Test parsing multi-line structured input."""
from flakestorm.core.protocol import parse_structured_input
input_text = """
Industry: Fitness tech
Product/Service: AI personal trainer app
Business Model: B2C
Target Market: fitness enthusiasts
Description: An app that provides personalized workout plans
"""
result = parse_structured_input(input_text)
assert result["industry"] == "Fitness tech"
assert result["productservice"] == "AI personal trainer app"
assert result["businessmodel"] == "B2C"
assert result["targetmarket"] == "fitness enthusiasts"
assert (
result["description"] == "An app that provides personalized workout plans"
)
def test_parse_empty_input(self):
"""Test parsing empty input."""
from flakestorm.core.protocol import parse_structured_input
result = parse_structured_input("")
assert result == {}
def test_parse_normalizes_keys(self):
"""Test that keys are normalized (lowercase, no spaces)."""
from flakestorm.core.protocol import parse_structured_input
input_text = "Product Name: AI Trainer\nBusiness-Model: B2C"
result = parse_structured_input(input_text)
# Keys should be normalized
assert "productname" in result
assert "businessmodel" in result
class TestTemplateEngine:
"""Tests for template rendering."""
def test_render_simple_template(self):
"""Test rendering template with {prompt}."""
from flakestorm.core.protocol import render_template
template = '{"message": "{prompt}"}'
prompt = "Book a flight"
result = render_template(template, prompt)
assert result == {"message": "Book a flight"}
def test_render_with_structured_data(self):
"""Test rendering template with structured data fields."""
from flakestorm.core.protocol import render_template
template = '{"industry": "{industry}", "product": "{productname}"}'
prompt = "test"
structured_data = {"industry": "Fitness tech", "productname": "AI trainer"}
result = render_template(template, prompt, structured_data)
assert result == {"industry": "Fitness tech", "product": "AI trainer"}
def test_render_json_template(self):
"""Test rendering JSON template."""
from flakestorm.core.protocol import render_template
template = '{"messages": [{"role": "user", "content": "{prompt}"}]}'
prompt = "Hello"
result = render_template(template, prompt)
assert isinstance(result, dict)
assert result["messages"][0]["content"] == "Hello"
def test_render_string_template(self):
"""Test rendering non-JSON template."""
from flakestorm.core.protocol import render_template
template = "q={prompt}&format=json"
prompt = "search query"
result = render_template(template, prompt)
assert result == "q=search query&format=json"
class TestResponseExtractor:
"""Tests for response extraction."""
def test_extract_simple_key(self):
"""Test extracting simple key from response."""
from flakestorm.core.protocol import extract_response
data = {"output": "Hello world"}
result = extract_response(data, "output")
assert result == "Hello world"
def test_extract_dot_notation(self):
"""Test extracting nested field using dot notation."""
from flakestorm.core.protocol import extract_response
data = {"data": {"result": "Success"}}
result = extract_response(data, "data.result")
assert result == "Success"
def test_extract_jsonpath(self):
"""Test extracting using JSONPath-style notation."""
from flakestorm.core.protocol import extract_response
data = {"data": {"result": "Success"}}
result = extract_response(data, "$.data.result")
assert result == "Success"
def test_extract_default_fallback(self):
"""Test default extraction when path is None."""
from flakestorm.core.protocol import extract_response
data = {"output": "Hello"}
result = extract_response(data, None)
assert result == "Hello"
def test_extract_fallback_to_response(self):
"""Test fallback to 'response' key."""
from flakestorm.core.protocol import extract_response
data = {"response": "Hello"}
result = extract_response(data, None)
assert result == "Hello"
def test_extract_missing_path(self):
"""Test extraction with missing path falls back to default."""
from flakestorm.core.protocol import extract_response
data = {"output": "Hello"}
result = extract_response(data, "nonexistent.path")
# Should fall back to default extraction
assert result == "Hello"
class TestHTTPAgentAdapterNewFeatures:
"""Tests for new HTTP adapter features."""
def test_adapter_with_method(self):
"""Test adapter creation with custom HTTP method."""
from flakestorm.core.protocol import HTTPAgentAdapter
adapter = HTTPAgentAdapter(
endpoint="http://localhost:8000/api",
method="GET",
)
assert adapter.method == "GET"
def test_adapter_with_request_template(self):
"""Test adapter creation with request template."""
from flakestorm.core.protocol import HTTPAgentAdapter
template = '{"message": "{prompt}"}'
adapter = HTTPAgentAdapter(
endpoint="http://localhost:8000/api",
request_template=template,
)
assert adapter.request_template == template
def test_adapter_with_response_path(self):
"""Test adapter creation with response path."""
from flakestorm.core.protocol import HTTPAgentAdapter
adapter = HTTPAgentAdapter(
endpoint="http://localhost:8000/api",
response_path="$.data.result",
)
assert adapter.response_path == "$.data.result"
def test_adapter_with_query_params(self):
"""Test adapter creation with query parameters."""
from flakestorm.core.protocol import HTTPAgentAdapter
query_params = {"api_key": "test", "format": "json"}
adapter = HTTPAgentAdapter(
endpoint="http://localhost:8000/api",
query_params=query_params,
)
assert adapter.query_params == query_params
def test_adapter_parse_structured_input_flag(self):
"""Test adapter with parse_structured_input flag."""
from flakestorm.core.protocol import HTTPAgentAdapter
adapter = HTTPAgentAdapter(
endpoint="http://localhost:8000/api",
parse_structured_input=False,
)
assert adapter.parse_structured_input is False
def test_adapter_all_new_features(self):
"""Test adapter with all new features combined."""
from flakestorm.core.protocol import HTTPAgentAdapter
adapter = HTTPAgentAdapter(
endpoint="http://localhost:8000/api",
method="PUT",
request_template='{"content": "{prompt}"}',
response_path="$.result",
query_params={"version": "v1"},
parse_structured_input=True,
timeout=60000,
headers={"Authorization": "Bearer token"},
)
assert adapter.method == "PUT"
assert adapter.request_template == '{"content": "{prompt}"}'
assert adapter.response_path == "$.result"
assert adapter.query_params == {"version": "v1"}
assert adapter.parse_structured_input is True
assert adapter.timeout == 60.0
assert adapter.headers == {"Authorization": "Bearer token"}
class TestAgentAdapterFactoryNewFeatures:
"""Tests for factory with new config fields."""
def test_factory_passes_all_fields(self):
"""Test factory passes all new config fields to HTTP adapter."""
from flakestorm.core.config import AgentConfig, AgentType
from flakestorm.core.protocol import HTTPAgentAdapter, create_agent_adapter
config = AgentConfig(
endpoint="http://localhost:8000/api",
type=AgentType.HTTP,
method="POST",
request_template='{"message": "{prompt}"}',
response_path="$.reply",
query_params={"key": "value"},
parse_structured_input=True,
)
adapter = create_agent_adapter(config)
assert isinstance(adapter, HTTPAgentAdapter)
assert adapter.method == "POST"
assert adapter.request_template == '{"message": "{prompt}"}'
assert adapter.response_path == "$.reply"
assert adapter.query_params == {"key": "value"}
assert adapter.parse_structured_input is True