jarviscore-framework 0.3.0__py3-none-any.whl → 0.3.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- examples/cloud_deployment_example.py +3 -3
- examples/{listeneragent_cognitive_discovery_example.py → customagent_cognitive_discovery_example.py} +55 -14
- examples/customagent_distributed_example.py +140 -1
- examples/fastapi_integration_example.py +74 -11
- jarviscore/__init__.py +8 -11
- jarviscore/cli/smoketest.py +1 -1
- jarviscore/core/mesh.py +158 -0
- jarviscore/data/examples/cloud_deployment_example.py +3 -3
- jarviscore/data/examples/custom_profile_decorator.py +134 -0
- jarviscore/data/examples/custom_profile_wrap.py +168 -0
- jarviscore/data/examples/{listeneragent_cognitive_discovery_example.py → customagent_cognitive_discovery_example.py} +55 -14
- jarviscore/data/examples/customagent_distributed_example.py +140 -1
- jarviscore/data/examples/fastapi_integration_example.py +74 -11
- jarviscore/docs/API_REFERENCE.md +576 -47
- jarviscore/docs/CHANGELOG.md +131 -0
- jarviscore/docs/CONFIGURATION.md +1 -1
- jarviscore/docs/CUSTOMAGENT_GUIDE.md +591 -153
- jarviscore/docs/GETTING_STARTED.md +186 -329
- jarviscore/docs/TROUBLESHOOTING.md +1 -1
- jarviscore/docs/USER_GUIDE.md +292 -12
- jarviscore/integrations/fastapi.py +4 -4
- jarviscore/p2p/coordinator.py +36 -7
- jarviscore/p2p/messages.py +13 -0
- jarviscore/p2p/peer_client.py +380 -21
- jarviscore/p2p/peer_tool.py +17 -11
- jarviscore/profiles/__init__.py +2 -4
- jarviscore/profiles/customagent.py +302 -74
- jarviscore/testing/__init__.py +35 -0
- jarviscore/testing/mocks.py +578 -0
- {jarviscore_framework-0.3.0.dist-info → jarviscore_framework-0.3.2.dist-info}/METADATA +61 -46
- {jarviscore_framework-0.3.0.dist-info → jarviscore_framework-0.3.2.dist-info}/RECORD +42 -34
- tests/test_13_dx_improvements.py +37 -37
- tests/test_15_llm_cognitive_discovery.py +18 -18
- tests/test_16_unified_dx_flow.py +3 -3
- tests/test_17_session_context.py +489 -0
- tests/test_18_mesh_diagnostics.py +465 -0
- tests/test_19_async_requests.py +516 -0
- tests/test_20_load_balancing.py +546 -0
- tests/test_21_mock_testing.py +776 -0
- jarviscore/profiles/listeneragent.py +0 -292
- {jarviscore_framework-0.3.0.dist-info → jarviscore_framework-0.3.2.dist-info}/WHEEL +0 -0
- {jarviscore_framework-0.3.0.dist-info → jarviscore_framework-0.3.2.dist-info}/licenses/LICENSE +0 -0
- {jarviscore_framework-0.3.0.dist-info → jarviscore_framework-0.3.2.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,489 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Test 17: Session Context Propagation (Feature F6)
|
|
3
|
+
|
|
4
|
+
Tests the context propagation feature:
|
|
5
|
+
- Context parameter in notify(), request(), respond(), broadcast()
|
|
6
|
+
- Auto-propagation of context in respond()
|
|
7
|
+
- Context accessible via IncomingMessage.context
|
|
8
|
+
|
|
9
|
+
Run with: pytest tests/test_17_session_context.py -v -s
|
|
10
|
+
"""
|
|
11
|
+
import asyncio
|
|
12
|
+
import sys
|
|
13
|
+
import pytest
|
|
14
|
+
import logging
|
|
15
|
+
from unittest.mock import AsyncMock, MagicMock, patch
|
|
16
|
+
|
|
17
|
+
sys.path.insert(0, '.')
|
|
18
|
+
|
|
19
|
+
# Setup logging
|
|
20
|
+
logging.basicConfig(level=logging.INFO)
|
|
21
|
+
logger = logging.getLogger(__name__)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
# =============================================================================
|
|
25
|
+
# TEST: CONTEXT IN OUTGOING MESSAGES
|
|
26
|
+
# =============================================================================
|
|
27
|
+
|
|
28
|
+
class TestContextInNotify:
|
|
29
|
+
"""Test context parameter in notify()."""
|
|
30
|
+
|
|
31
|
+
@pytest.mark.asyncio
|
|
32
|
+
async def test_notify_with_context(self):
|
|
33
|
+
"""Test notify() accepts and sends context."""
|
|
34
|
+
from jarviscore.testing import MockPeerClient
|
|
35
|
+
|
|
36
|
+
client = MockPeerClient(
|
|
37
|
+
agent_id="sender-1",
|
|
38
|
+
agent_role="sender",
|
|
39
|
+
mock_peers=[{"role": "receiver", "capabilities": ["receiving"]}]
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
context = {"mission_id": "mission-123", "priority": "high"}
|
|
43
|
+
result = await client.notify("receiver", {"event": "test"}, context=context)
|
|
44
|
+
|
|
45
|
+
assert result is True
|
|
46
|
+
notifications = client.get_sent_notifications()
|
|
47
|
+
assert len(notifications) == 1
|
|
48
|
+
assert notifications[0]["context"] == context
|
|
49
|
+
assert notifications[0]["message"] == {"event": "test"}
|
|
50
|
+
|
|
51
|
+
@pytest.mark.asyncio
|
|
52
|
+
async def test_notify_without_context(self):
|
|
53
|
+
"""Test notify() works without context (None by default)."""
|
|
54
|
+
from jarviscore.testing import MockPeerClient
|
|
55
|
+
|
|
56
|
+
client = MockPeerClient(
|
|
57
|
+
agent_id="sender-1",
|
|
58
|
+
agent_role="sender",
|
|
59
|
+
mock_peers=[{"role": "receiver", "capabilities": ["receiving"]}]
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
result = await client.notify("receiver", {"event": "test"})
|
|
63
|
+
|
|
64
|
+
assert result is True
|
|
65
|
+
notifications = client.get_sent_notifications()
|
|
66
|
+
assert len(notifications) == 1
|
|
67
|
+
assert notifications[0]["context"] is None
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
class TestContextInRequest:
|
|
71
|
+
"""Test context parameter in request()."""
|
|
72
|
+
|
|
73
|
+
@pytest.mark.asyncio
|
|
74
|
+
async def test_request_with_context(self):
|
|
75
|
+
"""Test request() accepts and sends context."""
|
|
76
|
+
from jarviscore.testing import MockPeerClient
|
|
77
|
+
|
|
78
|
+
client = MockPeerClient(
|
|
79
|
+
agent_id="sender-1",
|
|
80
|
+
agent_role="sender",
|
|
81
|
+
mock_peers=[{"role": "analyst", "capabilities": ["analysis"]}]
|
|
82
|
+
)
|
|
83
|
+
client.set_mock_response("analyst", {"result": "analyzed"})
|
|
84
|
+
|
|
85
|
+
context = {"mission_id": "mission-456", "trace_id": "trace-abc"}
|
|
86
|
+
response = await client.request("analyst", {"query": "test"}, context=context)
|
|
87
|
+
|
|
88
|
+
assert response == {"result": "analyzed"}
|
|
89
|
+
requests = client.get_sent_requests()
|
|
90
|
+
assert len(requests) == 1
|
|
91
|
+
assert requests[0]["context"] == context
|
|
92
|
+
|
|
93
|
+
@pytest.mark.asyncio
|
|
94
|
+
async def test_request_without_context(self):
|
|
95
|
+
"""Test request() works without context."""
|
|
96
|
+
from jarviscore.testing import MockPeerClient
|
|
97
|
+
|
|
98
|
+
client = MockPeerClient(
|
|
99
|
+
agent_id="sender-1",
|
|
100
|
+
agent_role="sender",
|
|
101
|
+
mock_peers=[{"role": "analyst", "capabilities": ["analysis"]}]
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
response = await client.request("analyst", {"query": "test"})
|
|
105
|
+
|
|
106
|
+
assert response is not None
|
|
107
|
+
requests = client.get_sent_requests()
|
|
108
|
+
assert len(requests) == 1
|
|
109
|
+
assert requests[0]["context"] is None
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
class TestContextInBroadcast:
|
|
113
|
+
"""Test context parameter in broadcast()."""
|
|
114
|
+
|
|
115
|
+
@pytest.mark.asyncio
|
|
116
|
+
async def test_broadcast_with_context(self):
|
|
117
|
+
"""Test broadcast() accepts and sends context to all peers."""
|
|
118
|
+
from jarviscore.testing import MockPeerClient
|
|
119
|
+
|
|
120
|
+
client = MockPeerClient(
|
|
121
|
+
agent_id="broadcaster-1",
|
|
122
|
+
agent_role="broadcaster",
|
|
123
|
+
mock_peers=[
|
|
124
|
+
{"role": "peer1", "capabilities": ["cap1"]},
|
|
125
|
+
{"role": "peer2", "capabilities": ["cap2"]}
|
|
126
|
+
]
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
context = {"broadcast_id": "bc-789", "source": "alert_system"}
|
|
130
|
+
count = await client.broadcast({"alert": "important"}, context=context)
|
|
131
|
+
|
|
132
|
+
assert count == 2
|
|
133
|
+
broadcasts = client.get_sent_broadcasts()
|
|
134
|
+
assert len(broadcasts) == 1
|
|
135
|
+
assert broadcasts[0]["context"] == context
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
# =============================================================================
|
|
139
|
+
# TEST: CONTEXT IN INCOMING MESSAGES
|
|
140
|
+
# =============================================================================
|
|
141
|
+
|
|
142
|
+
class TestContextInIncomingMessage:
|
|
143
|
+
"""Test context accessible in IncomingMessage."""
|
|
144
|
+
|
|
145
|
+
def test_incoming_message_has_context_field(self):
|
|
146
|
+
"""Test IncomingMessage dataclass has context field."""
|
|
147
|
+
from jarviscore.p2p.messages import IncomingMessage, MessageType
|
|
148
|
+
|
|
149
|
+
msg = IncomingMessage(
|
|
150
|
+
sender="sender-1",
|
|
151
|
+
sender_node="localhost:7946",
|
|
152
|
+
type=MessageType.NOTIFY,
|
|
153
|
+
data={"event": "test"},
|
|
154
|
+
context={"mission_id": "m-123"}
|
|
155
|
+
)
|
|
156
|
+
|
|
157
|
+
assert msg.context == {"mission_id": "m-123"}
|
|
158
|
+
|
|
159
|
+
def test_incoming_message_context_default_none(self):
|
|
160
|
+
"""Test IncomingMessage context defaults to None."""
|
|
161
|
+
from jarviscore.p2p.messages import IncomingMessage, MessageType
|
|
162
|
+
|
|
163
|
+
msg = IncomingMessage(
|
|
164
|
+
sender="sender-1",
|
|
165
|
+
sender_node="localhost:7946",
|
|
166
|
+
type=MessageType.NOTIFY,
|
|
167
|
+
data={"event": "test"}
|
|
168
|
+
)
|
|
169
|
+
|
|
170
|
+
assert msg.context is None
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
class TestContextInOutgoingMessage:
|
|
174
|
+
"""Test context in OutgoingMessage dataclass."""
|
|
175
|
+
|
|
176
|
+
def test_outgoing_message_has_context_field(self):
|
|
177
|
+
"""Test OutgoingMessage dataclass has context field."""
|
|
178
|
+
from jarviscore.p2p.messages import OutgoingMessage, MessageType
|
|
179
|
+
|
|
180
|
+
msg = OutgoingMessage(
|
|
181
|
+
target="receiver",
|
|
182
|
+
type=MessageType.REQUEST,
|
|
183
|
+
data={"query": "test"},
|
|
184
|
+
context={"priority": "high"}
|
|
185
|
+
)
|
|
186
|
+
|
|
187
|
+
assert msg.context == {"priority": "high"}
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
# =============================================================================
|
|
191
|
+
# TEST: CONTEXT AUTO-PROPAGATION IN RESPOND
|
|
192
|
+
# =============================================================================
|
|
193
|
+
|
|
194
|
+
class TestContextAutoPropagation:
|
|
195
|
+
"""Test context auto-propagation in respond()."""
|
|
196
|
+
|
|
197
|
+
@pytest.mark.asyncio
|
|
198
|
+
async def test_respond_auto_propagates_context(self):
|
|
199
|
+
"""Test respond() auto-propagates request context if not overridden."""
|
|
200
|
+
from jarviscore.p2p.peer_client import PeerClient
|
|
201
|
+
from jarviscore.p2p.messages import IncomingMessage, MessageType
|
|
202
|
+
|
|
203
|
+
# Create a mock coordinator
|
|
204
|
+
mock_coordinator = MagicMock()
|
|
205
|
+
mock_coordinator._send_p2p_message = AsyncMock(return_value=True)
|
|
206
|
+
mock_coordinator._remote_agent_registry = {}
|
|
207
|
+
|
|
208
|
+
# Create mock agent registry with a sender agent
|
|
209
|
+
class MockAgent:
|
|
210
|
+
def __init__(self):
|
|
211
|
+
self.agent_id = "sender-1"
|
|
212
|
+
self.role = "sender"
|
|
213
|
+
self.capabilities = ["sending"]
|
|
214
|
+
self.peers = MagicMock()
|
|
215
|
+
self.peers._deliver_message = AsyncMock()
|
|
216
|
+
|
|
217
|
+
mock_sender = MockAgent()
|
|
218
|
+
agent_registry = {"sender": [mock_sender]}
|
|
219
|
+
|
|
220
|
+
# Create the responder PeerClient
|
|
221
|
+
client = PeerClient(
|
|
222
|
+
coordinator=mock_coordinator,
|
|
223
|
+
agent_id="responder-1",
|
|
224
|
+
agent_role="responder",
|
|
225
|
+
agent_registry=agent_registry,
|
|
226
|
+
node_id="localhost:7946"
|
|
227
|
+
)
|
|
228
|
+
|
|
229
|
+
# Create incoming request with context
|
|
230
|
+
incoming = IncomingMessage(
|
|
231
|
+
sender="sender-1",
|
|
232
|
+
sender_node="localhost:7946",
|
|
233
|
+
type=MessageType.REQUEST,
|
|
234
|
+
data={"query": "test"},
|
|
235
|
+
correlation_id="corr-123",
|
|
236
|
+
context={"mission_id": "m-999", "trace_id": "t-abc"}
|
|
237
|
+
)
|
|
238
|
+
|
|
239
|
+
# Respond without explicitly providing context
|
|
240
|
+
result = await client.respond(incoming, {"answer": "42"})
|
|
241
|
+
|
|
242
|
+
assert result is True
|
|
243
|
+
|
|
244
|
+
# Verify the response was delivered with propagated context
|
|
245
|
+
mock_sender.peers._deliver_message.assert_called_once()
|
|
246
|
+
delivered_msg = mock_sender.peers._deliver_message.call_args[0][0]
|
|
247
|
+
assert delivered_msg.context == {"mission_id": "m-999", "trace_id": "t-abc"}
|
|
248
|
+
|
|
249
|
+
@pytest.mark.asyncio
|
|
250
|
+
async def test_respond_override_context(self):
|
|
251
|
+
"""Test respond() can override context."""
|
|
252
|
+
from jarviscore.p2p.peer_client import PeerClient
|
|
253
|
+
from jarviscore.p2p.messages import IncomingMessage, MessageType
|
|
254
|
+
|
|
255
|
+
mock_coordinator = MagicMock()
|
|
256
|
+
mock_coordinator._send_p2p_message = AsyncMock(return_value=True)
|
|
257
|
+
mock_coordinator._remote_agent_registry = {}
|
|
258
|
+
|
|
259
|
+
class MockAgent:
|
|
260
|
+
def __init__(self):
|
|
261
|
+
self.agent_id = "sender-1"
|
|
262
|
+
self.role = "sender"
|
|
263
|
+
self.capabilities = ["sending"]
|
|
264
|
+
self.peers = MagicMock()
|
|
265
|
+
self.peers._deliver_message = AsyncMock()
|
|
266
|
+
|
|
267
|
+
mock_sender = MockAgent()
|
|
268
|
+
agent_registry = {"sender": [mock_sender]}
|
|
269
|
+
|
|
270
|
+
client = PeerClient(
|
|
271
|
+
coordinator=mock_coordinator,
|
|
272
|
+
agent_id="responder-1",
|
|
273
|
+
agent_role="responder",
|
|
274
|
+
agent_registry=agent_registry,
|
|
275
|
+
node_id="localhost:7946"
|
|
276
|
+
)
|
|
277
|
+
|
|
278
|
+
# Incoming with original context
|
|
279
|
+
incoming = IncomingMessage(
|
|
280
|
+
sender="sender-1",
|
|
281
|
+
sender_node="localhost:7946",
|
|
282
|
+
type=MessageType.REQUEST,
|
|
283
|
+
data={"query": "test"},
|
|
284
|
+
correlation_id="corr-456",
|
|
285
|
+
context={"original": "context"}
|
|
286
|
+
)
|
|
287
|
+
|
|
288
|
+
# Respond with overridden context
|
|
289
|
+
result = await client.respond(
|
|
290
|
+
incoming,
|
|
291
|
+
{"answer": "42"},
|
|
292
|
+
context={"overridden": "context", "status": "complete"}
|
|
293
|
+
)
|
|
294
|
+
|
|
295
|
+
assert result is True
|
|
296
|
+
delivered_msg = mock_sender.peers._deliver_message.call_args[0][0]
|
|
297
|
+
assert delivered_msg.context == {"overridden": "context", "status": "complete"}
|
|
298
|
+
|
|
299
|
+
|
|
300
|
+
# =============================================================================
|
|
301
|
+
# TEST: CONTEXT THROUGH LOCAL DELIVERY
|
|
302
|
+
# =============================================================================
|
|
303
|
+
|
|
304
|
+
class TestContextLocalDelivery:
|
|
305
|
+
"""Test context flows through local message delivery."""
|
|
306
|
+
|
|
307
|
+
@pytest.mark.asyncio
|
|
308
|
+
async def test_context_in_local_notify(self):
|
|
309
|
+
"""Test context preserved in local notify delivery."""
|
|
310
|
+
from jarviscore.p2p.peer_client import PeerClient
|
|
311
|
+
from jarviscore.p2p.messages import MessageType
|
|
312
|
+
|
|
313
|
+
mock_coordinator = MagicMock()
|
|
314
|
+
mock_coordinator._remote_agent_registry = {}
|
|
315
|
+
|
|
316
|
+
# Create receiver agent with PeerClient
|
|
317
|
+
class MockReceiverAgent:
|
|
318
|
+
def __init__(self):
|
|
319
|
+
self.agent_id = "receiver-1"
|
|
320
|
+
self.role = "receiver"
|
|
321
|
+
self.capabilities = ["receiving"]
|
|
322
|
+
self.peers = None
|
|
323
|
+
|
|
324
|
+
receiver = MockReceiverAgent()
|
|
325
|
+
receiver_client = PeerClient(
|
|
326
|
+
coordinator=mock_coordinator,
|
|
327
|
+
agent_id="receiver-1",
|
|
328
|
+
agent_role="receiver",
|
|
329
|
+
agent_registry={},
|
|
330
|
+
node_id="localhost:7946"
|
|
331
|
+
)
|
|
332
|
+
receiver.peers = receiver_client
|
|
333
|
+
|
|
334
|
+
# Create sender with receiver in registry
|
|
335
|
+
agent_registry = {"receiver": [receiver]}
|
|
336
|
+
sender_client = PeerClient(
|
|
337
|
+
coordinator=mock_coordinator,
|
|
338
|
+
agent_id="sender-1",
|
|
339
|
+
agent_role="sender",
|
|
340
|
+
agent_registry=agent_registry,
|
|
341
|
+
node_id="localhost:7946"
|
|
342
|
+
)
|
|
343
|
+
|
|
344
|
+
# Send notify with context
|
|
345
|
+
context = {"session_id": "sess-123", "user_id": "user-456"}
|
|
346
|
+
result = await sender_client.notify("receiver", {"event": "test"}, context=context)
|
|
347
|
+
|
|
348
|
+
assert result is True
|
|
349
|
+
|
|
350
|
+
# Receive and check context
|
|
351
|
+
msg = await receiver_client.receive(timeout=1)
|
|
352
|
+
assert msg is not None
|
|
353
|
+
assert msg.type == MessageType.NOTIFY
|
|
354
|
+
assert msg.context == context
|
|
355
|
+
|
|
356
|
+
|
|
357
|
+
# =============================================================================
|
|
358
|
+
# TEST: CONTEXT IN MOCK PEER CLIENT
|
|
359
|
+
# =============================================================================
|
|
360
|
+
|
|
361
|
+
class TestMockPeerClientContext:
|
|
362
|
+
"""Test MockPeerClient supports context in all operations."""
|
|
363
|
+
|
|
364
|
+
@pytest.mark.asyncio
|
|
365
|
+
async def test_mock_inject_message_with_context(self):
|
|
366
|
+
"""Test MockPeerClient.inject_message() supports context."""
|
|
367
|
+
from jarviscore.testing import MockPeerClient
|
|
368
|
+
from jarviscore.p2p.messages import MessageType
|
|
369
|
+
|
|
370
|
+
client = MockPeerClient()
|
|
371
|
+
|
|
372
|
+
context = {"injected": "context", "test_id": "inject-1"}
|
|
373
|
+
client.inject_message(
|
|
374
|
+
sender="injector",
|
|
375
|
+
message_type=MessageType.NOTIFY,
|
|
376
|
+
data={"injected": True},
|
|
377
|
+
context=context
|
|
378
|
+
)
|
|
379
|
+
|
|
380
|
+
msg = await client.receive(timeout=1)
|
|
381
|
+
assert msg is not None
|
|
382
|
+
assert msg.context == context
|
|
383
|
+
assert msg.data == {"injected": True}
|
|
384
|
+
|
|
385
|
+
@pytest.mark.asyncio
|
|
386
|
+
async def test_mock_tracks_context_in_sent_messages(self):
|
|
387
|
+
"""Test MockPeerClient tracks context in all sent messages."""
|
|
388
|
+
from jarviscore.testing import MockPeerClient
|
|
389
|
+
|
|
390
|
+
client = MockPeerClient(
|
|
391
|
+
mock_peers=[{"role": "target", "capabilities": []}]
|
|
392
|
+
)
|
|
393
|
+
|
|
394
|
+
# Send notification with context
|
|
395
|
+
await client.notify("target", {"n": 1}, context={"ctx": "notify"})
|
|
396
|
+
assert client.get_sent_notifications()[0]["context"] == {"ctx": "notify"}
|
|
397
|
+
|
|
398
|
+
# Send request with context
|
|
399
|
+
await client.request("target", {"r": 2}, context={"ctx": "request"})
|
|
400
|
+
assert client.get_sent_requests()[0]["context"] == {"ctx": "request"}
|
|
401
|
+
|
|
402
|
+
# Send broadcast with context
|
|
403
|
+
await client.broadcast({"b": 3}, context={"ctx": "broadcast"})
|
|
404
|
+
assert client.get_sent_broadcasts()[0]["context"] == {"ctx": "broadcast"}
|
|
405
|
+
|
|
406
|
+
|
|
407
|
+
# =============================================================================
|
|
408
|
+
# TEST: CONTEXT IN CUSTOM AGENT HANDLERS
|
|
409
|
+
# =============================================================================
|
|
410
|
+
|
|
411
|
+
class TestContextInCustomAgentHandlers:
|
|
412
|
+
"""Test context accessible in CustomAgent message handlers."""
|
|
413
|
+
|
|
414
|
+
@pytest.mark.asyncio
|
|
415
|
+
async def test_context_in_on_peer_request(self):
|
|
416
|
+
"""Test context is accessible in on_peer_request handler."""
|
|
417
|
+
from jarviscore.profiles import CustomAgent
|
|
418
|
+
from jarviscore.p2p.messages import IncomingMessage, MessageType
|
|
419
|
+
|
|
420
|
+
received_context = None
|
|
421
|
+
|
|
422
|
+
class TestAgent(CustomAgent):
|
|
423
|
+
role = "context_handler"
|
|
424
|
+
capabilities = ["handling"]
|
|
425
|
+
|
|
426
|
+
async def on_peer_request(self, msg):
|
|
427
|
+
nonlocal received_context
|
|
428
|
+
received_context = msg.context
|
|
429
|
+
return {"received_context": msg.context}
|
|
430
|
+
|
|
431
|
+
agent = TestAgent()
|
|
432
|
+
agent._logger = MagicMock()
|
|
433
|
+
agent.peers = MagicMock()
|
|
434
|
+
agent.peers.respond = AsyncMock()
|
|
435
|
+
|
|
436
|
+
msg = IncomingMessage(
|
|
437
|
+
sender="sender",
|
|
438
|
+
sender_node="localhost:7946",
|
|
439
|
+
type=MessageType.REQUEST,
|
|
440
|
+
data={"query": "test"},
|
|
441
|
+
correlation_id="corr-123",
|
|
442
|
+
context={"mission_id": "m-handler", "stage": "processing"}
|
|
443
|
+
)
|
|
444
|
+
|
|
445
|
+
await agent._dispatch_message(msg)
|
|
446
|
+
|
|
447
|
+
assert received_context == {"mission_id": "m-handler", "stage": "processing"}
|
|
448
|
+
|
|
449
|
+
@pytest.mark.asyncio
|
|
450
|
+
async def test_context_in_on_peer_notify(self):
|
|
451
|
+
"""Test context is accessible in on_peer_notify handler."""
|
|
452
|
+
from jarviscore.profiles import CustomAgent
|
|
453
|
+
from jarviscore.p2p.messages import IncomingMessage, MessageType
|
|
454
|
+
|
|
455
|
+
received_context = None
|
|
456
|
+
|
|
457
|
+
class TestAgent(CustomAgent):
|
|
458
|
+
role = "context_handler"
|
|
459
|
+
capabilities = ["handling"]
|
|
460
|
+
|
|
461
|
+
async def on_peer_notify(self, msg):
|
|
462
|
+
nonlocal received_context
|
|
463
|
+
received_context = msg.context
|
|
464
|
+
|
|
465
|
+
async def on_peer_request(self, msg):
|
|
466
|
+
return {}
|
|
467
|
+
|
|
468
|
+
agent = TestAgent()
|
|
469
|
+
agent._logger = MagicMock()
|
|
470
|
+
|
|
471
|
+
msg = IncomingMessage(
|
|
472
|
+
sender="sender",
|
|
473
|
+
sender_node="localhost:7946",
|
|
474
|
+
type=MessageType.NOTIFY,
|
|
475
|
+
data={"event": "test"},
|
|
476
|
+
context={"notification_source": "event_system"}
|
|
477
|
+
)
|
|
478
|
+
|
|
479
|
+
await agent._dispatch_message(msg)
|
|
480
|
+
|
|
481
|
+
assert received_context == {"notification_source": "event_system"}
|
|
482
|
+
|
|
483
|
+
|
|
484
|
+
# =============================================================================
|
|
485
|
+
# RUN TESTS
|
|
486
|
+
# =============================================================================
|
|
487
|
+
|
|
488
|
+
if __name__ == "__main__":
|
|
489
|
+
pytest.main([__file__, "-v", "-s"])
|