Skip to content

Commit faf4cde

Browse files
committed
add tests
1 parent 7e0a897 commit faf4cde

1 file changed

Lines changed: 216 additions & 0 deletions

File tree

tests/lib/test_payload_codec.py

Lines changed: 216 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,216 @@
1+
from __future__ import annotations
2+
3+
from typing import Any
4+
from unittest.mock import AsyncMock, patch
5+
6+
import pytest
7+
from temporalio.client import Client, Plugin as ClientPlugin
8+
from temporalio.converter import PayloadCodec
9+
from temporalio.contrib.pydantic import pydantic_data_converter
10+
11+
12+
class _NoopCodec(PayloadCodec):
13+
async def encode(self, payloads):
14+
return list(payloads)
15+
16+
async def decode(self, payloads):
17+
return list(payloads)
18+
19+
20+
class _FakeOpenAIPlugin(ClientPlugin):
21+
def configure_client(self, config):
22+
return config
23+
24+
async def connect_service_client(self, config, next):
25+
return await next(config)
26+
27+
28+
def _mock_connect():
29+
return patch.object(Client, "connect", new=AsyncMock(return_value=object()))
30+
31+
32+
def _patch_openai_plugin():
33+
return patch("temporalio.contrib.openai_agents.OpenAIAgentsPlugin", _FakeOpenAIPlugin)
34+
35+
36+
class TestTemporalClient:
37+
def test_init_stores_payload_codec(self):
38+
from agentex.lib.core.clients.temporal.temporal_client import TemporalClient
39+
40+
codec = _NoopCodec()
41+
client = TemporalClient(payload_codec=codec)
42+
assert client._payload_codec is codec
43+
44+
def test_init_default_payload_codec_is_none(self):
45+
from agentex.lib.core.clients.temporal.temporal_client import TemporalClient
46+
47+
assert TemporalClient()._payload_codec is None
48+
49+
async def test_create_with_disabled_address_stores_codec(self):
50+
from agentex.lib.core.clients.temporal.temporal_client import TemporalClient
51+
52+
codec = _NoopCodec()
53+
client = await TemporalClient.create(temporal_address="false", payload_codec=codec)
54+
assert client._client is None
55+
assert client._payload_codec is codec
56+
57+
async def test_create_propagates_codec_to_get_temporal_client(self):
58+
import agentex.lib.core.clients.temporal.temporal_client as module
59+
60+
codec = _NoopCodec()
61+
with patch.object(module, "get_temporal_client", new=AsyncMock(return_value=object())) as mock_get:
62+
await module.TemporalClient.create(temporal_address="localhost:7233", plugins=[], payload_codec=codec)
63+
64+
mock_get.assert_awaited_once()
65+
assert mock_get.await_args.kwargs["payload_codec"] is codec
66+
67+
68+
class TestGetTemporalClientUtils:
69+
async def test_no_codec_uses_pydantic_data_converter_unchanged(self):
70+
from agentex.lib.core.clients.temporal.utils import get_temporal_client
71+
72+
with _mock_connect() as mock_connect:
73+
await get_temporal_client(temporal_address="localhost:7233")
74+
75+
kwargs = mock_connect.await_args.kwargs
76+
assert kwargs["data_converter"] is pydantic_data_converter
77+
assert kwargs["data_converter"].payload_codec is None
78+
79+
async def test_codec_is_attached_to_pydantic_data_converter(self):
80+
from agentex.lib.core.clients.temporal.utils import get_temporal_client
81+
82+
codec = _NoopCodec()
83+
with _mock_connect() as mock_connect:
84+
await get_temporal_client(temporal_address="localhost:7233", payload_codec=codec)
85+
86+
data_converter = mock_connect.await_args.kwargs["data_converter"]
87+
assert data_converter.payload_codec is codec
88+
assert data_converter.payload_converter_class is pydantic_data_converter.payload_converter_class
89+
90+
async def test_codec_with_openai_plugin_raises(self):
91+
from agentex.lib.core.clients.temporal.utils import get_temporal_client
92+
93+
codec = _NoopCodec()
94+
with _patch_openai_plugin(), _mock_connect() as mock_connect:
95+
with pytest.raises(ValueError, match="payload_codec is not supported alongside OpenAIAgentsPlugin"):
96+
await get_temporal_client(
97+
temporal_address="localhost:7233",
98+
plugins=[_FakeOpenAIPlugin()],
99+
payload_codec=codec,
100+
)
101+
mock_connect.assert_not_awaited()
102+
103+
async def test_openai_plugin_without_codec_omits_data_converter(self):
104+
from agentex.lib.core.clients.temporal.utils import get_temporal_client
105+
106+
with _patch_openai_plugin(), _mock_connect() as mock_connect:
107+
await get_temporal_client(temporal_address="localhost:7233", plugins=[_FakeOpenAIPlugin()])
108+
109+
assert "data_converter" not in mock_connect.await_args.kwargs
110+
111+
112+
class TestGetTemporalClientWorker:
113+
async def test_no_codec_uses_custom_data_converter_unchanged(self):
114+
from agentex.lib.core.temporal.workers.worker import get_temporal_client, custom_data_converter
115+
116+
with _mock_connect() as mock_connect:
117+
await get_temporal_client(temporal_address="localhost:7233")
118+
119+
kwargs = mock_connect.await_args.kwargs
120+
assert kwargs["data_converter"] is custom_data_converter
121+
assert kwargs["data_converter"].payload_codec is None
122+
123+
async def test_codec_is_attached_to_custom_data_converter(self):
124+
from agentex.lib.core.temporal.workers.worker import get_temporal_client, custom_data_converter
125+
126+
codec = _NoopCodec()
127+
with _mock_connect() as mock_connect:
128+
await get_temporal_client(temporal_address="localhost:7233", payload_codec=codec)
129+
130+
data_converter = mock_connect.await_args.kwargs["data_converter"]
131+
assert data_converter.payload_codec is codec
132+
assert data_converter.payload_converter_class is custom_data_converter.payload_converter_class
133+
134+
async def test_codec_with_openai_plugin_raises(self):
135+
from agentex.lib.core.temporal.workers.worker import get_temporal_client
136+
137+
codec = _NoopCodec()
138+
with _patch_openai_plugin(), _mock_connect() as mock_connect:
139+
with pytest.raises(ValueError, match="payload_codec is not supported alongside OpenAIAgentsPlugin"):
140+
await get_temporal_client(
141+
temporal_address="localhost:7233",
142+
plugins=[_FakeOpenAIPlugin()],
143+
payload_codec=codec,
144+
)
145+
mock_connect.assert_not_awaited()
146+
147+
async def test_openai_plugin_without_codec_omits_data_converter(self):
148+
from agentex.lib.core.temporal.workers.worker import get_temporal_client
149+
150+
with _patch_openai_plugin(), _mock_connect() as mock_connect:
151+
await get_temporal_client(temporal_address="localhost:7233", plugins=[_FakeOpenAIPlugin()])
152+
153+
assert "data_converter" not in mock_connect.await_args.kwargs
154+
155+
156+
class TestAgentexWorkerCodec:
157+
def test_worker_stores_payload_codec(self):
158+
from agentex.lib.core.temporal.workers.worker import AgentexWorker
159+
160+
codec = _NoopCodec()
161+
worker = AgentexWorker(task_queue="test-queue", health_check_port=80, payload_codec=codec)
162+
assert worker.payload_codec is codec
163+
164+
def test_worker_default_payload_codec_is_none(self):
165+
from agentex.lib.core.temporal.workers.worker import AgentexWorker
166+
167+
worker = AgentexWorker(task_queue="test-queue", health_check_port=80)
168+
assert worker.payload_codec is None
169+
170+
171+
class TestTemporalACPCodec:
172+
def test_create_stores_payload_codec(self):
173+
from agentex.lib.sdk.fastacp.impl.temporal_acp import TemporalACP
174+
175+
codec = _NoopCodec()
176+
acp = TemporalACP.create(temporal_address="localhost:7233", payload_codec=codec)
177+
assert acp._payload_codec is codec
178+
179+
def test_create_default_payload_codec_is_none(self):
180+
from agentex.lib.sdk.fastacp.impl.temporal_acp import TemporalACP
181+
182+
acp = TemporalACP.create(temporal_address="localhost:7233")
183+
assert acp._payload_codec is None
184+
185+
186+
class TestFastACPConfigCodec:
187+
def test_config_default_codec_is_none(self):
188+
from agentex.lib.types.fastacp import TemporalACPConfig
189+
190+
assert TemporalACPConfig().payload_codec is None
191+
192+
def test_config_accepts_codec(self):
193+
from agentex.lib.types.fastacp import TemporalACPConfig
194+
195+
codec = _NoopCodec()
196+
assert TemporalACPConfig(payload_codec=codec).payload_codec is codec
197+
198+
def test_fastacp_forwards_codec_from_config(self):
199+
from agentex.lib.types.fastacp import TemporalACPConfig
200+
from agentex.lib.sdk.fastacp.fastacp import FastACP
201+
202+
codec = _NoopCodec()
203+
config = TemporalACPConfig(payload_codec=codec)
204+
captured: dict[str, Any] = {}
205+
206+
def fake_create(**kwargs):
207+
captured.update(kwargs)
208+
return object()
209+
210+
with patch(
211+
"agentex.lib.sdk.fastacp.impl.temporal_acp.TemporalACP.create",
212+
side_effect=fake_create,
213+
):
214+
FastACP.create("async", config=config)
215+
216+
assert captured.get("payload_codec") is codec

0 commit comments

Comments
 (0)