Files
wehub-resource-sync 5a558eb09e
TypeScript SDK Compatibility V1.x E2E Tests / Select Node version matrix (push) Has been cancelled
TypeScript SDK Compatibility V1.x E2E Tests / TypeScript SDK Compatibility V1.x E2E Tests Node ${{matrix.node_version}} (push) Has been cancelled
TypeScript SDK E2E Tests / TypeScript SDK E2E Tests Node ${{matrix.node_version}} (push) Has been cancelled
Opik Optimizer - E2E Tests / build-opik (push) Has been cancelled
TypeScript SDK Compatibility V1.x E2E Tests / build-opik (push) Has been cancelled
Python SDK E2E Tests / Select Python version matrix (push) Has been cancelled
Python SDK E2E Tests / Python SDK E2E Tests ${{matrix.python_version}} (push) Has been cancelled
Python SDK E2E Tests / build-opik (push) Has been cancelled
Python SDK Compatibility V1.x E2E Tests / Select Python version matrix (push) Has been cancelled
Python SDK Compatibility V1.x E2E Tests / Python SDK Compatibility V1.x E2E Tests ${{matrix.python_version}} (push) Has been cancelled
Python SDK Compatibility V1.x E2E Tests / build-opik (push) Has been cancelled
TypeScript SDK E2E Tests / Select Node version matrix (push) Has been cancelled
TypeScript SDK E2E Tests / build-opik (push) Has been cancelled
Opik Optimizer - E2E Tests / Opik Optimizer E2E Tests Python ${{matrix.python_version}} (push) Has been cancelled
Opik Optimizer - E2E Tests / Opik Optimizer Integration Smoke Tests (push) Has been cancelled
🐙 Code Quality / detect (push) Has been cancelled
🐙 Code Quality / lint (${{ matrix.leg.name }}) (push) Has been cancelled
🐙 Code Quality / summary (push) Has been cancelled
TypeScript SDK Library Integration Tests / Check Secrets (push) Has been cancelled
TypeScript SDK Library Integration Tests / opik-vercel (Vercel AI SDK / eve) (push) Has been cancelled
SDK Library Integration Tests Runner / Check Secrets (push) Has been cancelled
SDK Library Integration Tests Runner / Missed OpenAI API Key Warning (push) Has been cancelled
SDK Library Integration Tests Runner / Build (push) Has been cancelled
SDK Library Integration Tests Runner / openai_tests (push) Has been cancelled
SDK Library Integration Tests Runner / langchain_tests (push) Has been cancelled
SDK Library Integration Tests Runner / langchain_legacy_tests (push) Has been cancelled
SDK Library Integration Tests Runner / llama_index_tests (push) Has been cancelled
SDK Library Integration Tests Runner / anthropic_tests (push) Has been cancelled
SDK Library Integration Tests Runner / mistral_tests (push) Has been cancelled
SDK Library Integration Tests Runner / groq_tests (push) Has been cancelled
SDK Library Integration Tests Runner / aisuite_tests (push) Has been cancelled
SDK Library Integration Tests Runner / haystack_tests (push) Has been cancelled
SDK Library Integration Tests Runner / dspy_tests (push) Has been cancelled
SDK Library Integration Tests Runner / crewai_v0_tests (push) Has been cancelled
SDK Library Integration Tests Runner / crewai_v1_tests (push) Has been cancelled
SDK Library Integration Tests Runner / genai_tests (push) Has been cancelled
SDK Library Integration Tests Runner / adk_tests (push) Has been cancelled
SDK Library Integration Tests Runner / adk_legacy_1_3_0_tests (push) Has been cancelled
SDK Library Integration Tests Runner / evaluation_metrics_tests (push) Has been cancelled
SDK Library Integration Tests Runner / bedrock_tests (push) Has been cancelled
SDK Library Integration Tests Runner / litellm_tests (push) Has been cancelled
SDK Library Integration Tests Runner / harbor_tests (push) Has been cancelled
SDK Library Integration Tests Runner / Slack Notification (push) Has been cancelled
Lint Opik Helm Chart / render-equality (push) Has been cancelled
Opik Optimizer - Unit Tests / Opik Optimizer Unit Tests Python ${{matrix.python_version}} (push) Has been cancelled
Python BE E2E Tests / Python BE E2E (push) Has been cancelled
Python Backend Tests / run-python-backend-tests (push) Has been cancelled
Python SDK Unit Tests / Python SDK Unit Tests ${{matrix.python_version}} (push) Has been cancelled
Release Drafter / update_release_draft (push) Has been cancelled
SDK E2E Libraries Integration Tests / Check Secrets (push) Has been cancelled
SDK E2E Libraries Integration Tests / Missed OpenAI API Key Warning (push) Has been cancelled
SDK E2E Libraries Integration Tests / build-opik (push) Has been cancelled
SDK E2E Libraries Integration Tests / E2E Lib Integration Python ${{matrix.python_version}} (push) Has been cancelled
TypeScript SDK Integration Build & Publish / build-and-publish (opik-gemini) (push) Has been cancelled
TypeScript SDK Integration Build & Publish / build-and-publish (opik-langchain) (push) Has been cancelled
TypeScript SDK Integration Build & Publish / build-and-publish (opik-openai) (push) Has been cancelled
TypeScript SDK Integration Build & Publish / build-and-publish (opik-otel) (push) Has been cancelled
TypeScript SDK Integration Build & Publish / build-and-publish (opik-vercel) (push) Has been cancelled
TypeScript SDK Build & Publish / build-and-publish (push) Has been cancelled
TypeScript SDK Unit Tests / Test on Node ${{ matrix.node-version }} (push) Has been cancelled
Backend Tests / discover-tests (push) Has been cancelled
Backend Tests / ${{ matrix.name }} (push) Has been cancelled
Build and Publish SDK / build-and-publish (push) Has been cancelled
Build Opik Docker Images / set-version (push) Has been cancelled
Build Opik Docker Images / build-backend (push) Has been cancelled
Build Opik Docker Images / build-sandbox-executor-python (push) Has been cancelled
Build Opik Docker Images / build-python-backend (push) Has been cancelled
Build Opik Docker Images / build-frontend (push) Has been cancelled
Build Opik Docker Images / create-git-tag (push) Has been cancelled
ClickHouse Migration Cluster Check / validate-clickhouse-migrations (push) Has been cancelled
Docs - Publish / run (push) Has been cancelled
E2E Tests - Post Merge (v2) / 🧪 E2E v2 Tests (${{ github.event.inputs.tier || 't1' }}) (push) Has been cancelled
E2E Tests - Post Merge (v2) / 📢 Slack Notification (push) Has been cancelled
Frontend Unit Tests / Test on Node 20 (push) Has been cancelled
Guardrails E2E Tests / Select Python version matrix (push) Has been cancelled
Guardrails E2E Tests / Guardrails E2E Tests ${{matrix.python_version}} (push) Has been cancelled
Guardrails E2E Tests / 📢 Slack Notification (push) Has been cancelled
Guardrails Backend Unit Tests / Guardrails Backend Unit Tests (push) Has been cancelled
Guardrails Backend Unit Tests / 📢 Slack Notification (push) Has been cancelled
Lint Opik Helm Chart / lint-helm-chart (Helm v3.21.0) (push) Has been cancelled
Lint Opik Helm Chart / lint-helm-chart (Helm v4.2.0) (push) Has been cancelled
Lint Opik Helm Chart / unittest-helm-chart (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:25:44 +08:00

328 lines
10 KiB
Python

"""Tests for ColBERT utility module."""
import copy
from collections.abc import Iterator
from unittest.mock import MagicMock, patch
import pytest
from opik_optimizer.utils.tools.colbert import (
ColBERTv2,
dotdict,
colbertv2_get_request,
colbertv2_post_request,
_create_session_with_retries,
)
def _json_response(payload: dict) -> MagicMock:
response = MagicMock()
response.json.return_value = payload
return response
@pytest.fixture
def mocked_requests_session() -> Iterator[MagicMock]:
"""
Patch `requests.Session` construction inside the ColBERT module.
Tests can then configure `.get` / `.post` return values or side effects without
repeating the same patch boilerplate.
"""
with patch("opik_optimizer.utils.tools.colbert.requests.Session") as session_cls:
session = MagicMock()
session_cls.return_value = session
yield session
class TestDotDict:
"""Tests for dotdict helper class."""
def test_attribute_access(self) -> None:
d = dotdict({"name": "test", "value": 42})
assert d.name == "test"
assert d.value == 42
def test_attribute_assignment(self) -> None:
d = dotdict()
d.name = "test"
d.value = 42
assert d["name"] == "test"
assert d["value"] == 42
def test_attribute_deletion(self) -> None:
d = dotdict({"name": "test", "value": 42})
del d.name
assert "name" not in d
assert d.value == 42
def test_raises_attribute_error_for_missing_key(self) -> None:
d = dotdict({"name": "test"})
with pytest.raises(AttributeError, match="has no attribute"):
_ = d.missing_key
def test_dunder_attribute_passthrough(self) -> None:
d = dotdict()
# Should not raise - dunder attributes use parent behavior
repr(d)
str(d)
def test_deepcopy(self) -> None:
d = dotdict({"nested": {"value": 42}})
copied = copy.deepcopy(d)
assert copied.nested["value"] == 42
# Modify original - copy should be independent
d.nested["value"] = 100
assert copied.nested["value"] == 42
def test_dict_operations(self) -> None:
d = dotdict({"a": 1, "b": 2})
assert len(d) == 2
assert list(d.keys()) == ["a", "b"]
assert list(d.values()) == [1, 2]
class TestCreateSessionWithRetries:
"""Tests for _create_session_with_retries function."""
def test_creates_session(self) -> None:
session = _create_session_with_retries()
assert session is not None
# Check adapters are mounted
assert "http://" in session.adapters
assert "https://" in session.adapters
def test_custom_max_retries(self) -> None:
session = _create_session_with_retries(max_retries=10)
assert session is not None
class TestColbertv2GetRequest:
"""Tests for colbertv2_get_request function."""
def test_successful_request(self, mocked_requests_session: MagicMock) -> None:
mock_response = {
"topk": [
{"text": "Result 1", "score": 0.9},
{"text": "Result 2", "score": 0.8},
]
}
mocked_requests_session.get.return_value = _json_response(mock_response)
results = colbertv2_get_request(
url="http://localhost:8000/search",
query="test query",
k=2,
)
assert len(results) == 2
assert results[0]["text"] == "Result 1"
assert results[0]["long_text"] == "Result 1"
def test_raises_on_k_greater_than_100(self) -> None:
with pytest.raises(AssertionError, match="k <= 100"):
colbertv2_get_request(
url="http://localhost:8000/search",
query="test query",
k=101,
)
def test_handles_server_error_response(
self, mocked_requests_session: MagicMock
) -> None:
mock_response = {
"error": True,
"message": "Internal server error",
}
mocked_requests_session.get.return_value = _json_response(mock_response)
with pytest.raises(Exception, match="ColBERTv2 server error"):
colbertv2_get_request(
url="http://localhost:8000/search",
query="test query",
k=5,
)
def test_retries_on_connection_error(
self, mocked_requests_session: MagicMock
) -> None:
mock_response_error = {
"error": True,
"message": "Cannot connect to host",
}
mock_response_success = {"topk": [{"text": "Result", "score": 0.9}]}
mocked_requests_session.get.side_effect = [
_json_response(mock_response_error),
_json_response(mock_response_success),
]
with patch("opik_optimizer.utils.tools.colbert.time.sleep"):
results = colbertv2_get_request(
url="http://localhost:8000/search",
query="test query",
k=1,
)
assert len(results) == 1
def test_handles_unexpected_response_format(
self, mocked_requests_session: MagicMock
) -> None:
mock_response = {"unexpected_key": "value"}
mocked_requests_session.get.return_value = _json_response(mock_response)
with pytest.raises(Exception, match="Unexpected response format"):
colbertv2_get_request(
url="http://localhost:8000/search",
query="test query",
k=5,
)
def test_handles_request_exception(
self, mocked_requests_session: MagicMock
) -> None:
import requests
mocked_requests_session.get.side_effect = requests.RequestException(
"Network error"
)
with patch("opik_optimizer.utils.tools.colbert.time.sleep"):
with pytest.raises(Exception, match="ColBERTv2 request failed"):
colbertv2_get_request(
url="http://localhost:8000/search",
query="test query",
k=5,
max_retries=2,
)
class TestColbertv2PostRequest:
"""Tests for colbertv2_post_request function."""
def test_successful_post_request(self, mocked_requests_session: MagicMock) -> None:
mock_response = {
"topk": [
{"text": "Result 1", "score": 0.9},
{"text": "Result 2", "score": 0.8},
]
}
mocked_requests_session.post.return_value = _json_response(mock_response)
results = colbertv2_post_request(
url="http://localhost:8000/search",
query="test query",
k=2,
)
assert len(results) == 2
assert results[0]["text"] == "Result 1"
def test_handles_server_error_response(
self, mocked_requests_session: MagicMock
) -> None:
mock_response = {
"error": True,
"message": "Bad request",
}
mocked_requests_session.post.return_value = _json_response(mock_response)
with pytest.raises(Exception, match="ColBERTv2 server error"):
colbertv2_post_request(
url="http://localhost:8000/search",
query="test query",
k=5,
)
def test_retries_on_connection_refused(
self, mocked_requests_session: MagicMock
) -> None:
mock_response_error = {
"error": True,
"message": "Connection refused",
}
mocked_requests_session.post.return_value = _json_response(mock_response_error)
with patch("opik_optimizer.utils.tools.colbert.time.sleep"):
with pytest.raises(Exception, match="ColBERTv2 server error"):
colbertv2_post_request(
url="http://localhost:8000/search",
query="test query",
k=5,
max_retries=2,
)
class TestColBERTv2Class:
"""Tests for ColBERTv2 wrapper class."""
def test_initialization_with_defaults(self) -> None:
client = ColBERTv2()
assert client.url == "http://0.0.0.0"
assert client.post_requests is False
def test_initialization_with_port(self) -> None:
client = ColBERTv2(url="http://localhost", port=8080)
assert client.url == "http://localhost:8080"
def test_initialization_with_post_requests(self) -> None:
client = ColBERTv2(post_requests=True)
assert client.post_requests is True
def test_call_with_get_request(self, mocked_requests_session: MagicMock) -> None:
mock_response = {
"topk": [
{"text": "Result 1", "score": 0.9},
{"text": "Result 2", "score": 0.8},
]
}
mocked_requests_session.get.return_value = _json_response(mock_response)
client = ColBERTv2(post_requests=False)
results = client(query="test", k=2)
assert len(results) == 2
assert isinstance(results[0], dotdict)
def test_call_with_post_request(self, mocked_requests_session: MagicMock) -> None:
mock_response = {
"topk": [
{"text": "Result 1", "score": 0.9},
]
}
mocked_requests_session.post.return_value = _json_response(mock_response)
client = ColBERTv2(post_requests=True)
results = client(query="test", k=1)
assert len(results) == 1
mocked_requests_session.post.assert_called_once()
def test_call_with_simplify_returns_strings(
self, mocked_requests_session: MagicMock
) -> None:
mock_response = {
"topk": [
{"text": "Result 1", "score": 0.9, "long_text": "Result 1 full"},
{"text": "Result 2", "score": 0.8, "long_text": "Result 2 full"},
]
}
mocked_requests_session.get.return_value = _json_response(mock_response)
client = ColBERTv2()
results = client(query="test", k=2, simplify=True)
assert len(results) == 2
assert isinstance(results[0], str)
def test_call_with_custom_max_retries(
self, mocked_requests_session: MagicMock
) -> None:
mock_response = {"topk": [{"text": "Result", "score": 0.9}]}
mocked_requests_session.get.return_value = _json_response(mock_response)
client = ColBERTv2()
results = client(query="test", k=1, max_retries=10)
assert len(results) == 1