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

236 lines
8.5 KiB
Python

"""
Contract tests for Java-Python RQ integration.
These tests verify that:
1. Java writes jobs with plain JSON 'data' (no zlib) in RQ format
2. Java enqueues job IDs into the RQ list key: 'rq:queue:<queue_name>'
3. Python RQ (JSONSerializer + default Job) can process Java-created jobs
4. Job format matches RQ expectations
"""
import pytest
fakeredis = pytest.importorskip("fakeredis")
import json
import uuid
from datetime import datetime
@pytest.fixture
def redis_conn():
"""Mocked Redis using fakeredis (no external service)."""
return fakeredis.FakeRedis(decode_responses=False)
def create_java_style_job(redis_conn, job_id=None, function='test_function', args=None, kwargs=None):
"""
Create a job in Redis using the same format as Java RqPublisher.
Simulates Java by:
- Writing 'rq:job:{id}' hash with 'data' as plain JSON: [func, null, args, kwargs]
- Pushing the job id onto the RQ list: 'rq:queue:<queue_name>'
"""
if job_id is None:
job_id = str(uuid.uuid4())
if args is None:
args = ['test_arg']
if kwargs is None:
kwargs = {}
queue_name = 'opik:optimizer-cloud'
job_key = f'rq:job:{job_id}'
# Create data field: [function, null, args, kwargs] as plain JSON string
data_array = [function, None, args, kwargs]
json_data = json.dumps(data_array)
# Create HASH fields
now = datetime.utcnow().isoformat() + 'Z'
job_fields = {
b'data': json_data.encode('utf-8'),
b'created_at': now.encode('utf-8'),
b'enqueued_at': now.encode('utf-8'),
b'status': b'queued',
b'origin': queue_name.encode('utf-8'),
b'timeout': b'3600'
}
# Store in Redis
redis_conn.hset(job_key, mapping=job_fields)
redis_conn.expire(job_key, 3600)
redis_conn.rpush(f'rq:queue:{queue_name}', job_id)
return job_id, queue_name
class TestJavaPythonRqContract:
"""Test Java-Python RQ integration contract."""
def test_java_plain_json_data_format(self):
"""Verify Java contract uses plain JSON string for 'data'."""
test_data = ["function_name", None, ["arg1", "arg2"], {"key": "value"}]
json_str = json.dumps(test_data)
# Assert it's valid JSON and round-trips
parsed = json.loads(json_str)
assert parsed == test_data
def test_python_can_read_java_created_job(self, redis_conn):
"""Verify Python can read job created by Java."""
# Given: Job created with Java format
job_id, queue_name = create_java_style_job(
redis_conn,
function='opik_backend.rq_worker.process_optimizer_job',
args=['Test message']
)
try:
# When: Python reads the job
job_key = f'rq:job:{job_id}'
job_data = redis_conn.hgetall(job_key)
# Then: All fields are present
assert b'data' in job_data
assert b'created_at' in job_data
assert b'enqueued_at' in job_data
assert b'status' in job_data
assert b'origin' in job_data
assert b'timeout' in job_data
# And: Data is plain JSON
parsed = json.loads(job_data[b'data'].decode('utf-8'))
# And: Data has correct RQ format
assert len(parsed) == 4
assert parsed[0] == 'opik_backend.rq_worker.process_optimizer_job'
assert parsed[1] is None
assert parsed[2] == ['Test message']
assert parsed[3] == {}
# And: Status is correct
assert job_data[b'status'] == b'queued'
finally:
# Cleanup
redis_conn.delete(f'rq:job:{job_id}')
redis_conn.delete(queue_name)
def test_rq_job_format_matches_expectations(self):
"""Verify RQ job 'data' array structure."""
# Given: Expected RQ format
expected_format = {
'function': str, # Import path to Python function
'callback': type(None),# Result callback placeholder (RQ uses None)
'args': list, # Positional arguments
'kwargs': dict # Keyword arguments
}
# When: Create job data
job_data = [
'opik_backend.rq_worker.process_optimizer_job',
None,
['message'],
{}
]
# Then: Format matches expectations
assert isinstance(job_data[0], str)
assert job_data[1] is None
assert isinstance(job_data[2], list)
assert isinstance(job_data[3], dict)
def test_data_is_json_not_compressed(self):
"""Ensure contract uses plain JSON, not zlib compression."""
arr = ["f", None, ["x"], {}]
json_str = json.dumps(arr)
# No compression; just JSON presence check
assert json.loads(json_str) == arr
def test_timestamp_format_compatibility(self):
"""Verify timestamp format is ISO-8601."""
# Given: Java Instant format
java_timestamp = "2025-10-14T10:57:05.638222Z"
# When: Parse with Python
# This should not raise an exception
from datetime import datetime
parsed = datetime.fromisoformat(java_timestamp.replace('Z', '+00:00'))
# Then: Successfully parsed
assert parsed.year == 2025
assert parsed.month == 10
assert parsed.day == 14
def test_rq_api_with_fakeredis_works(self, redis_conn):
"""Use RQ Queue + SimpleWorker (JSONSerializer) over fakeredis to validate processing API."""
from rq import Queue
from rq.serializers import JSONSerializer
from rq.worker import SimpleWorker
from rq.job import Job
# Create queue using mocked Redis
queue_name = 'opik:optimizer-cloud'
serializer = JSONSerializer()
q = Queue(queue_name, connection=redis_conn, serializer=serializer)
# Create a proper job message matching the OptimizationJobContext format
job_message = {
'optimization_id': str(uuid.uuid4()),
'workspace_name': 'test-workspace',
'opik_api_key': 'test-key',
'config': {
'dataset_name': 'test-dataset',
'prompt': {
'messages': [
{'role': 'system', 'content': 'You are a helpful assistant'},
{'role': 'user', 'content': 'Answer: {question}'}
]
},
'llm_model': {
'model': 'gpt-4',
'parameters': {'temperature': 0.7}
},
'evaluation': {
'metrics': [
{
'type': 'equals',
'parameters': {}
}
]
},
'optimizer': {
'type': 'gepa',
'parameters': {}
}
}
}
# Enqueue our worker function by reference with proper job message
from opik_backend.rq_worker import process_optimizer_job
job = q.enqueue(process_optimizer_job, job_message)
# Process with SimpleWorker (no forking) against the same mocked Redis
worker = SimpleWorker([q], connection=redis_conn, serializer=serializer)
worker.work(burst=True)
# Fetch job and verify result
fetched = Job.fetch(job.id, connection=redis_conn, serializer=serializer)
# The job will fail because we don't have a real dataset or LLM keys,
# but it should at least parse the message correctly and not fail with KeyError
# Check that it got past the message parsing stage
if not fetched.is_finished:
# If it failed, check that it's not due to missing job message fields
exc_info = fetched.latest_result()
error_msg = str(exc_info.exc_string) if hasattr(exc_info, 'exc_string') else str(fetched.exc_info)
# Should not fail with KeyError for optimization_id, workspace_name, or config
assert 'KeyError' not in error_msg or 'optimization_id' not in error_msg, \
f"Job failed with message parsing error: {error_msg}"
# It's OK to fail for other reasons (missing dataset, API keys, etc.)
else:
# If it succeeded (unlikely without real resources), that's also OK
val = fetched.return_value
assert val is not None