1010use std:: io:: prelude:: * ;
1111use std:: io:: BufReader ;
1212use std:: path:: PathBuf ;
13- use std:: process:: { Command , Stdio } ;
13+ use std:: process:: { Child , Command , Stdio } ;
1414use std:: sync:: { Arc , Mutex } ;
1515use std:: thread;
1616#[ cfg( test) ]
@@ -39,7 +39,7 @@ pub(crate) const WEBDRIVER_URL: &str = "http://localhost";
3939struct WdInner {
4040 webdriver_port : u32 ,
4141 driver_path : PathBuf ,
42- webdriver_process_id : Option < u32 > ,
42+ webdriver_child : Option < Child > ,
4343 is_external : bool , /* Marker for whether this WebDriver was spawned by us or connected to
4444 * existing */
4545}
@@ -97,7 +97,7 @@ impl WebDriver {
9797 inner : Arc :: new ( Mutex :: new ( WdInner {
9898 webdriver_port : port,
9999 driver_path : full_path,
100- webdriver_process_id : None ,
100+ webdriver_child : None ,
101101 is_external : false , // mark it as spawned by us
102102 } ) ) ,
103103 } )
@@ -113,51 +113,40 @@ impl WebDriver {
113113 /// using the `stop()` method.
114114 pub ( crate ) fn spawn_webdriver ( & mut self ) {
115115 info ! ( "Spawning {WEBDRIVER_BIN}" ) ;
116- let local_self = self . inner . clone ( ) ;
116+
117+ // Spawn the process in the main thread to get the Child handle
118+ let mut command = Command :: new ( self . inner . lock ( ) . unwrap ( ) . driver_path . clone ( ) ) ;
119+ command
120+ . arg ( format ! ( "--port={}" , self . inner. lock( ) . unwrap( ) . webdriver_port) )
121+ . stdin ( Stdio :: piped ( ) )
122+ . stdout ( Stdio :: piped ( ) )
123+ . stderr ( Stdio :: piped ( ) ) ;
117124
118- let _ = thread:: spawn ( move || {
119- let mut inner = match local_self. lock ( ) {
120- Ok ( inner) => inner,
121- Err ( e) => {
122- error ! ( "Could not acquire lock: {e}" ) ;
123- return ;
124- }
125- } ;
126-
127- let mut command = Command :: new ( inner. driver_path . clone ( ) ) ;
128- command
129- . arg ( format ! ( "--port={}" , inner. webdriver_port) )
130- . stdin ( Stdio :: piped ( ) )
131- . stdout ( Stdio :: piped ( ) )
132- . stderr ( Stdio :: piped ( ) ) ;
133-
134- let mut child = match command. spawn ( ) {
135- Ok ( c) => {
136- inner. webdriver_process_id = Some ( c. id ( ) ) ;
137- c
138- }
139- Err ( e) => {
140- error ! ( "Failed to spawn '{WEBDRIVER_BIN}': {e}" ) ;
141- return ;
142- }
143- } ;
144- drop ( inner) ;
125+ let mut child = match command. spawn ( ) {
126+ Ok ( c) => c,
127+ Err ( e) => {
128+ error ! ( "Failed to spawn '{WEBDRIVER_BIN}': {e}" ) ;
129+ return ;
130+ }
131+ } ;
145132
146- match child. wait ( ) {
147- Ok ( c) => {
148- info ! ( "Terminated with ExitStatus: {c}" ) ;
149- let stderr = child. stderr . take ( ) . unwrap ( ) ;
150- let stderr_lines = BufReader :: new ( stderr) . lines ( ) ;
151- for line in stderr_lines {
152- let line = line. unwrap ( ) ;
133+ // Spawn a thread to handle the process stderr output (logging only)
134+ if let Some ( stderr) = child. stderr . take ( ) {
135+ thread:: spawn ( move || {
136+ let stderr_lines = BufReader :: new ( stderr) . lines ( ) ;
137+ for line in stderr_lines {
138+ if let Ok ( line) = line {
153139 debug ! ( "{line}" ) ;
154140 }
155141 }
156- Err ( e) => {
157- error ! ( "Failed waiting on '{WEBDRIVER_BIN}': {e}" ) ;
158- }
159- } ;
160- } ) ;
142+ } ) ;
143+ }
144+
145+ // Store the Child handle (without stderr)
146+ {
147+ let mut inner = self . inner . lock ( ) . unwrap ( ) ;
148+ inner. webdriver_child = Some ( child) ;
149+ }
161150 }
162151
163152 /// Stops the WebDriver process
@@ -172,14 +161,28 @@ impl WebDriver {
172161 /// Returns `Ok(())` on success, or an error if the process termination
173162 /// fails.
174163 pub fn stop ( & mut self ) -> Result < ( ) > {
175- let inner = self . inner . lock ( ) . unwrap ( ) ;
164+ let mut inner = self . inner . lock ( ) . unwrap ( ) ;
176165
177166 // Only stop the process if we spawned it (not if it's external)
178167 if !inner. is_external {
179- if let Some ( id) = inner. webdriver_process_id {
180- info ! ( "Stopping '{WEBDRIVER_BIN}' (PID: {id})" ) ;
181- let mut kill = Command :: new ( "kill" ) . arg ( id. to_string ( ) ) . spawn ( ) ?;
182- kill. wait ( ) ?;
168+ if let Some ( child) = inner. webdriver_child . as_mut ( ) {
169+ info ! ( "Stopping '{WEBDRIVER_BIN}' (PID: {})" , child. id( ) ) ;
170+
171+ // Use the robust Child::kill() method which works cross-platform
172+ match child. kill ( ) {
173+ Ok ( _) => {
174+ info ! ( "Successfully sent kill signal to WebDriver process" ) ;
175+ // Wait for the process to terminate
176+ match child. wait ( ) {
177+ Ok ( status) => info ! ( "WebDriver process terminated with status: {status}" ) ,
178+ Err ( e) => warn ! ( "Failed to wait for WebDriver process termination: {e}" ) ,
179+ }
180+ }
181+ Err ( e) => {
182+ error ! ( "Failed to kill WebDriver process: {e}" ) ;
183+ return Err ( anyhow ! ( "Failed to kill WebDriver process: {e}" ) ) ;
184+ }
185+ }
183186 }
184187 } else {
185188 warn ! (
@@ -272,7 +275,14 @@ impl WebDriver {
272275 None => {
273276 // For external connections, we don't need the actual path
274277 // Just use a placeholder since we're not spawning
275- String :: from ( "/usr/bin/webdriver" )
278+ #[ cfg( target_os = "windows" ) ]
279+ {
280+ String :: from ( "C:\\ Windows\\ System32\\ webdriver.exe" )
281+ }
282+ #[ cfg( not( target_os = "windows" ) ) ]
283+ {
284+ String :: from ( "/usr/bin/webdriver" )
285+ }
276286 }
277287 } ,
278288 } ;
@@ -283,7 +293,7 @@ impl WebDriver {
283293 inner : Arc :: new ( Mutex :: new ( WdInner {
284294 webdriver_port : port,
285295 driver_path : full_path,
286- webdriver_process_id : None ,
296+ webdriver_child : None ,
287297 is_external : true , // Mark as external since we didn't spawn it
288298 } ) ) ,
289299 } )
@@ -314,8 +324,16 @@ impl WebDriver {
314324 }
315325
316326 #[ cfg( target_os = "windows" ) ]
317- fn os_binary_path ( path : PathBuf ) -> PathBuf {
327+ fn os_binary_path ( path : PathBuf ) -> Result < PathBuf > {
318328 let app = format ! ( "{WEBDRIVER_BIN}.exe" ) ;
319- path. join ( app)
329+ let full_path = path. join ( app) ;
330+ if full_path. exists ( ) {
331+ Ok ( full_path)
332+ } else {
333+ Err ( anyhow ! (
334+ "No {WEBDRIVER_BIN}.exe found at '{}'" ,
335+ path. display( )
336+ ) )
337+ }
320338 }
321339}
0 commit comments