@@ -10,6 +10,7 @@ import (
1010 "os"
1111 "runtime"
1212 "strings"
13+ "sync"
1314 "testing"
1415 "time"
1516
@@ -783,6 +784,133 @@ func TestProcessOutput(t *testing.T) {
783784 w2 := getOutput (t , handler , id )
784785 require .Equal (t , http .StatusOK , w2 .Code )
785786 })
787+
788+ t .Run ("WaitForExit" , func (t * testing.T ) {
789+ t .Parallel ()
790+
791+ handler := newTestAPI (t )
792+
793+ id := startAndGetID (t , handler , workspacesdk.StartProcessRequest {
794+ Command : "echo hello-wait && sleep 0.1" ,
795+ })
796+
797+ w := getOutputWithWait (t , handler , id )
798+ require .Equal (t , http .StatusOK , w .Code )
799+
800+ var resp workspacesdk.ProcessOutputResponse
801+ err := json .NewDecoder (w .Body ).Decode (& resp )
802+ require .NoError (t , err )
803+ require .False (t , resp .Running )
804+ require .NotNil (t , resp .ExitCode )
805+ require .Equal (t , 0 , * resp .ExitCode )
806+ require .Contains (t , resp .Output , "hello-wait" )
807+ })
808+
809+ t .Run ("WaitAlreadyExited" , func (t * testing.T ) {
810+ t .Parallel ()
811+
812+ handler := newTestAPI (t )
813+
814+ id := startAndGetID (t , handler , workspacesdk.StartProcessRequest {
815+ Command : "echo done" ,
816+ })
817+
818+ waitForExit (t , handler , id )
819+
820+ w := getOutputWithWait (t , handler , id )
821+ require .Equal (t , http .StatusOK , w .Code )
822+
823+ var resp workspacesdk.ProcessOutputResponse
824+ err := json .NewDecoder (w .Body ).Decode (& resp )
825+ require .NoError (t , err )
826+ require .False (t , resp .Running )
827+ require .Contains (t , resp .Output , "done" )
828+ })
829+
830+ t .Run ("WaitTimeout" , func (t * testing.T ) {
831+ t .Parallel ()
832+
833+ handler := newTestAPI (t )
834+
835+ id := startAndGetID (t , handler , workspacesdk.StartProcessRequest {
836+ Command : "sleep 300" ,
837+ Background : true ,
838+ })
839+
840+ ctx , cancel := context .WithTimeout (context .Background (), testutil .IntervalMedium )
841+ defer cancel ()
842+
843+ w := getOutputWithWaitCtx (ctx , t , handler , id )
844+ require .Equal (t , http .StatusOK , w .Code )
845+
846+ var resp workspacesdk.ProcessOutputResponse
847+ err := json .NewDecoder (w .Body ).Decode (& resp )
848+ require .NoError (t , err )
849+ require .True (t , resp .Running )
850+
851+ // Kill and wait for the process so cleanup does
852+ // not hang.
853+ postSignal (
854+ t , handler , id ,
855+ workspacesdk.SignalProcessRequest {Signal : "kill" },
856+ )
857+ waitForExit (t , handler , id )
858+ })
859+
860+ t .Run ("ConcurrentWaiters" , func (t * testing.T ) {
861+ t .Parallel ()
862+
863+ handler := newTestAPI (t )
864+
865+ id := startAndGetID (t , handler , workspacesdk.StartProcessRequest {
866+ Command : "sleep 300" ,
867+ Background : true ,
868+ })
869+
870+ var (
871+ wg sync.WaitGroup
872+ resps [2 ]workspacesdk.ProcessOutputResponse
873+ codes [2 ]int
874+ )
875+ for i := range 2 {
876+ wg .Add (1 )
877+ go func () {
878+ defer wg .Done ()
879+ w := getOutputWithWait (t , handler , id )
880+ codes [i ] = w .Code
881+ _ = json .NewDecoder (w .Body ).Decode (& resps [i ])
882+ }()
883+ }
884+
885+ // Signal the process to exit so both waiters unblock.
886+ postSignal (
887+ t , handler , id ,
888+ workspacesdk.SignalProcessRequest {Signal : "kill" },
889+ )
890+
891+ wg .Wait ()
892+
893+ for i := range 2 {
894+ require .Equal (t , http .StatusOK , codes [i ], "waiter %d" , i )
895+ require .False (t , resps [i ].Running , "waiter %d" , i )
896+ }
897+ })
898+ }
899+
900+ func getOutputWithWait (t * testing.T , handler http.Handler , id string ) * httptest.ResponseRecorder {
901+ t .Helper ()
902+ ctx , cancel := context .WithTimeout (context .Background (), testutil .WaitLong )
903+ defer cancel ()
904+ return getOutputWithWaitCtx (ctx , t , handler , id )
905+ }
906+
907+ func getOutputWithWaitCtx (ctx context.Context , t * testing.T , handler http.Handler , id string ) * httptest.ResponseRecorder {
908+ t .Helper ()
909+ path := fmt .Sprintf ("/%s/output?wait=true" , id )
910+ req := httptest .NewRequestWithContext (ctx , http .MethodGet , path , nil )
911+ w := httptest .NewRecorder ()
912+ handler .ServeHTTP (w , req )
913+ return w
786914}
787915
788916func TestSignalProcess (t * testing.T ) {
0 commit comments