|
12 | 12 | """ |
13 | 13 |
|
14 | 14 | import asyncio |
15 | | -import json |
16 | 15 | import os |
17 | 16 | import signal |
18 | 17 | import subprocess |
@@ -154,13 +153,17 @@ def test_web_mode_experimental_warning(self): |
154 | 153 | proc.kill() |
155 | 154 | stdout, stderr = proc.communicate() |
156 | 155 | combined = stdout + stderr |
157 | | - # The warning is printed by the CLI before start |
| 156 | + # The warning is printed by the CLI before start. |
| 157 | + # Once the event loop fix landed, neonize actually connects |
| 158 | + # to WhatsApp servers, so we may also see websocket messages. |
158 | 159 | assert ( |
159 | 160 | "experimental" in combined.lower() |
160 | 161 | or "EXPERIMENTAL" in combined |
161 | 162 | or "web mode" in combined.lower() |
162 | 163 | or "Starting WhatsApp" in combined |
163 | | - ), f"Expected experimental warning in output, got: {combined[:500]}" |
| 164 | + or "websocket" in combined.lower() |
| 165 | + or "whatsapp" in combined.lower() |
| 166 | + ), f"Expected WhatsApp output, got: {combined[:500]}" |
164 | 167 | except Exception: |
165 | 168 | proc.kill() |
166 | 169 | proc.wait() |
@@ -430,6 +433,48 @@ async def patched_connect(self_client): |
430 | 433 | finally: |
431 | 434 | NewAClient.connect = original_connect |
432 | 435 |
|
| 436 | + @pytest.mark.asyncio |
| 437 | + async def test_adapter_connect_bridges_event_loop(self): |
| 438 | + """connect() patches neonize's event_global_loop with the running loop. |
| 439 | +
|
| 440 | + Root cause fix: neonize creates event_global_loop = asyncio.new_event_loop() |
| 441 | + at import time but never starts it. Go-thread callbacks (QR, messages) |
| 442 | + are posted to that dead loop. Our adapter must replace it with the |
| 443 | + currently running loop so callbacks actually execute. |
| 444 | + """ |
| 445 | + sys.path.insert(0, PRAISONAI_SRC) |
| 446 | + from praisonai.bots._whatsapp_web_adapter import WhatsAppWebAdapter |
| 447 | + from neonize.aioze.client import NewAClient |
| 448 | + import neonize.aioze.events as nz_events |
| 449 | + import neonize.aioze.client as nz_client |
| 450 | + |
| 451 | + tmpdir = tempfile.mkdtemp() |
| 452 | + adapter = WhatsAppWebAdapter(creds_dir=tmpdir) |
| 453 | + |
| 454 | + running_loop = asyncio.get_running_loop() |
| 455 | + |
| 456 | + # Before connect: neonize's loop is NOT our running loop |
| 457 | + original_nz_loop = nz_events.event_global_loop |
| 458 | + |
| 459 | + original_connect = NewAClient.connect |
| 460 | + async def patched_connect(self_client): |
| 461 | + raise ConnectionError("test: skip real connection") |
| 462 | + |
| 463 | + NewAClient.connect = patched_connect |
| 464 | + try: |
| 465 | + with pytest.raises(ConnectionError): |
| 466 | + await adapter.connect() |
| 467 | + |
| 468 | + # After connect: neonize's event loops must be bridged to ours |
| 469 | + assert nz_events.event_global_loop is running_loop |
| 470 | + assert nz_client.event_global_loop is running_loop |
| 471 | + assert adapter._client.loop is running_loop |
| 472 | + finally: |
| 473 | + NewAClient.connect = original_connect |
| 474 | + # Restore original loop to avoid test pollution |
| 475 | + nz_events.event_global_loop = original_nz_loop |
| 476 | + nz_client.event_global_loop = original_nz_loop |
| 477 | + |
433 | 478 | def test_adapter_logout_cleans_db(self): |
434 | 479 | """logout() removes the DB file.""" |
435 | 480 | sys.path.insert(0, PRAISONAI_SRC) |
|
0 commit comments