@@ -255,6 +255,46 @@ def enable_flag(flag_name: str, headers: dict):
255255 logger .error (f"Error enabling flag '{ flag_name } ': { e } " )
256256
257257
258+ EXPECTED_FLAGS = {
259+ "integration-boolean-flag" ,
260+ "integration-string-flag" ,
261+ "integration-float-flag" ,
262+ "integration-object-flag" ,
263+ "integration-integer-flag" ,
264+ "integration-targeting-flag" ,
265+ }
266+
267+
268+ def wait_for_flags_visible (timeout = 30 , interval = 2 ):
269+ """Poll the client features endpoint until all expected flags are visible.
270+
271+ After flags are created via the Admin API, there is a short propagation
272+ delay before they appear on the Client API. Without this wait the
273+ provider's initial fetch may return stale data, causing flaky tests.
274+ """
275+ headers = {"Authorization" : API_TOKEN }
276+ start = time .time ()
277+ while time .time () - start < timeout :
278+ try :
279+ resp = requests .get (
280+ f"{ UNLEASH_URL } /api/client/features" ,
281+ headers = headers ,
282+ timeout = 5 ,
283+ )
284+ if resp .status_code == 200 :
285+ names = {f ["name" ] for f in resp .json ().get ("features" , [])}
286+ if EXPECTED_FLAGS .issubset (names ):
287+ logger .info ("All flags visible via client API" )
288+ return
289+ logger .info (
290+ f"Waiting for flags; have { len (names )} /{ len (EXPECTED_FLAGS )} "
291+ )
292+ except Exception as e :
293+ logger .warning (f"Polling client features: { e } " )
294+ time .sleep (interval )
295+ raise TimeoutError (f"Flags not visible via client API within { timeout } s" )
296+
297+
258298@pytest .fixture (scope = "session" )
259299def postgres_container ():
260300 """Create and start PostgreSQL container."""
@@ -291,7 +331,7 @@ def unleash_container(postgres_container): # noqa: PLR0915
291331
292332 # Wait for health check to pass
293333 logger .info ("Waiting for Unleash container to be healthy..." )
294- max_wait_time = 60 # 1 minute max wait
334+ max_wait_time = 120 # 2 minutes; Unleash DB migrations can be slow in CI
295335 start_time = time .time ()
296336
297337 while time .time () - start_time < max_wait_time :
@@ -301,6 +341,16 @@ def unleash_container(postgres_container): # noqa: PLR0915
301341 unleash_url = f"http://localhost:{ exposed_port } "
302342 logger .info (f"Trying health check at: { unleash_url } " )
303343 except Exception as port_error :
344+ # if the container exited, fail fast with its logs
345+ docker_container = container .get_wrapped_container ()
346+ if docker_container :
347+ docker_container .reload ()
348+ if docker_container .status in ("exited" , "dead" ):
349+ logs = docker_container .logs ().decode (errors = "replace" )
350+ raise RuntimeError (
351+ f"Unleash container died ({ docker_container .status } ).\n "
352+ f"Logs:\n { logs } "
353+ ) from port_error
304354 logger .error (f"Port not ready yet: { port_error } " )
305355 time .sleep (2 )
306356 continue
@@ -313,10 +363,24 @@ def unleash_container(postgres_container): # noqa: PLR0915
313363 logger .error (f"Health check failed, status: { response .status_code } " )
314364 time .sleep (2 )
315365
366+ except RuntimeError :
367+ raise
316368 except Exception as e :
317369 logger .error (f"Health check error: { e } " )
318370 time .sleep (2 )
319371 else :
372+ # timeout; dump container logs for debugging
373+ try :
374+ docker_container = container .get_wrapped_container ()
375+ if docker_container :
376+ docker_container .reload ()
377+ logs = docker_container .logs ().decode (errors = "replace" )
378+ logger .error (
379+ f"Unleash container status: { docker_container .status } \n "
380+ f"Logs:\n { logs } "
381+ )
382+ except Exception :
383+ pass
320384 raise Exception ("Unleash container did not become healthy within timeout" )
321385
322386 # Get the exposed port and set global URL
@@ -331,9 +395,11 @@ def unleash_container(postgres_container): # noqa: PLR0915
331395
332396@pytest .fixture (scope = "session" , autouse = True )
333397def setup_test_flags (unleash_container ):
334- """Setup test flags before running any tests ."""
398+ """Setup test flags and wait for them to be visible via the client API ."""
335399 logger .info ("Creating test flags in Unleash..." )
336400 create_test_flags ()
401+ logger .info ("Waiting for flags to propagate to client API..." )
402+ wait_for_flags_visible ()
337403 logger .info ("Test flags setup completed" )
338404
339405
0 commit comments