@@ -94,6 +94,7 @@ const setupApp = async (env: TestEnv) => {
9494async function sshShellExec (
9595 conn : Client ,
9696 command : string ,
97+ allowNonZeroExitCode = false ,
9798) : Promise < { code : number ; stdout : string ; stderr : string } > {
9899 const START = `__START_${ Math . random ( ) . toString ( 36 ) . slice ( 2 ) } __` ;
99100 const END = `__END_${ Math . random ( ) . toString ( 36 ) . slice ( 2 ) } __` ;
@@ -103,9 +104,13 @@ async function sshShellExec(
103104 if ( err ) return reject ( err ) ;
104105 let stdout = "" ;
105106 let stderr = "" ;
106- let code = - 1 ;
107+ let code = undefined ;
107108 let done = false ;
109+
108110 const parseCode = ( buf : string ) : boolean => {
111+ if ( code !== undefined ) {
112+ return true ; // exit code was set already
113+ }
109114 const idx = buf . indexOf ( `${ END } :` ) ;
110115 if ( idx === - 1 ) return false ;
111116 const tail = buf . substring ( idx + END . length + 1 ) . trim ( ) ;
@@ -143,26 +148,41 @@ async function sshShellExec(
143148 } else if ( startIdx !== - 1 ) {
144149 cmdOut = stdout . substring ( startIdx + START . length ) ;
145150 }
151+ if ( code === undefined ) {
152+ return reject (
153+ new Error (
154+ `ssh error: command=${ command } , stream closed before exit code marker was observed, stdout=${ cmdOut } , stderr=${ stderr } ` ,
155+ ) ,
156+ ) ;
157+ }
158+ if ( ! allowNonZeroExitCode && code !== 0 ) {
159+ return reject (
160+ new Error (
161+ `ssh error: command=${ command } , code=${ code } , stdout=${ cmdOut } , stderr=${ stderr } ` ,
162+ ) ,
163+ ) ;
164+ }
146165 stream . end ( ) ;
147166 resolve ( { code, stdout : cmdOut , stderr } ) ;
148167 } ;
149168 const onStdout = ( d : Buffer ) => {
150169 stdout += d . toString ( ) ;
151170 if ( parseCode ( stdout ) ) {
152- finish ( ) ;
171+ stream . end ( ) ;
153172 }
154173 } ;
155174 const onStderr = ( d : Buffer ) => {
156175 const t = d . toString ( ) ;
157176 stderr += t ;
158177 if ( parseCode ( stderr ) ) {
159- finish ( ) ;
178+ stream . end ( ) ;
160179 }
161180 } ;
162181 stream . on ( "data" , onStdout ) ;
163182 stream . stderr . on ( "data" , onStderr ) ;
164183 stream . on ( "close" , ( ) => {
165184 console . log ( "stream close" ) ;
185+ finish ( ) ;
166186 } ) ;
167187 stream . write ( `echo ${ START } \n` ) ;
168188 stream . write ( `${ command } \n` ) ;
@@ -256,7 +276,7 @@ test("app-ssh", async () => {
256276 expect ( checkData . code ) . toBe ( 0 ) ;
257277 expect ( checkData . stdout ) . toContain ( "ok" ) ;
258278
259- const errCase = await sshShellExec ( conn , "echo oops 1>&2; false" ) ;
279+ const errCase = await sshShellExec ( conn , "echo oops 1>&2; false" , true ) ;
260280 expect ( errCase . code ) . not . toBe ( 0 ) ;
261281 expect ( errCase . stderr ) . toContain ( "oops" ) ;
262282 } finally {
0 commit comments