@Test
 public void testFailoverGood() throws Exception {
   AbstractClientConnectionFactory factory1 = mock(AbstractClientConnectionFactory.class);
   AbstractClientConnectionFactory factory2 = mock(AbstractClientConnectionFactory.class);
   List<AbstractClientConnectionFactory> factories =
       new ArrayList<AbstractClientConnectionFactory>();
   factories.add(factory1);
   factories.add(factory2);
   TcpConnectionSupport conn1 = makeMockConnection();
   TcpConnectionSupport conn2 = makeMockConnection();
   when(factory1.getConnection()).thenReturn(conn1);
   when(factory2.getConnection()).thenReturn(conn2);
   when(factory1.isActive()).thenReturn(true);
   when(factory2.isActive()).thenReturn(true);
   doThrow(new IOException("fail")).when(conn1).send(Mockito.any(Message.class));
   doAnswer(
           new Answer<Object>() {
             public Object answer(InvocationOnMock invocation) throws Throwable {
               return null;
             }
           })
       .when(conn2)
       .send(Mockito.any(Message.class));
   FailoverClientConnectionFactory failoverFactory =
       new FailoverClientConnectionFactory(factories);
   failoverFactory.start();
   GenericMessage<String> message = new GenericMessage<String>("foo");
   failoverFactory.getConnection().send(message);
   Mockito.verify(conn2).send(message);
 }
 @Test(expected = IOException.class)
 public void testFailoverConnectNone() throws Exception {
   AbstractClientConnectionFactory factory1 = mock(AbstractClientConnectionFactory.class);
   AbstractClientConnectionFactory factory2 = mock(AbstractClientConnectionFactory.class);
   List<AbstractClientConnectionFactory> factories =
       new ArrayList<AbstractClientConnectionFactory>();
   factories.add(factory1);
   factories.add(factory2);
   when(factory1.getConnection()).thenThrow(new IOException("fail"));
   when(factory2.getConnection()).thenThrow(new IOException("fail"));
   when(factory1.isActive()).thenReturn(true);
   when(factory2.isActive()).thenReturn(true);
   FailoverClientConnectionFactory failoverFactory =
       new FailoverClientConnectionFactory(factories);
   failoverFactory.start();
   GenericMessage<String> message = new GenericMessage<String>("foo");
   failoverFactory.getConnection().send(message);
 }
 @Test
 public void testOkAgainAfterCompleteFailure() throws Exception {
   AbstractClientConnectionFactory factory1 = mock(AbstractClientConnectionFactory.class);
   AbstractClientConnectionFactory factory2 = mock(AbstractClientConnectionFactory.class);
   List<AbstractClientConnectionFactory> factories =
       new ArrayList<AbstractClientConnectionFactory>();
   factories.add(factory1);
   factories.add(factory2);
   TcpConnectionSupport conn1 = makeMockConnection();
   TcpConnectionSupport conn2 = makeMockConnection();
   when(factory1.getConnection()).thenReturn(conn1);
   when(factory2.getConnection()).thenReturn(conn2);
   when(factory1.isActive()).thenReturn(true);
   when(factory2.isActive()).thenReturn(true);
   final AtomicInteger failCount = new AtomicInteger();
   doAnswer(
           new Answer<Object>() {
             @Override
             public Object answer(InvocationOnMock invocation) throws Throwable {
               if (failCount.incrementAndGet() < 3) {
                 throw new IOException("fail");
               }
               return null;
             }
           })
       .when(conn1)
       .send(Mockito.any(Message.class));
   doThrow(new IOException("fail")).when(conn2).send(Mockito.any(Message.class));
   FailoverClientConnectionFactory failoverFactory =
       new FailoverClientConnectionFactory(factories);
   failoverFactory.start();
   GenericMessage<String> message = new GenericMessage<String>("foo");
   try {
     failoverFactory.getConnection().send(message);
     fail("ExpectedFailure");
   } catch (IOException e) {
   }
   failoverFactory.getConnection().send(message);
   Mockito.verify(conn2).send(message);
   Mockito.verify(conn1, times(3)).send(message);
 }
 @Test(expected = IOException.class)
 public void testFailoverAllDead() throws Exception {
   AbstractClientConnectionFactory factory1 = mock(AbstractClientConnectionFactory.class);
   AbstractClientConnectionFactory factory2 = mock(AbstractClientConnectionFactory.class);
   List<AbstractClientConnectionFactory> factories =
       new ArrayList<AbstractClientConnectionFactory>();
   factories.add(factory1);
   factories.add(factory2);
   TcpConnectionSupport conn1 = makeMockConnection();
   TcpConnectionSupport conn2 = makeMockConnection();
   when(factory1.getConnection()).thenReturn(conn1);
   when(factory2.getConnection()).thenReturn(conn2);
   when(factory1.isActive()).thenReturn(true);
   when(factory2.isActive()).thenReturn(true);
   doThrow(new IOException("fail")).when(conn1).send(Mockito.any(Message.class));
   doThrow(new IOException("fail")).when(conn2).send(Mockito.any(Message.class));
   FailoverClientConnectionFactory failoverFactory =
       new FailoverClientConnectionFactory(factories);
   failoverFactory.start();
   GenericMessage<String> message = new GenericMessage<String>("foo");
   failoverFactory.getConnection().send(message);
   Mockito.verify(conn2).send(message);
 }
 @Test
 public void testFailoverAllDeadButOriginalOkAgain() throws Exception {
   AbstractClientConnectionFactory factory1 = mock(AbstractClientConnectionFactory.class);
   AbstractClientConnectionFactory factory2 = mock(AbstractClientConnectionFactory.class);
   List<AbstractClientConnectionFactory> factories =
       new ArrayList<AbstractClientConnectionFactory>();
   factories.add(factory1);
   factories.add(factory2);
   TcpConnectionSupport conn1 = makeMockConnection();
   TcpConnectionSupport conn2 = makeMockConnection();
   when(factory1.getConnection()).thenReturn(conn1);
   when(factory2.getConnection()).thenReturn(conn2);
   when(factory1.isActive()).thenReturn(true);
   when(factory2.isActive()).thenReturn(true);
   final AtomicBoolean failedOnce = new AtomicBoolean();
   doAnswer(
           new Answer<Object>() {
             @Override
             public Object answer(InvocationOnMock invocation) throws Throwable {
               if (!failedOnce.get()) {
                 failedOnce.set(true);
                 throw new IOException("fail");
               }
               return null;
             }
           })
       .when(conn1)
       .send(Mockito.any(Message.class));
   doThrow(new IOException("fail")).when(conn2).send(Mockito.any(Message.class));
   FailoverClientConnectionFactory failoverFactory =
       new FailoverClientConnectionFactory(factories);
   failoverFactory.start();
   GenericMessage<String> message = new GenericMessage<String>("foo");
   failoverFactory.getConnection().send(message);
   Mockito.verify(conn2).send(message);
   Mockito.verify(conn1, times(2)).send(message);
 }
  private void testRealGuts(
      AbstractClientConnectionFactory client1,
      AbstractClientConnectionFactory client2,
      AbstractServerConnectionFactory server1,
      AbstractServerConnectionFactory server2)
      throws Exception {
    int port1;
    int port2;
    Executor exec = Executors.newCachedThreadPool();
    client1.setTaskExecutor(exec);
    client2.setTaskExecutor(exec);
    server1.setTaskExecutor(exec);
    server2.setTaskExecutor(exec);
    ApplicationEventPublisher pub =
        new ApplicationEventPublisher() {

          @Override
          public void publishEvent(ApplicationEvent event) {}
        };
    client1.setApplicationEventPublisher(pub);
    client2.setApplicationEventPublisher(pub);
    server1.setApplicationEventPublisher(pub);
    server2.setApplicationEventPublisher(pub);
    TcpInboundGateway gateway1 = new TcpInboundGateway();
    gateway1.setConnectionFactory(server1);
    SubscribableChannel channel = new DirectChannel();
    final AtomicReference<String> connectionId = new AtomicReference<String>();
    channel.subscribe(
        new MessageHandler() {
          public void handleMessage(Message<?> message) throws MessagingException {
            connectionId.set((String) message.getHeaders().get(IpHeaders.CONNECTION_ID));
            ((MessageChannel) message.getHeaders().getReplyChannel()).send(message);
          }
        });
    gateway1.setRequestChannel(channel);
    gateway1.start();
    TcpInboundGateway gateway2 = new TcpInboundGateway();
    gateway2.setConnectionFactory(server2);
    gateway2.setRequestChannel(channel);
    gateway2.start();
    TestingUtilities.waitListening(server1, null);
    TestingUtilities.waitListening(server2, null);
    List<AbstractClientConnectionFactory> factories =
        new ArrayList<AbstractClientConnectionFactory>();
    factories.add(client1);
    factories.add(client2);
    FailoverClientConnectionFactory failFactory = new FailoverClientConnectionFactory(factories);
    boolean singleUse = client1.isSingleUse();
    failFactory.setSingleUse(singleUse);
    failFactory.afterPropertiesSet();
    TcpOutboundGateway outGateway = new TcpOutboundGateway();
    outGateway.setConnectionFactory(failFactory);
    outGateway.start();
    QueueChannel replyChannel = new QueueChannel();
    outGateway.setReplyChannel(replyChannel);
    Message<String> message = new GenericMessage<String>("foo");
    outGateway.setRemoteTimeout(120000);
    outGateway.handleMessage(message);
    Socket socket = getSocket(client1);
    port1 = socket.getLocalPort();
    assertTrue(singleUse | connectionId.get().contains(Integer.toString(port1)));
    Message<?> replyMessage = replyChannel.receive(10000);
    assertNotNull(replyMessage);
    server1.stop();
    TestingUtilities.waitUntilFactoryHasThisNumberOfConnections(client1, 0);
    outGateway.handleMessage(message);
    socket = getSocket(client2);
    port2 = socket.getLocalPort();
    assertTrue(singleUse | connectionId.get().contains(Integer.toString(port2)));
    replyMessage = replyChannel.receive(10000);
    assertNotNull(replyMessage);
    gateway2.stop();
    outGateway.stop();
  }