From f9be9d679a64c00184f629ee976df15931287128 Mon Sep 17 00:00:00 2001 From: jackie-pc <136611113+jackie-pc@users.noreply.github.com> Date: Tue, 1 Aug 2023 16:19:39 -0700 Subject: [PATCH] fail faster in integration test (#1493) --- scripts/integration.sh | 13 ++++++++++-- scripts/wait_for_listening_port.py | 34 +++++++++++++++++++++++------- 2 files changed, 37 insertions(+), 10 deletions(-) diff --git a/scripts/integration.sh b/scripts/integration.sh index 326c29e94..b35efe6d0 100755 --- a/scripts/integration.sh +++ b/scripts/integration.sh @@ -10,11 +10,20 @@ export PYTHONUNBUFFERED=1 # Start the server in the background reflex run --loglevel debug --env "$2" & pid=$! -# TODO does this even work on windows? Not clear, possibly not impactful though. -trap "kill -INT $pid ||:" EXIT +# Within the context of this bash, $pid_in_bash is what we need to pass to "kill" on exit +# This is true on all platforms. +pid_in_bash=$pid +trap "kill -INT $pid_in_bash ||:" EXIT echo "Started server with PID $pid" # Assume we run from the root of the repo popd + +# In Windows, our Python script below needs to work with the WINPID +if [ -f /proc/$pid/winpid ]; then + pid=$(cat /proc/$pid/winpid) + echo "Windows detected, passing winpid $pid to port waiter" +fi + python scripts/wait_for_listening_port.py 3000 8000 --timeout=600 --server-pid "$pid" \ No newline at end of file diff --git a/scripts/wait_for_listening_port.py b/scripts/wait_for_listening_port.py index 0b2b1cf5d..093b8e7e2 100644 --- a/scripts/wait_for_listening_port.py +++ b/scripts/wait_for_listening_port.py @@ -7,21 +7,36 @@ import argparse import socket import time from concurrent.futures import ThreadPoolExecutor, as_completed +from typing import Tuple + +# psutil is already a dependency of Reflex itself - so it's OK to use +import psutil -def _wait_for_port(port, server_pid, timeout): +def _pid_exists(pid): + # os.kill(pid, 0) doesn't work on Windows (actually kills the PID) + # psutil.pid_exists() doesn't work on Windows (does os.kill underneath) + # psutil.pids() seems to return the right thing. Inefficient but doesn't matter - keeps things simple. + # + # Note: For windows, the pid here is really the "winpid". + return pid in psutil.pids() + + +def _wait_for_port(port, server_pid, timeout) -> Tuple[bool, str]: start = time.time() print(f"Waiting for up to {timeout} seconds for port {port} to start listening.") while True: - # TODO fail early if server pid not there + if not _pid_exists(server_pid): + return False, f"Server PID {server_pid} is not running." try: socket.create_connection(("localhost", port), timeout=0.5) - print(f"OK! Port {port} is listening after {time.time() - start} seconds") - return True + return True, f"Port {port} is listening after {time.time() - start} seconds" except Exception: if time.time() - start > timeout: - print(f"FAIL: Port {port} still not listening after {timeout} seconds.") - return False + return ( + False, + f"Port {port} still not listening after {timeout} seconds.", + ) time.sleep(5) @@ -39,8 +54,11 @@ def main(): executor.submit(_wait_for_port, p, args.server_pid, args.timeout) ) for f in as_completed(futures): - if not f.result(): - print("At least one port failed... exiting with failure.") + ok, msg = f.result() + if ok: + print(f"OK: {msg}") + else: + print(f"FAIL: {msg}") exit(1)