From b91cac7b4b948ddaefb9f58d4bd144b8431a9eef Mon Sep 17 00:00:00 2001 From: Teknium <127238744+teknium1@users.noreply.github.com> Date: Sat, 14 Mar 2026 03:12:15 -0700 Subject: [PATCH] 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 --- tests/gateway/test_email.py | 47 ++++++++++++++++++++----------------- 1 file changed, 25 insertions(+), 22 deletions(-) diff --git a/tests/gateway/test_email.py b/tests/gateway/test_email.py index 05cb11f55..5344d369c 100644 --- a/tests/gateway/test_email.py +++ b/tests/gateway/test_email.py @@ -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": ""} - 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") )