This method sets up the gRPC service by starting the server
(self)
| 59 | TestBackendServicer is the class that tests the gRPC service |
| 60 | """ |
| 61 | def setUp(self): |
| 62 | """ |
| 63 | This method sets up the gRPC service by starting the server |
| 64 | """ |
| 65 | print("Starting backend server...", file=sys.stderr, flush=True) |
| 66 | self.backend_log = open(BACKEND_LOG, "w") |
| 67 | self.service = subprocess.Popen( |
| 68 | ["python3", "backend.py", "--addr", "localhost:50051"], |
| 69 | stdout=self.backend_log, |
| 70 | stderr=self.backend_log, |
| 71 | ) |
| 72 | |
| 73 | # Start tailing backend log so CI sees progress in real time |
| 74 | self._log_stop = threading.Event() |
| 75 | self._log_thread = threading.Thread( |
| 76 | target=_tail_log, args=(BACKEND_LOG, self._log_stop), daemon=True |
| 77 | ) |
| 78 | self._log_thread.start() |
| 79 | |
| 80 | # Poll for readiness instead of a fixed sleep |
| 81 | print("Waiting for backend to be ready...", file=sys.stderr, flush=True) |
| 82 | max_wait = 60 |
| 83 | start = time.time() |
| 84 | ready = False |
| 85 | while time.time() - start < max_wait: |
| 86 | try: |
| 87 | with grpc.insecure_channel("localhost:50051") as channel: |
| 88 | stub = backend_pb2_grpc.BackendStub(channel) |
| 89 | resp = stub.Health(backend_pb2.HealthMessage(), timeout=2.0) |
| 90 | if resp.message: |
| 91 | ready = True |
| 92 | break |
| 93 | except Exception: |
| 94 | pass |
| 95 | # Check if process died |
| 96 | if self.service.poll() is not None: |
| 97 | self.fail(f"Backend process exited early with code {self.service.returncode}") |
| 98 | time.sleep(2) |
| 99 | |
| 100 | elapsed = time.time() - start |
| 101 | if not ready: |
| 102 | self.fail(f"Backend not ready after {max_wait}s") |
| 103 | print(f"Backend ready after {elapsed:.1f}s", file=sys.stderr, flush=True) |
| 104 | |
| 105 | def tearDown(self) -> None: |
| 106 | """ |