1- import os
21import shlex
3- import signal
42import subprocess
5- import sys
63import tempfile
74import time
85from contextlib import contextmanager
1411
1512from dapr .clients import DaprClient
1613from dapr .conf import settings
14+ from tests ._process_utils import get_kwargs_for_process_group , terminate_process_group
1715
1816T = TypeVar ('T' )
1917
2220APPS_DIR = INTEGRATION_DIR / 'apps'
2321
2422
25- def _new_process_group_kwargs () -> dict [str , Any ]:
26- """Popen kwargs that place the child at the head of its own process group.
27-
28- ``dapr run`` spawns ``daprd`` and the user's app as siblings; signaling
29- only the immediate process can orphan them if the signal isn't forwarded,
30- which leaves stale listeners on the test ports across runs. Putting the
31- whole subtree in its own group lets cleanup take them all down together.
32- """
33- if sys .platform == 'win32' :
34- return {'creationflags' : subprocess .CREATE_NEW_PROCESS_GROUP }
35- return {'start_new_session' : True }
36-
37-
38- def _terminate_process_group (proc : subprocess .Popen [str ], * , force : bool = False ) -> None :
39- """Sends the right termination signal to an entire process group."""
40- if sys .platform == 'win32' :
41- if force :
42- proc .kill ()
43- else :
44- proc .send_signal (signal .CTRL_BREAK_EVENT )
45- else :
46- cleanup_signal_unix = signal .SIGKILL if force else signal .SIGTERM
47- os .killpg (os .getpgid (proc .pid ), cleanup_signal_unix )
48-
49-
5023class DaprTestEnvironment :
5124 """Manages Dapr sidecars and returns SDK clients for programmatic testing.
5225
@@ -57,7 +30,6 @@ class returns real DaprClient instances so tests can make assertions against SDK
5730 def __init__ (self , default_components : Path = COMPONENTS_DIR ) -> None :
5831 self ._default_components = default_components
5932 self ._processes : list [subprocess .Popen [str ]] = []
60- self ._log_files : list [Path ] = []
6133 self ._clients : list [DaprClient ] = []
6234
6335 def start_sidecar (
@@ -100,15 +72,14 @@ def start_sidecar(
10072 if app_cmd is not None :
10173 cmd .extend (['--' , * shlex .split (app_cmd )])
10274
103- with tempfile .NamedTemporaryFile (mode = 'w' , suffix = f'-{ app_id } .log' , delete = False ) as log :
104- self ._log_files .append (Path (log .name ))
75+ with tempfile .NamedTemporaryFile (mode = 'w' , suffix = f'-{ app_id } .log' ) as log :
10576 proc = subprocess .Popen (
10677 cmd ,
10778 cwd = INTEGRATION_DIR ,
10879 stdout = log ,
10980 stderr = subprocess .STDOUT ,
11081 text = True ,
111- ** _new_process_group_kwargs (),
82+ ** get_kwargs_for_process_group (),
11283 )
11384 self ._processes .append (proc )
11485
@@ -137,18 +108,14 @@ def cleanup(self) -> None:
137108
138109 for proc in self ._processes :
139110 if proc .poll () is None :
140- _terminate_process_group (proc )
111+ terminate_process_group (proc )
141112 try :
142113 proc .wait (timeout = 10 )
143114 except subprocess .TimeoutExpired :
144- _terminate_process_group (proc , force = True )
115+ terminate_process_group (proc , force = True )
145116 proc .wait ()
146117 self ._processes .clear ()
147118
148- for log_path in self ._log_files :
149- log_path .unlink (missing_ok = True )
150- self ._log_files .clear ()
151-
152119
153120def _wait_until (
154121 predicate : Callable [[], T | None ],
0 commit comments