44import shutil
55import stat
66import subprocess
7+ import sys
78import tempfile
89import time
910import unittest
1314import app_pb2_grpc as app_service
1415import docker
1516import grpc
17+ from absl import logging
18+
19+ try :
20+ # Initialize the abseil logging system - this prevents the "WARNING: All log messages..." message
21+ logging .set_verbosity (logging .INFO )
22+ logging .use_absl_handler ()
23+ except ImportError :
24+ pass
1625
1726
1827def get_docker_client ():
@@ -47,24 +56,49 @@ def setUp(self):
4756 stderr = subprocess .PIPE ,
4857 )
4958 self .client = get_docker_client ()
50- timeout = time .time () + 120
51- while len (self .client .containers .list ()) != 4 :
52- if time .time () > timeout :
53- raise TimeoutError ()
54- time .sleep (0.001 )
59+ self .wait_for_containers ()
5560
5661 # Wait so that backend can come up.
5762 # TODO: replace with something better
5863 time .sleep (5 )
5964
6065 self .conn = http .client .HTTPConnection ("localhost" , 8080 , timeout = 5 )
61- self .grpcConn = grpc .insecure_channel ("localhost:8081" )
62- try :
63- grpc .channel_ready_future (self .grpcConn ).result (timeout = 10 )
64- except grpc .FutureTimeoutError :
65- sys .exit ("Error connecting to server" )
66+
67+ # Only create the gRPC connection when needed, not during setup
68+ self .grpcConn = None
6669 self .running = True
6770
71+ def wait_for_containers (self , expected_containers = None ):
72+ if expected_containers is None :
73+ expected_containers = ["nginx" , "backend" , "php_fpm" , "grpc" ]
74+
75+ timeout = time .time () + 120
76+ while True :
77+ try :
78+ containers = {c .name : c .status for c in self .client .containers .list ()}
79+
80+ # Check if each expected container name is a substring of any running container
81+ ready = all (
82+ any (
83+ expected in name and status == "running"
84+ for name , status in containers .items ()
85+ )
86+ for expected in expected_containers
87+ )
88+
89+ if ready :
90+ break
91+
92+ if time .time () > timeout :
93+ raise TimeoutError (
94+ f"Containers not ready in time. Current containers: { containers } "
95+ )
96+ time .sleep (0.5 )
97+ except docker .errors .APIError as e :
98+ if time .time () > timeout :
99+ raise TimeoutError (f"Docker API error: { str (e )} " )
100+ time .sleep (0.5 )
101+
68102 def _logEnvironment (self ):
69103 logdir = os .environ ["LOG_DIR" ]
70104 test_log = os .path .join (logdir , self ._testMethodName )
@@ -91,6 +125,16 @@ def _logEnvironment(self):
91125 os .path .join (test_log , "nginx-error.log" ),
92126 )
93127
128+ def _setup_grpc (self ):
129+ """Set up gRPC connection only when needed"""
130+ if self .grpcConn is None :
131+ self .grpcConn = grpc .insecure_channel ("localhost:8081" )
132+ try :
133+ grpc .channel_ready_future (self .grpcConn ).result (timeout = 10 )
134+ except grpc .FutureTimeoutError :
135+ raise RuntimeError ("Error connecting to gRPC server" )
136+ return self .grpcConn
137+
94138 def tearDown (self ):
95139 self ._stopDocker ()
96140 logdir = None
@@ -101,9 +145,17 @@ def tearDown(self):
101145 os .chdir (self .testdir )
102146 self .client .close ()
103147 self .conn .close ()
104- self .grpcConn .close ()
148+
149+ # Only close gRPC if it was created
150+ if self .grpcConn :
151+ self .grpcConn .close ()
105152
106153 def _stopDocker (self ):
154+ # Close any active gRPC connection before Docker operations that might fork
155+ if self .grpcConn is not None :
156+ self .grpcConn .close ()
157+ self .grpcConn = None
158+
107159 if not self .running :
108160 return
109161 self .running = False
@@ -210,11 +262,24 @@ def testFastcgiPropagation(self):
210262 self .assertEqual (len (self .nginx_traces ), 2 )
211263
212264 def testGrpcPropagation (self ):
213- app = app_service .AppStub (self .grpcConn )
214- app .CheckTraceHeader (app_messages .Empty ())
265+ # Set up gRPC just for this test
266+ grpc_conn = self ._setup_grpc ()
267+ app = app_service .AppStub (grpc_conn )
268+ try :
269+ app .CheckTraceHeader (app_messages .Empty ())
270+ except Exception as e :
271+ # Close the connection before allowing any exceptions to propagate
272+ if self .grpcConn :
273+ self .grpcConn .close ()
274+ self .grpcConn = None
275+ raise
276+
277+ # Explicitly close the connection before stopping Docker
278+ if self .grpcConn :
279+ self .grpcConn .close ()
280+ self .grpcConn = None
215281
216282 self ._stopEnvironment ()
217-
218283 self .assertEqual (len (self .nginx_traces ), 2 )
219284
220285
0 commit comments