2 * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
9 package org.opendaylight.controller.netconf.nettyutil.handler.ssh.client;
11 import static org.junit.Assert.fail;
12 import static org.mockito.Matchers.any;
13 import static org.mockito.Matchers.anyBoolean;
14 import static org.mockito.Matchers.anyObject;
15 import static org.mockito.Matchers.anyString;
16 import static org.mockito.Mockito.doAnswer;
17 import static org.mockito.Mockito.doNothing;
18 import static org.mockito.Mockito.doReturn;
19 import static org.mockito.Mockito.doThrow;
20 import static org.mockito.Mockito.mock;
21 import static org.mockito.Mockito.times;
22 import static org.mockito.Mockito.verify;
23 import static org.mockito.Mockito.verifyNoMoreInteractions;
24 import static org.mockito.Mockito.verifyZeroInteractions;
26 import com.google.common.util.concurrent.FutureCallback;
27 import com.google.common.util.concurrent.Futures;
28 import com.google.common.util.concurrent.ListenableFuture;
29 import com.google.common.util.concurrent.SettableFuture;
30 import io.netty.buffer.ByteBuf;
31 import io.netty.buffer.Unpooled;
32 import io.netty.channel.Channel;
33 import io.netty.channel.ChannelHandlerContext;
34 import io.netty.channel.ChannelPromise;
35 import java.io.IOException;
36 import java.net.SocketAddress;
37 import org.apache.sshd.ClientChannel;
38 import org.apache.sshd.ClientSession;
39 import org.apache.sshd.SshClient;
40 import org.apache.sshd.client.channel.ChannelSubsystem;
41 import org.apache.sshd.client.future.AuthFuture;
42 import org.apache.sshd.client.future.ConnectFuture;
43 import org.apache.sshd.client.future.OpenFuture;
44 import org.apache.sshd.common.future.CloseFuture;
45 import org.apache.sshd.common.future.SshFuture;
46 import org.apache.sshd.common.future.SshFutureListener;
47 import org.apache.sshd.common.io.IoInputStream;
48 import org.apache.sshd.common.io.IoOutputStream;
49 import org.apache.sshd.common.io.IoReadFuture;
50 import org.apache.sshd.common.io.IoWriteFuture;
51 import org.apache.sshd.common.util.Buffer;
52 import org.junit.After;
53 import org.junit.Before;
54 import org.junit.Ignore;
55 import org.junit.Test;
56 import org.mockito.Matchers;
57 import org.mockito.Mock;
58 import org.mockito.MockitoAnnotations;
59 import org.mockito.invocation.InvocationOnMock;
60 import org.mockito.stubbing.Answer;
61 import org.opendaylight.controller.netconf.nettyutil.handler.ssh.authentication.AuthenticationHandler;
63 public class AsyncSshHandlerTest {
66 private SshClient sshClient;
68 private AuthenticationHandler authHandler;
70 private ChannelHandlerContext ctx;
72 private Channel channel;
74 private SocketAddress remoteAddress;
76 private SocketAddress localAddress;
78 private AsyncSshHandler asyncSshHandler;
80 private SshFutureListener<ConnectFuture> sshConnectListener;
81 private SshFutureListener<AuthFuture> sshAuthListener;
82 private SshFutureListener<OpenFuture> sshChannelOpenListener;
84 private ChannelPromise promise;
87 public void setUp() throws Exception {
88 MockitoAnnotations.initMocks(this);
95 promise = getMockedPromise();
97 asyncSshHandler = new AsyncSshHandler(authHandler, sshClient);
101 public void tearDown() throws Exception {
102 sshConnectListener = null;
103 sshAuthListener = null;
104 sshChannelOpenListener = null;
106 asyncSshHandler.close(ctx, getMockedPromise());
109 private void stubAuth() throws IOException {
110 doReturn("usr").when(authHandler).getUsername();
112 final AuthFuture authFuture = mock(AuthFuture.class);
113 Futures.addCallback(stubAddListener(authFuture), new SuccessFutureListener<AuthFuture>() {
115 public void onSuccess(final SshFutureListener<AuthFuture> result) {
116 sshAuthListener = result;
119 doReturn(authFuture).when(authHandler).authenticate(any(ClientSession.class));
122 @SuppressWarnings("unchecked")
123 private <T extends SshFuture<T>> ListenableFuture<SshFutureListener<T>> stubAddListener(final T future) {
124 final SettableFuture<SshFutureListener<T>> listenerSettableFuture = SettableFuture.create();
126 doAnswer(new Answer<Object>() {
128 public Object answer(final InvocationOnMock invocation) throws Throwable {
129 listenerSettableFuture.set((SshFutureListener<T>) invocation.getArguments()[0]);
132 }).when(future).addListener(any(SshFutureListener.class));
134 return listenerSettableFuture;
137 private void stubRemoteAddress() {
138 doReturn("remote").when(remoteAddress).toString();
141 private void stubCtx() {
142 doReturn(channel).when(ctx).channel();
143 doReturn(ctx).when(ctx).fireChannelActive();
144 doReturn(ctx).when(ctx).fireChannelInactive();
145 doReturn(ctx).when(ctx).fireChannelRead(anyObject());
146 doReturn(getMockedPromise()).when(ctx).newPromise();
149 private void stubChannel() {
150 doReturn("channel").when(channel).toString();
153 private void stubSshClient() {
154 doNothing().when(sshClient).start();
155 final ConnectFuture connectFuture = mock(ConnectFuture.class);
156 Futures.addCallback(stubAddListener(connectFuture), new SuccessFutureListener<ConnectFuture>() {
158 public void onSuccess(final SshFutureListener<ConnectFuture> result) {
159 sshConnectListener = result;
162 doReturn(connectFuture).when(sshClient).connect("usr", remoteAddress);
166 public void testConnectSuccess() throws Exception {
167 asyncSshHandler.connect(ctx, remoteAddress, localAddress, promise);
169 final IoInputStream asyncOut = getMockedIoInputStream();
170 final IoOutputStream asyncIn = getMockedIoOutputStream();
171 final ChannelSubsystem subsystemChannel = getMockedSubsystemChannel(asyncOut, asyncIn);
172 final ClientSession sshSession = getMockedSshSession(subsystemChannel);
173 final ConnectFuture connectFuture = getSuccessConnectFuture(sshSession);
175 sshConnectListener.operationComplete(connectFuture);
176 sshAuthListener.operationComplete(getSuccessAuthFuture());
177 sshChannelOpenListener.operationComplete(getSuccessOpenFuture());
179 verify(subsystemChannel).setStreaming(ClientChannel.Streaming.Async);
181 verify(promise).setSuccess();
182 verifyNoMoreInteractions(promise);
183 verify(ctx).fireChannelActive();
187 public void testRead() throws Exception {
188 asyncSshHandler.connect(ctx, remoteAddress, localAddress, promise);
190 final IoInputStream asyncOut = getMockedIoInputStream();
191 final IoOutputStream asyncIn = getMockedIoOutputStream();
192 final ChannelSubsystem subsystemChannel = getMockedSubsystemChannel(asyncOut, asyncIn);
193 final ClientSession sshSession = getMockedSshSession(subsystemChannel);
194 final ConnectFuture connectFuture = getSuccessConnectFuture(sshSession);
196 sshConnectListener.operationComplete(connectFuture);
197 sshAuthListener.operationComplete(getSuccessAuthFuture());
198 sshChannelOpenListener.operationComplete(getSuccessOpenFuture());
200 verify(ctx).fireChannelRead(any(ByteBuf.class));
204 public void testReadClosed() throws Exception {
205 asyncSshHandler.connect(ctx, remoteAddress, localAddress, promise);
207 final IoInputStream asyncOut = getMockedIoInputStream();
208 final IoReadFuture mockedReadFuture = asyncOut.read(null);
210 Futures.addCallback(stubAddListener(mockedReadFuture), new SuccessFutureListener<IoReadFuture>() {
212 public void onSuccess(final SshFutureListener<IoReadFuture> result) {
213 doReturn(new IllegalStateException()).when(mockedReadFuture).getException();
214 doReturn(mockedReadFuture).when(mockedReadFuture).removeListener(Matchers.<SshFutureListener<IoReadFuture>>any());
215 doReturn(true).when(asyncOut).isClosing();
216 doReturn(true).when(asyncOut).isClosed();
217 result.operationComplete(mockedReadFuture);
221 final IoOutputStream asyncIn = getMockedIoOutputStream();
222 final ChannelSubsystem subsystemChannel = getMockedSubsystemChannel(asyncOut, asyncIn);
223 final ClientSession sshSession = getMockedSshSession(subsystemChannel);
224 final ConnectFuture connectFuture = getSuccessConnectFuture(sshSession);
226 sshConnectListener.operationComplete(connectFuture);
227 sshAuthListener.operationComplete(getSuccessAuthFuture());
228 sshChannelOpenListener.operationComplete(getSuccessOpenFuture());
230 verify(ctx).fireChannelInactive();
234 public void testReadFail() throws Exception {
235 asyncSshHandler.connect(ctx, remoteAddress, localAddress, promise);
237 final IoInputStream asyncOut = getMockedIoInputStream();
238 final IoReadFuture mockedReadFuture = asyncOut.read(null);
240 Futures.addCallback(stubAddListener(mockedReadFuture), new SuccessFutureListener<IoReadFuture>() {
242 public void onSuccess(final SshFutureListener<IoReadFuture> result) {
243 doReturn(new IllegalStateException()).when(mockedReadFuture).getException();
244 doReturn(mockedReadFuture).when(mockedReadFuture).removeListener(Matchers.<SshFutureListener<IoReadFuture>>any());
245 result.operationComplete(mockedReadFuture);
249 final IoOutputStream asyncIn = getMockedIoOutputStream();
250 final ChannelSubsystem subsystemChannel = getMockedSubsystemChannel(asyncOut, asyncIn);
251 final ClientSession sshSession = getMockedSshSession(subsystemChannel);
252 final ConnectFuture connectFuture = getSuccessConnectFuture(sshSession);
254 sshConnectListener.operationComplete(connectFuture);
255 sshAuthListener.operationComplete(getSuccessAuthFuture());
256 sshChannelOpenListener.operationComplete(getSuccessOpenFuture());
258 verify(ctx).fireChannelInactive();
262 public void testWrite() throws Exception {
263 asyncSshHandler.connect(ctx, remoteAddress, localAddress, promise);
265 final IoInputStream asyncOut = getMockedIoInputStream();
266 final IoOutputStream asyncIn = getMockedIoOutputStream();
267 final ChannelSubsystem subsystemChannel = getMockedSubsystemChannel(asyncOut, asyncIn);
268 final ClientSession sshSession = getMockedSshSession(subsystemChannel);
269 final ConnectFuture connectFuture = getSuccessConnectFuture(sshSession);
271 sshConnectListener.operationComplete(connectFuture);
272 sshAuthListener.operationComplete(getSuccessAuthFuture());
273 sshChannelOpenListener.operationComplete(getSuccessOpenFuture());
275 final ChannelPromise writePromise = getMockedPromise();
276 asyncSshHandler.write(ctx, Unpooled.copiedBuffer(new byte[]{0, 1, 2, 3, 4, 5}), writePromise);
278 verify(writePromise).setSuccess();
282 public void testWriteClosed() throws Exception {
283 asyncSshHandler.connect(ctx, remoteAddress, localAddress, promise);
285 final IoInputStream asyncOut = getMockedIoInputStream();
286 final IoOutputStream asyncIn = getMockedIoOutputStream();
288 final IoWriteFuture ioWriteFuture = asyncIn.write(null);
290 Futures.addCallback(stubAddListener(ioWriteFuture), new SuccessFutureListener<IoWriteFuture>() {
292 public void onSuccess(final SshFutureListener<IoWriteFuture> result) {
293 doReturn(false).when(ioWriteFuture).isWritten();
294 doReturn(new IllegalStateException()).when(ioWriteFuture).getException();
295 doReturn(true).when(asyncIn).isClosing();
296 doReturn(true).when(asyncIn).isClosed();
297 result.operationComplete(ioWriteFuture);
301 final ChannelSubsystem subsystemChannel = getMockedSubsystemChannel(asyncOut, asyncIn);
302 final ClientSession sshSession = getMockedSshSession(subsystemChannel);
303 final ConnectFuture connectFuture = getSuccessConnectFuture(sshSession);
305 sshConnectListener.operationComplete(connectFuture);
306 sshAuthListener.operationComplete(getSuccessAuthFuture());
307 sshChannelOpenListener.operationComplete(getSuccessOpenFuture());
309 final ChannelPromise writePromise = getMockedPromise();
310 asyncSshHandler.write(ctx, Unpooled.copiedBuffer(new byte[]{0,1,2,3,4,5}), writePromise);
312 verify(writePromise).setFailure(any(Throwable.class));
316 public void testWritePendingOne() throws Exception {
317 asyncSshHandler.connect(ctx, remoteAddress, localAddress, promise);
319 final IoInputStream asyncOut = getMockedIoInputStream();
320 final IoOutputStream asyncIn = getMockedIoOutputStream();
321 final IoWriteFuture ioWriteFuture = asyncIn.write(null);
323 final ChannelSubsystem subsystemChannel = getMockedSubsystemChannel(asyncOut, asyncIn);
324 final ClientSession sshSession = getMockedSshSession(subsystemChannel);
325 final ConnectFuture connectFuture = getSuccessConnectFuture(sshSession);
327 sshConnectListener.operationComplete(connectFuture);
328 sshAuthListener.operationComplete(getSuccessAuthFuture());
329 sshChannelOpenListener.operationComplete(getSuccessOpenFuture());
331 final ChannelPromise firstWritePromise = getMockedPromise();
333 // intercept listener for first write, so we can invoke successful write later thus simulate pending of the first write
334 final ListenableFuture<SshFutureListener<IoWriteFuture>> firstWriteListenerFuture = stubAddListener(ioWriteFuture);
335 asyncSshHandler.write(ctx, Unpooled.copiedBuffer(new byte[]{0,1,2,3,4,5}), firstWritePromise);
336 final SshFutureListener<IoWriteFuture> firstWriteListener = firstWriteListenerFuture.get();
337 // intercept second listener, this is the listener for pending write for the pending write to know when pending state ended
338 final ListenableFuture<SshFutureListener<IoWriteFuture>> pendingListener = stubAddListener(ioWriteFuture);
340 final ChannelPromise secondWritePromise = getMockedPromise();
341 // now make write throw pending exception
342 doThrow(org.apache.sshd.common.io.WritePendingException.class).when(asyncIn).write(any(Buffer.class));
343 asyncSshHandler.write(ctx, Unpooled.copiedBuffer(new byte[]{0, 1, 2, 3, 4, 5}), secondWritePromise);
345 doReturn(ioWriteFuture).when(asyncIn).write(any(Buffer.class));
347 verifyZeroInteractions(firstWritePromise, secondWritePromise);
349 // make first write stop pending
350 firstWriteListener.operationComplete(ioWriteFuture);
352 // notify listener for second write that pending has ended
353 pendingListener.get().operationComplete(ioWriteFuture);
355 // verify both write promises successful
356 verify(firstWritePromise).setSuccess();
357 verify(secondWritePromise).setSuccess();
360 @Ignore("Pending queue is not limited")
362 public void testWritePendingMax() throws Exception {
363 asyncSshHandler.connect(ctx, remoteAddress, localAddress, promise);
365 final IoInputStream asyncOut = getMockedIoInputStream();
366 final IoOutputStream asyncIn = getMockedIoOutputStream();
367 final IoWriteFuture ioWriteFuture = asyncIn.write(null);
369 final ChannelSubsystem subsystemChannel = getMockedSubsystemChannel(asyncOut, asyncIn);
370 final ClientSession sshSession = getMockedSshSession(subsystemChannel);
371 final ConnectFuture connectFuture = getSuccessConnectFuture(sshSession);
373 sshConnectListener.operationComplete(connectFuture);
374 sshAuthListener.operationComplete(getSuccessAuthFuture());
375 sshChannelOpenListener.operationComplete(getSuccessOpenFuture());
377 final ChannelPromise firstWritePromise = getMockedPromise();
379 // intercept listener for first write, so we can invoke successful write later thus simulate pending of the first write
380 final ListenableFuture<SshFutureListener<IoWriteFuture>> firstWriteListenerFuture = stubAddListener(ioWriteFuture);
381 asyncSshHandler.write(ctx, Unpooled.copiedBuffer(new byte[]{0,1,2,3,4,5}), firstWritePromise);
383 final ChannelPromise secondWritePromise = getMockedPromise();
384 // now make write throw pending exception
385 doThrow(org.apache.sshd.common.io.WritePendingException.class).when(asyncIn).write(any(Buffer.class));
386 for (int i = 0; i < 1001; i++) {
387 asyncSshHandler.write(ctx, Unpooled.copiedBuffer(new byte[]{0, 1, 2, 3, 4, 5}), secondWritePromise);
390 verify(secondWritePromise, times(1)).setFailure(any(Throwable.class));
394 public void testDisconnect() throws Exception {
395 asyncSshHandler.connect(ctx, remoteAddress, localAddress, promise);
397 final IoInputStream asyncOut = getMockedIoInputStream();
398 final IoOutputStream asyncIn = getMockedIoOutputStream();
399 final ChannelSubsystem subsystemChannel = getMockedSubsystemChannel(asyncOut, asyncIn);
400 final ClientSession sshSession = getMockedSshSession(subsystemChannel);
401 final ConnectFuture connectFuture = getSuccessConnectFuture(sshSession);
403 sshConnectListener.operationComplete(connectFuture);
404 sshAuthListener.operationComplete(getSuccessAuthFuture());
405 sshChannelOpenListener.operationComplete(getSuccessOpenFuture());
407 final ChannelPromise disconnectPromise = getMockedPromise();
408 asyncSshHandler.disconnect(ctx, disconnectPromise);
410 verify(sshSession).close(anyBoolean());
411 verify(disconnectPromise).setSuccess();
412 verify(ctx).fireChannelInactive();
415 private OpenFuture getSuccessOpenFuture() {
416 final OpenFuture failedOpenFuture = mock(OpenFuture.class);
417 doReturn(true).when(failedOpenFuture).isOpened();
418 return failedOpenFuture;
421 private AuthFuture getSuccessAuthFuture() {
422 final AuthFuture authFuture = mock(AuthFuture.class);
423 doReturn(true).when(authFuture).isSuccess();
427 private ConnectFuture getSuccessConnectFuture(final ClientSession sshSession) {
428 final ConnectFuture connectFuture = mock(ConnectFuture.class);
429 doReturn(true).when(connectFuture).isConnected();
431 doReturn(sshSession).when(connectFuture).getSession();
432 return connectFuture;
435 private ClientSession getMockedSshSession(final ChannelSubsystem subsystemChannel) throws IOException {
436 final ClientSession sshSession = mock(ClientSession.class);
438 doReturn("sshSession").when(sshSession).toString();
439 doReturn("serverVersion").when(sshSession).getServerVersion();
440 doReturn(false).when(sshSession).isClosed();
441 doReturn(false).when(sshSession).isClosing();
442 final CloseFuture closeFuture = mock(CloseFuture.class);
443 Futures.addCallback(stubAddListener(closeFuture), new SuccessFutureListener<CloseFuture>() {
445 public void onSuccess(final SshFutureListener<CloseFuture> result) {
446 doReturn(true).when(closeFuture).isClosed();
447 result.operationComplete(closeFuture);
450 doReturn(closeFuture).when(sshSession).close(false);
452 doReturn(subsystemChannel).when(sshSession).createSubsystemChannel(anyString());
457 private ChannelSubsystem getMockedSubsystemChannel(final IoInputStream asyncOut, final IoOutputStream asyncIn) throws IOException {
458 final ChannelSubsystem subsystemChannel = mock(ChannelSubsystem.class);
459 doReturn("subsystemChannel").when(subsystemChannel).toString();
461 doNothing().when(subsystemChannel).setStreaming(any(ClientChannel.Streaming.class));
462 final OpenFuture openFuture = mock(OpenFuture.class);
464 Futures.addCallback(stubAddListener(openFuture), new SuccessFutureListener<OpenFuture>() {
466 public void onSuccess(final SshFutureListener<OpenFuture> result) {
467 sshChannelOpenListener = result;
471 doReturn(asyncOut).when(subsystemChannel).getAsyncOut();
473 doReturn(openFuture).when(subsystemChannel).open();
474 doReturn(asyncIn).when(subsystemChannel).getAsyncIn();
475 return subsystemChannel;
478 private IoOutputStream getMockedIoOutputStream() {
479 final IoOutputStream mock = mock(IoOutputStream.class);
480 final IoWriteFuture ioWriteFuture = mock(IoWriteFuture.class);
481 doReturn(ioWriteFuture).when(ioWriteFuture).addListener(Matchers.<SshFutureListener<IoWriteFuture>>any());
482 doReturn(true).when(ioWriteFuture).isWritten();
484 Futures.addCallback(stubAddListener(ioWriteFuture), new SuccessFutureListener<IoWriteFuture>() {
486 public void onSuccess(final SshFutureListener<IoWriteFuture> result) {
487 result.operationComplete(ioWriteFuture);
491 doReturn(ioWriteFuture).when(mock).write(any(Buffer.class));
492 doReturn(false).when(mock).isClosed();
493 doReturn(false).when(mock).isClosing();
497 private IoInputStream getMockedIoInputStream() {
498 final IoInputStream mock = mock(IoInputStream.class);
499 final IoReadFuture ioReadFuture = mock(IoReadFuture.class);
500 doReturn(null).when(ioReadFuture).getException();
501 doReturn(ioReadFuture).when(ioReadFuture).removeListener(Matchers.<SshFutureListener<IoReadFuture>>any());
502 doReturn(5).when(ioReadFuture).getRead();
503 doReturn(new Buffer(new byte[]{0, 1, 2, 3, 4})).when(ioReadFuture).getBuffer();
504 doReturn(ioReadFuture).when(ioReadFuture).addListener(Matchers.<SshFutureListener<IoReadFuture>>any());
506 // Always success for read
507 Futures.addCallback(stubAddListener(ioReadFuture), new SuccessFutureListener<IoReadFuture>() {
509 public void onSuccess(final SshFutureListener<IoReadFuture> result) {
510 result.operationComplete(ioReadFuture);
514 doReturn(ioReadFuture).when(mock).read(any(Buffer.class));
515 doReturn(false).when(mock).isClosed();
516 doReturn(false).when(mock).isClosing();
521 public void testConnectFailOpenChannel() throws Exception {
522 asyncSshHandler.connect(ctx, remoteAddress, localAddress, promise);
524 final IoInputStream asyncOut = getMockedIoInputStream();
525 final IoOutputStream asyncIn = getMockedIoOutputStream();
526 final ChannelSubsystem subsystemChannel = getMockedSubsystemChannel(asyncOut, asyncIn);
527 final ClientSession sshSession = getMockedSshSession(subsystemChannel);
528 final ConnectFuture connectFuture = getSuccessConnectFuture(sshSession);
530 sshConnectListener.operationComplete(connectFuture);
532 sshAuthListener.operationComplete(getSuccessAuthFuture());
534 verify(subsystemChannel).setStreaming(ClientChannel.Streaming.Async);
537 sshChannelOpenListener.operationComplete(getFailedOpenFuture());
538 fail("Exception expected");
539 } catch (final Exception e) {
540 verify(promise).setFailure(any(Throwable.class));
541 verifyNoMoreInteractions(promise);
542 // TODO should ctx.channelInactive be called if we throw exception ?
547 public void testConnectFailAuth() throws Exception {
548 asyncSshHandler.connect(ctx, remoteAddress, localAddress, promise);
550 final ClientSession sshSession = mock(ClientSession.class);
551 doReturn(true).when(sshSession).isClosed();
552 final ConnectFuture connectFuture = getSuccessConnectFuture(sshSession);
554 sshConnectListener.operationComplete(connectFuture);
556 final AuthFuture authFuture = getFailedAuthFuture();
559 sshAuthListener.operationComplete(authFuture);
560 fail("Exception expected");
561 } catch (final Exception e) {
562 verify(promise).setFailure(any(Throwable.class));
563 verifyNoMoreInteractions(promise);
564 // TODO should ctx.channelInactive be called ?
568 private AuthFuture getFailedAuthFuture() {
569 final AuthFuture authFuture = mock(AuthFuture.class);
570 doReturn(false).when(authFuture).isSuccess();
571 doReturn(new IllegalStateException()).when(authFuture).getException();
575 private OpenFuture getFailedOpenFuture() {
576 final OpenFuture authFuture = mock(OpenFuture.class);
577 doReturn(false).when(authFuture).isOpened();
578 doReturn(new IllegalStateException()).when(authFuture).getException();
583 public void testConnectFail() throws Exception {
584 asyncSshHandler.connect(ctx, remoteAddress, localAddress, promise);
586 final ConnectFuture connectFuture = getFailedConnectFuture();
588 sshConnectListener.operationComplete(connectFuture);
589 fail("Exception expected");
590 } catch (final Exception e) {
591 verify(promise).setFailure(any(Throwable.class));
592 verifyNoMoreInteractions(promise);
593 // TODO should ctx.channelInactive be called ?
597 private ConnectFuture getFailedConnectFuture() {
598 final ConnectFuture connectFuture = mock(ConnectFuture.class);
599 doReturn(false).when(connectFuture).isConnected();
600 doReturn(new IllegalStateException()).when(connectFuture).getException();
601 return connectFuture;
604 private ChannelPromise getMockedPromise() {
605 final ChannelPromise promise = mock(ChannelPromise.class);
606 doReturn(promise).when(promise).setSuccess();
607 doReturn(promise).when(promise).setFailure(any(Throwable.class));
611 private static abstract class SuccessFutureListener<T extends SshFuture<T>> implements FutureCallback<SshFutureListener<T>> {
614 public abstract void onSuccess(final SshFutureListener<T> result);
617 public void onFailure(final Throwable t) {
618 throw new RuntimeException(t);