test: make gateway async tests xdist-safe (#1281)

* feat: improve context compaction handoff summaries

Adapt PR #916 onto current main by replacing the old context summary marker
with a clearer handoff wrapper, updating the summarization prompt for
resume-oriented summaries, and preserving the current call_llm-based
compression path.

* fix: clearer error when docker backend is unavailable

* fix: preserve docker discovery in backend preflight

Follow up on salvaged PR #940 by reusing find_docker() during the new
availability check so non-PATH Docker Desktop installs still work. Add
a regression test covering the resolved executable path.

* test: make gateway async tests xdist-safe

Replace sync test usage of asyncio.get_event_loop().run_until_complete()
with asyncio.run() so tests do not depend on an ambient current event loop.
Also create the email disconnect poll task inside a running loop. This fixes
xdist/CI failures where workers have no current loop in MainThread.

---------

Co-authored-by: aydnOktay <xaydinoktay@gmail.com>
This commit is contained in:
Teknium
2026-03-14 03:12:15 -07:00
committed by GitHub
parent 29312a23d9
commit b91cac7b4b

View File

@@ -407,7 +407,7 @@ class TestDispatchMessage(unittest.TestCase):
"date": "",
}
asyncio.get_event_loop().run_until_complete(adapter._dispatch_message(msg_data))
asyncio.run(adapter._dispatch_message(msg_data))
adapter._message_handler.assert_not_called()
def test_subject_included_in_text(self):
@@ -441,7 +441,7 @@ class TestDispatchMessage(unittest.TestCase):
"date": "",
}
asyncio.get_event_loop().run_until_complete(adapter._dispatch_message(msg_data))
asyncio.run(adapter._dispatch_message(msg_data))
self.assertEqual(len(captured_events), 1)
self.assertIn("[Subject: Help with Python]", captured_events[0].text)
self.assertIn("How do I use lists?", captured_events[0].text)
@@ -469,7 +469,7 @@ class TestDispatchMessage(unittest.TestCase):
"date": "",
}
asyncio.get_event_loop().run_until_complete(adapter._dispatch_message(msg_data))
asyncio.run(adapter._dispatch_message(msg_data))
self.assertEqual(len(captured_events), 1)
self.assertNotIn("[Subject:", captured_events[0].text)
self.assertEqual(captured_events[0].text, "Thanks for the help!")
@@ -497,7 +497,7 @@ class TestDispatchMessage(unittest.TestCase):
"date": "",
}
asyncio.get_event_loop().run_until_complete(adapter._dispatch_message(msg_data))
asyncio.run(adapter._dispatch_message(msg_data))
self.assertEqual(len(captured_events), 1)
self.assertIn("(empty email)", captured_events[0].text)
@@ -525,7 +525,7 @@ class TestDispatchMessage(unittest.TestCase):
"date": "",
}
asyncio.get_event_loop().run_until_complete(adapter._dispatch_message(msg_data))
asyncio.run(adapter._dispatch_message(msg_data))
self.assertEqual(len(captured_events), 1)
self.assertEqual(captured_events[0].message_type, MessageType.PHOTO)
self.assertEqual(captured_events[0].media_urls, ["/tmp/img.jpg"])
@@ -553,7 +553,7 @@ class TestDispatchMessage(unittest.TestCase):
"date": "",
}
asyncio.get_event_loop().run_until_complete(adapter._dispatch_message(msg_data))
asyncio.run(adapter._dispatch_message(msg_data))
event = captured_events[0]
self.assertEqual(event.source.chat_id, "john@example.com")
self.assertEqual(event.source.user_id, "john@example.com")
@@ -598,7 +598,7 @@ class TestThreadContext(unittest.TestCase):
"date": "",
}
asyncio.get_event_loop().run_until_complete(adapter._dispatch_message(msg_data))
asyncio.run(adapter._dispatch_message(msg_data))
ctx = adapter._thread_context.get("user@test.com")
self.assertIsNotNone(ctx)
self.assertEqual(ctx["subject"], "Project question")
@@ -680,7 +680,7 @@ class TestSendMethods(unittest.TestCase):
mock_server = MagicMock()
mock_smtp.return_value = mock_server
result = asyncio.get_event_loop().run_until_complete(
result = asyncio.run(
adapter.send("user@test.com", "Hello from Hermes!")
)
@@ -698,7 +698,7 @@ class TestSendMethods(unittest.TestCase):
with patch("smtplib.SMTP") as mock_smtp:
mock_smtp.side_effect = Exception("Connection refused")
result = asyncio.get_event_loop().run_until_complete(
result = asyncio.run(
adapter.send("user@test.com", "Hello")
)
@@ -713,7 +713,7 @@ class TestSendMethods(unittest.TestCase):
adapter.send = AsyncMock(return_value=SendResult(success=True))
asyncio.get_event_loop().run_until_complete(
asyncio.run(
adapter.send_image("user@test.com", "https://img.com/photo.jpg", "My photo")
)
@@ -737,7 +737,7 @@ class TestSendMethods(unittest.TestCase):
mock_server = MagicMock()
mock_smtp.return_value = mock_server
result = asyncio.get_event_loop().run_until_complete(
result = asyncio.run(
adapter.send_document("user@test.com", tmp_path, "Here is the file")
)
@@ -759,7 +759,7 @@ class TestSendMethods(unittest.TestCase):
import asyncio
adapter = self._make_adapter()
# Should not raise
asyncio.get_event_loop().run_until_complete(adapter.send_typing("user@test.com"))
asyncio.run(adapter.send_typing("user@test.com"))
def test_get_chat_info(self):
"""get_chat_info should return email address as chat info."""
@@ -767,7 +767,7 @@ class TestSendMethods(unittest.TestCase):
adapter = self._make_adapter()
adapter._thread_context["user@test.com"] = {"subject": "Test", "message_id": "<m@t>"}
info = asyncio.get_event_loop().run_until_complete(
info = asyncio.run(
adapter.get_chat_info("user@test.com")
)
@@ -804,7 +804,7 @@ class TestConnectDisconnect(unittest.TestCase):
mock_server = MagicMock()
mock_smtp.return_value = mock_server
result = asyncio.get_event_loop().run_until_complete(adapter.connect())
result = asyncio.run(adapter.connect())
self.assertTrue(result)
self.assertTrue(adapter._running)
@@ -821,7 +821,7 @@ class TestConnectDisconnect(unittest.TestCase):
adapter = self._make_adapter()
with patch("imaplib.IMAP4_SSL", side_effect=Exception("IMAP down")):
result = asyncio.get_event_loop().run_until_complete(adapter.connect())
result = asyncio.run(adapter.connect())
self.assertFalse(result)
self.assertFalse(adapter._running)
@@ -835,7 +835,7 @@ class TestConnectDisconnect(unittest.TestCase):
with patch("imaplib.IMAP4_SSL", return_value=mock_imap), \
patch("smtplib.SMTP", side_effect=Exception("SMTP down")):
result = asyncio.get_event_loop().run_until_complete(adapter.connect())
result = asyncio.run(adapter.connect())
self.assertFalse(result)
def test_disconnect_cancels_poll(self):
@@ -843,9 +843,12 @@ class TestConnectDisconnect(unittest.TestCase):
import asyncio
adapter = self._make_adapter()
adapter._running = True
adapter._poll_task = asyncio.ensure_future(asyncio.sleep(100))
asyncio.get_event_loop().run_until_complete(adapter.disconnect())
async def _exercise_disconnect():
adapter._poll_task = asyncio.create_task(asyncio.sleep(100))
await adapter.disconnect()
asyncio.run(_exercise_disconnect())
self.assertFalse(adapter._running)
self.assertIsNone(adapter._poll_task)
@@ -967,7 +970,7 @@ class TestPollLoop(unittest.TestCase):
mock_imap.fetch.return_value = ("OK", [(b"1", raw_email.as_bytes())])
with patch("imaplib.IMAP4_SSL", return_value=mock_imap):
asyncio.get_event_loop().run_until_complete(adapter._check_inbox())
asyncio.run(adapter._check_inbox())
self.assertEqual(len(dispatched), 1)
self.assertEqual(dispatched[0]["subject"], "Inbox Test")
@@ -991,7 +994,7 @@ class TestSendEmailStandalone(unittest.TestCase):
mock_server = MagicMock()
mock_smtp.return_value = mock_server
result = asyncio.get_event_loop().run_until_complete(
result = asyncio.run(
_send_email({"address": "hermes@test.com", "smtp_host": "smtp.test.com"}, "user@test.com", "Hello")
)
@@ -1009,7 +1012,7 @@ class TestSendEmailStandalone(unittest.TestCase):
from tools.send_message_tool import _send_email
with patch("smtplib.SMTP", side_effect=Exception("SMTP error")):
result = asyncio.get_event_loop().run_until_complete(
result = asyncio.run(
_send_email({"address": "hermes@test.com", "smtp_host": "smtp.test.com"}, "user@test.com", "Hello")
)
@@ -1022,7 +1025,7 @@ class TestSendEmailStandalone(unittest.TestCase):
import asyncio
from tools.send_message_tool import _send_email
result = asyncio.get_event_loop().run_until_complete(
result = asyncio.run(
_send_email({}, "user@test.com", "Hello")
)