MCPcopy Create free account
hub / github.com/coder/coder / Test_sessionStart_orphan

Function Test_sessionStart_orphan

agent/agentssh/agentssh_internal_test.go:33–93  ·  view source on GitHub ↗

Test_sessionStart_orphan tests running a command that takes a long time to exit normally, and terminate the SSH session context early to verify that we return quickly and don't leave the command running as an "orphan" with no active SSH session.

(t *testing.T)

Source from the content-addressed store, hash-verified

31// return quickly and don't leave the command running as an "orphan" with no
32// active SSH session.
33func Test_sessionStart_orphan(t *testing.T) {
34 t.Parallel()
35
36 ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitMedium)
37 defer cancel()
38 logger := testutil.Logger(t)
39 s, err := NewServer(ctx, logger, prometheus.NewRegistry(), afero.NewMemMapFs(), agentexec.DefaultExecer, nil)
40 require.NoError(t, err)
41 defer s.Close()
42 err = s.UpdateHostSigner(42)
43 assert.NoError(t, err)
44
45 // Here we're going to call the handler directly with a faked SSH session
46 // that just uses io.Pipes instead of a network socket. There is a large
47 // variation in the time between closing the socket from the client side and
48 // the SSH server canceling the session Context, which would lead to a flaky
49 // test if we did it that way. So instead, we directly cancel the context
50 // in this test.
51 sessionCtx, sessionCancel := context.WithCancel(ctx)
52 toClient, fromClient, sess := newTestSession(sessionCtx)
53 ptyInfo := gliderssh.Pty{}
54 windowSize := make(chan gliderssh.Window)
55 close(windowSize)
56 // the command gets the session context so that Go will terminate it when
57 // the session expires.
58 cmd := pty.CommandContext(sessionCtx, "sh", "-c", longScript)
59
60 done := make(chan struct{})
61 go func() {
62 defer close(done)
63
64 // we don't really care what the error is here. In the larger scenario,
65 // the client has disconnected, so we can't return any error information
66 // to them.
67 _ = s.startPTYSession(logger, sess, "ssh", cmd, ptyInfo, windowSize)
68 }()
69
70 readDone := make(chan struct{})
71 go func() {
72 defer close(readDone)
73 s := bufio.NewScanner(toClient)
74 assert.True(t, s.Scan())
75 txt := s.Text()
76 assert.Equal(t, "started", txt, "output corrupted")
77 }()
78
79 waitForChan(ctx, t, readDone, "read timeout")
80 // process is started, and should be sleeping for ~30 seconds
81
82 sessionCancel()
83
84 // now, we wait for the handler to complete. If it does so before the
85 // main test timeout, we consider this a pass. If not, it indicates
86 // that the server isn't properly shutting down sessions when they are
87 // disconnected client side, which could lead to processes hanging around
88 // indefinitely.
89 waitForChan(ctx, t, done, "handler timeout")
90

Callers

nothing calls this directly

Calls 11

LoggerFunction · 0.92
CommandContextFunction · 0.92
newTestSessionFunction · 0.85
waitForChanFunction · 0.85
UpdateHostSignerMethod · 0.80
startPTYSessionMethod · 0.80
NewServerFunction · 0.70
CloseMethod · 0.65
ScanMethod · 0.45
TextMethod · 0.45
EqualMethod · 0.45

Tested by

no test coverage detected