@@ -324,29 +324,70 @@ async fn read_varint(r: &mut BufReader<ChildStdout>) -> Result<usize, Error> {
324324
325325#[ cfg( test) ]
326326mod tests {
327+ use std:: io:: Write as _;
328+
327329 use nativelink_macro:: nativelink_test;
328330
329331 use super :: * ;
330332
331- fn echo_script ( working_dir : & Path , body : & str ) -> PathBuf {
333+ struct TestWorkerProgram {
334+ executable : PathBuf ,
335+ startup_args : Vec < String > ,
336+ }
337+
338+ impl TestWorkerProgram {
339+ fn startup_args ( & self ) -> & [ String ] {
340+ & self . startup_args
341+ }
342+ }
343+
344+ #[ cfg( unix) ]
345+ fn echo_script ( working_dir : & Path , unix_body : & str , _windows_body : & str ) -> TestWorkerProgram {
332346 let path = working_dir. join ( "worker.sh" ) ;
333- std:: fs:: write ( & path, body) . unwrap ( ) ;
334- #[ cfg( unix) ]
335- {
336- use std:: os:: unix:: fs:: PermissionsExt ;
337- std:: fs:: set_permissions ( & path, std:: fs:: Permissions :: from_mode ( 0o755 ) ) . unwrap ( ) ;
347+ let mut file = std:: fs:: File :: create ( & path) . unwrap ( ) ;
348+ file. write_all ( unix_body. as_bytes ( ) ) . unwrap ( ) ;
349+ file. sync_all ( ) . unwrap ( ) ;
350+ drop ( file) ;
351+
352+ TestWorkerProgram {
353+ executable : PathBuf :: from ( "/bin/sh" ) ,
354+ startup_args : vec ! [ path. display( ) . to_string( ) ] ,
355+ }
356+ }
357+
358+ #[ cfg( windows) ]
359+ fn echo_script ( working_dir : & Path , _unix_body : & str , windows_body : & str ) -> TestWorkerProgram {
360+ let path = working_dir. join ( "worker.ps1" ) ;
361+ let mut file = std:: fs:: File :: create ( & path) . unwrap ( ) ;
362+ file. write_all ( windows_body. as_bytes ( ) ) . unwrap ( ) ;
363+ file. sync_all ( ) . unwrap ( ) ;
364+ drop ( file) ;
365+
366+ TestWorkerProgram {
367+ executable : PathBuf :: from ( "powershell.exe" ) ,
368+ startup_args : vec ! [
369+ "-NoProfile" . to_owned( ) ,
370+ "-ExecutionPolicy" . to_owned( ) ,
371+ "Bypass" . to_owned( ) ,
372+ "-File" . to_owned( ) ,
373+ path. display( ) . to_string( ) ,
374+ ] ,
338375 }
339- path
340376 }
341377
342378 #[ nativelink_test]
343379 async fn shutdown_kills_unresponsive_worker ( ) {
344380 // A worker that never reads/writes — shutdown grace expires, we SIGKILL.
345381 let dir = tempfile:: tempdir ( ) . unwrap ( ) ;
346- let script = echo_script ( dir. path ( ) , "#!/bin/sh\n exec sleep 30\n " ) ;
347- let worker = LiveWorker :: spawn ( & script, & [ ] , WireFormat :: Json , dir. path ( ) )
348- . await
349- . unwrap ( ) ;
382+ let script = echo_script ( dir. path ( ) , "exec sleep 30\n " , "Start-Sleep -Seconds 30\n " ) ;
383+ let worker = LiveWorker :: spawn (
384+ & script. executable ,
385+ script. startup_args ( ) ,
386+ WireFormat :: Json ,
387+ dir. path ( ) ,
388+ )
389+ . await
390+ . unwrap ( ) ;
350391 let start = Instant :: now ( ) ;
351392 worker. shutdown ( Duration :: from_millis ( 100 ) ) . await ;
352393 // SIGKILL should arrive well within a second.
@@ -360,11 +401,17 @@ mod tests {
360401 let script = echo_script (
361402 dir. path ( ) ,
362403 // Read one line, ignore it, emit a fixed response. Newline-terminated.
363- "#!/bin/sh\n read line\n echo '{\" exitCode\" :0,\" output\" :\" ok\" }'\n " ,
404+ "read line\n echo '{\" exitCode\" :0,\" output\" :\" ok\" }'\n " ,
405+ "$line = [Console]::In.ReadLine()\n [Console]::Out.WriteLine('{\" exitCode\" :0,\" output\" :\" ok\" }')\n " ,
364406 ) ;
365- let mut worker = LiveWorker :: spawn ( & script, & [ ] , WireFormat :: Json , dir. path ( ) )
366- . await
367- . unwrap ( ) ;
407+ let mut worker = LiveWorker :: spawn (
408+ & script. executable ,
409+ script. startup_args ( ) ,
410+ WireFormat :: Json ,
411+ dir. path ( ) ,
412+ )
413+ . await
414+ . unwrap ( ) ;
368415
369416 let req = WorkRequest {
370417 arguments : vec ! [ "compile" . into( ) ] ,
@@ -382,10 +429,19 @@ mod tests {
382429 async fn dispatch_timeout_kills_worker ( ) {
383430 let dir = tempfile:: tempdir ( ) . unwrap ( ) ;
384431 // Worker reads, then sleeps forever instead of responding.
385- let script = echo_script ( dir. path ( ) , "#!/bin/sh\n read line\n exec sleep 60\n " ) ;
386- let mut worker = LiveWorker :: spawn ( & script, & [ ] , WireFormat :: Json , dir. path ( ) )
387- . await
388- . unwrap ( ) ;
432+ let script = echo_script (
433+ dir. path ( ) ,
434+ "read line\n exec sleep 60\n " ,
435+ "$line = [Console]::In.ReadLine()\n Start-Sleep -Seconds 60\n " ,
436+ ) ;
437+ let mut worker = LiveWorker :: spawn (
438+ & script. executable ,
439+ script. startup_args ( ) ,
440+ WireFormat :: Json ,
441+ dir. path ( ) ,
442+ )
443+ . await
444+ . unwrap ( ) ;
389445
390446 let req = WorkRequest {
391447 arguments : vec ! [ "compile" . into( ) ] ,
@@ -404,11 +460,17 @@ mod tests {
404460 let dir = tempfile:: tempdir ( ) . unwrap ( ) ;
405461 let script = echo_script (
406462 dir. path ( ) ,
407- "#!/bin/sh\n read line\n echo '{\" exitCode\" :0}'\n " ,
463+ "read line\n echo '{\" exitCode\" :0}'\n " ,
464+ "$line = [Console]::In.ReadLine()\n [Console]::Out.WriteLine('{\" exitCode\" :0}')\n " ,
408465 ) ;
409- let mut worker = LiveWorker :: spawn ( & script, & [ ] , WireFormat :: Json , dir. path ( ) )
410- . await
411- . unwrap ( ) ;
466+ let mut worker = LiveWorker :: spawn (
467+ & script. executable ,
468+ script. startup_args ( ) ,
469+ WireFormat :: Json ,
470+ dir. path ( ) ,
471+ )
472+ . await
473+ . unwrap ( ) ;
412474 let req = WorkRequest {
413475 request_id : 7 ,
414476 ..WorkRequest :: default ( )
0 commit comments