Start a daemon once per session and return the socket path.
()
| 54 | |
| 55 | @pytest.fixture(scope="session") |
| 56 | def daemon_sock() -> Iterator[str]: |
| 57 | """Start a daemon once per session and return the socket path.""" |
| 58 | import cocoindex_code.daemon as dm |
| 59 | |
| 60 | # Use a short path to stay within AF_UNIX limit |
| 61 | user_dir = Path(tempfile.mkdtemp(prefix="ccc_d_")) |
| 62 | user_dir.mkdir(parents=True, exist_ok=True) |
| 63 | |
| 64 | # Use COCOINDEX_CODE_DIR env var for isolation instead of direct module patching. |
| 65 | # Direct patching of dm.user_settings_dir leaks across test modules and causes |
| 66 | # stop_daemon() in other fixtures to read the wrong PID file (pytest's own PID). |
| 67 | old_env = os.environ.get("COCOINDEX_CODE_DIR") |
| 68 | os.environ["COCOINDEX_CODE_DIR"] = str(user_dir) |
| 69 | |
| 70 | save_user_settings(make_test_user_settings()) |
| 71 | |
| 72 | thread = threading.Thread(target=dm.run_daemon, daemon=True) |
| 73 | thread.start() |
| 74 | |
| 75 | sock_path = dm.daemon_socket_path() |
| 76 | |
| 77 | deadline = time.monotonic() + 20 |
| 78 | while time.monotonic() < deadline: |
| 79 | if os.path.exists(sock_path): |
| 80 | break |
| 81 | time.sleep(0.1) |
| 82 | else: |
| 83 | raise TimeoutError("Daemon did not start") |
| 84 | |
| 85 | yield sock_path |
| 86 | |
| 87 | # Gracefully shut down the daemon thread so named pipes are released on Windows |
| 88 | try: |
| 89 | conn = Client(sock_path, family=connection_family()) |
| 90 | conn.send_bytes(encode_request(HandshakeRequest(version=__version__))) |
| 91 | conn.recv_bytes() |
| 92 | conn.send_bytes(encode_request(StopRequest())) |
| 93 | conn.recv_bytes() |
| 94 | conn.close() |
| 95 | except Exception: |
| 96 | pass |
| 97 | thread.join(timeout=5) |
| 98 | |
| 99 | if old_env is None: |
| 100 | os.environ.pop("COCOINDEX_CODE_DIR", None) |
| 101 | else: |
| 102 | os.environ["COCOINDEX_CODE_DIR"] = old_env |
| 103 | |
| 104 | |
| 105 | def _recv_index_response(conn: Connection) -> tuple[list[IndexProgressUpdate], IndexResponse]: |
nothing calls this directly
no test coverage detected