@@ -31,6 +31,7 @@ import (
31
31
"github.com/coder/coder/cli/clitest"
32
32
"github.com/coder/coder/cli/cliui"
33
33
"github.com/coder/coder/coderd/coderdtest"
34
+ "github.com/coder/coder/coderd/database"
34
35
"github.com/coder/coder/codersdk"
35
36
"github.com/coder/coder/codersdk/agentsdk"
36
37
"github.com/coder/coder/provisioner/echo"
@@ -143,6 +144,50 @@ func TestSSH(t *testing.T) {
143
144
cancel ()
144
145
<- cmdDone
145
146
})
147
+
148
+ t .Run ("ExitOnStop" , func (t * testing.T ) {
149
+ t .Parallel ()
150
+ if runtime .GOOS == "windows" {
151
+ t .Skip ("Windows doesn't seem to clean up the process, maybe #7100 will fix it" )
152
+ }
153
+
154
+ client , workspace , agentToken := setupWorkspaceForAgent (t , nil )
155
+ inv , root := clitest .New (t , "ssh" , workspace .Name )
156
+ clitest .SetupConfig (t , client , root )
157
+ pty := ptytest .New (t ).Attach (inv )
158
+
159
+ ctx , cancel := context .WithTimeout (context .Background (), testutil .WaitLong )
160
+ defer cancel ()
161
+
162
+ cmdDone := tGo (t , func () {
163
+ err := inv .WithContext (ctx ).Run ()
164
+ assert .Error (t , err )
165
+ })
166
+ pty .ExpectMatch ("Waiting" )
167
+
168
+ agentClient := agentsdk .New (client .URL )
169
+ agentClient .SetSessionToken (agentToken )
170
+ agentCloser := agent .New (agent.Options {
171
+ Client : agentClient ,
172
+ Logger : slogtest .Make (t , nil ).Named ("agent" ),
173
+ })
174
+ defer func () {
175
+ _ = agentCloser .Close ()
176
+ }()
177
+
178
+ // Ensure the agent is connected.
179
+ pty .WriteLine ("echo hell'o'" )
180
+ pty .ExpectMatchContext (ctx , "hello" )
181
+
182
+ workspace = coderdtest .MustTransitionWorkspace (t , client , workspace .ID , database .WorkspaceTransitionStart , database .WorkspaceTransitionStop )
183
+
184
+ select {
185
+ case <- cmdDone :
186
+ case <- ctx .Done ():
187
+ require .Fail (t , "command did not exit in time" )
188
+ }
189
+ })
190
+
146
191
t .Run ("Stdio" , func (t * testing.T ) {
147
192
t .Parallel ()
148
193
client , workspace , agentToken := setupWorkspaceForAgent (t , nil )
@@ -207,6 +252,76 @@ func TestSSH(t *testing.T) {
207
252
208
253
<- cmdDone
209
254
})
255
+
256
+ t .Run ("StdioExitOnStop" , func (t * testing.T ) {
257
+ t .Parallel ()
258
+ if runtime .GOOS == "windows" {
259
+ t .Skip ("Windows doesn't seem to clean up the process, maybe #7100 will fix it" )
260
+ }
261
+ client , workspace , agentToken := setupWorkspaceForAgent (t , nil )
262
+ _ , _ = tGoContext (t , func (ctx context.Context ) {
263
+ // Run this async so the SSH command has to wait for
264
+ // the build and agent to connect!
265
+ agentClient := agentsdk .New (client .URL )
266
+ agentClient .SetSessionToken (agentToken )
267
+ agentCloser := agent .New (agent.Options {
268
+ Client : agentClient ,
269
+ Logger : slogtest .Make (t , nil ).Named ("agent" ),
270
+ })
271
+ <- ctx .Done ()
272
+ _ = agentCloser .Close ()
273
+ })
274
+
275
+ clientOutput , clientInput := io .Pipe ()
276
+ serverOutput , serverInput := io .Pipe ()
277
+ defer func () {
278
+ for _ , c := range []io.Closer {clientOutput , clientInput , serverOutput , serverInput } {
279
+ _ = c .Close ()
280
+ }
281
+ }()
282
+
283
+ ctx , cancel := context .WithTimeout (context .Background (), testutil .WaitLong )
284
+ defer cancel ()
285
+
286
+ inv , root := clitest .New (t , "ssh" , "--stdio" , workspace .Name )
287
+ clitest .SetupConfig (t , client , root )
288
+ inv .Stdin = clientOutput
289
+ inv .Stdout = serverInput
290
+ inv .Stderr = io .Discard
291
+ cmdDone := tGo (t , func () {
292
+ err := inv .WithContext (ctx ).Run ()
293
+ assert .NoError (t , err )
294
+ })
295
+
296
+ conn , channels , requests , err := ssh .NewClientConn (& stdioConn {
297
+ Reader : serverOutput ,
298
+ Writer : clientInput ,
299
+ }, "" , & ssh.ClientConfig {
300
+ // #nosec
301
+ HostKeyCallback : ssh .InsecureIgnoreHostKey (),
302
+ })
303
+ require .NoError (t , err )
304
+ defer conn .Close ()
305
+
306
+ sshClient := ssh .NewClient (conn , channels , requests )
307
+ defer sshClient .Close ()
308
+
309
+ session , err := sshClient .NewSession ()
310
+ require .NoError (t , err )
311
+ defer session .Close ()
312
+
313
+ err = session .Shell ()
314
+ require .NoError (t , err )
315
+
316
+ workspace = coderdtest .MustTransitionWorkspace (t , client , workspace .ID , database .WorkspaceTransitionStart , database .WorkspaceTransitionStop )
317
+
318
+ select {
319
+ case <- cmdDone :
320
+ case <- ctx .Done ():
321
+ require .Fail (t , "command did not exit in time" )
322
+ }
323
+ })
324
+
210
325
t .Run ("ForwardAgent" , func (t * testing.T ) {
211
326
if runtime .GOOS == "windows" {
212
327
t .Skip ("Test not supported on windows" )
0 commit comments