@@ -100,16 +100,19 @@ func newMockLineServer(t *testing.T, signer ssh.Signer, pubKey string) string {
100100
101101 go func (in <- chan * ssh.Request ) {
102102 for req := range in {
103+ // since this channel's requests are serviced serially,
104+ // this will block keepalive probes, and can simulate a
105+ // hung connection.
106+ if bytes .Contains (req .Payload , []byte ("sleep" )) {
107+ time .Sleep (time .Second )
108+ }
109+
103110 if req .WantReply {
104111 req .Reply (true , nil )
105112 }
106113 }
107114 }(requests )
108115
109- go func (newChannel ssh.NewChannel ) {
110- conn .OpenChannel (newChannel .ChannelType (), nil )
111- }(newChannel )
112-
113116 defer channel .Close ()
114117 }
115118 conn .Close ()
@@ -182,6 +185,10 @@ func TestStart(t *testing.T) {
182185// TestKeepAlives verifies that the keepalive messages don't interfere with
183186// normal operation of the client.
184187func TestKeepAlives (t * testing.T ) {
188+ ivl := keepAliveInterval
189+ keepAliveInterval = 250 * time .Millisecond
190+ defer func () { keepAliveInterval = ivl }()
191+
185192 address := newMockLineServer (t , nil , testClientPublicKey )
186193 parts := strings .Split (address , ":" )
187194
@@ -193,7 +200,6 @@ func TestKeepAlives(t *testing.T) {
193200 "password" : "pass" ,
194201 "host" : parts [0 ],
195202 "port" : parts [1 ],
196- "timeout" : "30s" ,
197203 },
198204 },
199205 }
@@ -209,18 +215,64 @@ func TestKeepAlives(t *testing.T) {
209215
210216 var cmd remote.Cmd
211217 stdout := new (bytes.Buffer )
212- cmd .Command = "echo foo "
218+ cmd .Command = "sleep "
213219 cmd .Stdout = stdout
214220
215221 // wait a bit before executing the command, so that at least 1 keepalive is sent
216- time .Sleep (3 * time .Second )
222+ time .Sleep (500 * time .Millisecond )
217223
218224 err = c .Start (& cmd )
219225 if err != nil {
220226 t .Fatalf ("error executing remote command: %s" , err )
221227 }
222228}
223229
230+ // TestDeadConnection verifies that failed keepalive messages will eventually
231+ // kill the connection.
232+ func TestFailedKeepAlives (t * testing.T ) {
233+ ivl := keepAliveInterval
234+ del := maxKeepAliveDelay
235+ maxKeepAliveDelay = 500 * time .Millisecond
236+ keepAliveInterval = 250 * time .Millisecond
237+ defer func () {
238+ keepAliveInterval = ivl
239+ maxKeepAliveDelay = del
240+ }()
241+
242+ address := newMockLineServer (t , nil , testClientPublicKey )
243+ parts := strings .Split (address , ":" )
244+
245+ r := & terraform.InstanceState {
246+ Ephemeral : terraform.EphemeralState {
247+ ConnInfo : map [string ]string {
248+ "type" : "ssh" ,
249+ "user" : "user" ,
250+ "password" : "pass" ,
251+ "host" : parts [0 ],
252+ "port" : parts [1 ],
253+ },
254+ },
255+ }
256+
257+ c , err := New (r )
258+ if err != nil {
259+ t .Fatalf ("error creating communicator: %s" , err )
260+ }
261+
262+ if err := c .Connect (nil ); err != nil {
263+ t .Fatal (err )
264+ }
265+ var cmd remote.Cmd
266+ stdout := new (bytes.Buffer )
267+ cmd .Command = "sleep"
268+ cmd .Stdout = stdout
269+
270+ err = c .Start (& cmd )
271+ if err == nil {
272+ t .Fatal ("expected connection error" )
273+ }
274+ }
275+
224276func TestLostConnection (t * testing.T ) {
225277 address := newMockLineServer (t , nil , testClientPublicKey )
226278 parts := strings .Split (address , ":" )
0 commit comments