/* * Copyright 2014, The Sporting Exchange Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.betfair.cougar.client.socket; import com.betfair.cougar.client.socket.resolver.NetworkAddressResolver; import com.betfair.cougar.netutil.nio.message.ProtocolMessage; import org.apache.mina.common.IoSession; import org.junit.Before; import org.junit.Test; import java.lang.reflect.Field; import java.net.InetSocketAddress; import java.net.SocketAddress; import java.util.*; import static java.util.Arrays.asList; import static org.mockito.Matchers.any; import static org.mockito.Mockito.*; /** * */ public class SessionRecyclerTest { public static final String HOST1 = "HOST1"; public static final String HOST2 = "HOST2"; public static final String HOST3 = "HOST3"; public static final String HOST1_IP1 = "1.1.1.1"; public static final String HOST1_IP2 = "1.1.1.2"; public static final String HOST1_IP3 = "1.1.1.3"; public static final String HOST2_IP1 = "2.2.2.1"; public static final String HOST2_IP2 = "2.2.2.2"; public static final String HOST2_IP3 = "2.2.2.3"; public static final String HOST3_IP1 = "3.3.3.1"; public static final String HOST3_IP2 = "3.3.3.2"; public static final String HOST3_IP3 = "3.3.3.3"; private IoSessionFactory sessionFactory; private SessionRecycler recycler; private String hosts; @Before public void setup() throws Exception { sessionFactory = mock(IoSessionFactory.class); Field sessionsField = IoSessionFactory.class.getDeclaredField("sessions"); sessionsField.setAccessible(true); Map<SocketAddress, IoSession> sessions = new HashMap<SocketAddress, IoSession>(); final IoSession session1 = getSession(1); final IoSession session2 = getSession(2); final IoSession session3 = getSession(3); sessions.put(session1.getRemoteAddress(), session1); sessions.put(session2.getRemoteAddress(), session2); sessions.put(session3.getRemoteAddress(), session3); sessionsField.set(sessionFactory, sessions); when(sessionFactory.getSession()).thenCallRealMethod(); when(sessionFactory.isAvailable(any(IoSession.class))).thenCallRealMethod(); Field lockField = IoSessionFactory.class.getDeclaredField("lock"); lockField.setAccessible(true); lockField.set(sessionFactory, new Object()); NetworkAddressResolver resolver = mock(NetworkAddressResolver.class); when(resolver.resolve(HOST1)).thenReturn(asSet(HOST1_IP1, HOST1_IP2)); when(resolver.resolve(HOST2)).thenReturn(asSet(HOST2_IP1, HOST2_IP2)); when(resolver.resolve(HOST3)).thenReturn(asSet(HOST3_IP1, HOST3_IP2)); hosts = "HOST1:9003,HOST2:9003,HOST3:9003"; recycler = new SessionRecycler(sessionFactory, resolver, hosts, 5000); } @Test public void testSessionsAreEstablishedToAllResolvedEndpoints() { recycler.run(); verify(sessionFactory, times(6)).openSession(any(InetSocketAddress.class)); verify(sessionFactory).openSession(new InetSocketAddress(HOST1_IP1, 9003)); verify(sessionFactory).openSession(new InetSocketAddress(HOST2_IP1, 9003)); verify(sessionFactory).openSession(new InetSocketAddress(HOST3_IP1, 9003)); verify(sessionFactory).openSession(new InetSocketAddress(HOST1_IP2, 9003)); verify(sessionFactory).openSession(new InetSocketAddress(HOST2_IP2, 9003)); verify(sessionFactory).openSession(new InetSocketAddress(HOST3_IP2, 9003)); } @Test public void testSessionsAreRecycledWhenEndpointsChange() throws Exception { final InetSocketAddress host11 = new InetSocketAddress(HOST1_IP1, 9003); final InetSocketAddress host21 = new InetSocketAddress(HOST2_IP1, 9003); final InetSocketAddress host31 = new InetSocketAddress(HOST3_IP1, 9003); final InetSocketAddress host12 = new InetSocketAddress(HOST1_IP2, 9003); final InetSocketAddress host22 = new InetSocketAddress(HOST2_IP2, 9003); final InetSocketAddress host32 = new InetSocketAddress(HOST3_IP2, 9003); final InetSocketAddress host13 = new InetSocketAddress(HOST1_IP3, 9003); final InetSocketAddress host23 = new InetSocketAddress(HOST2_IP3, 9003); final InetSocketAddress host33 = new InetSocketAddress(HOST3_IP3, 9003); NetworkAddressResolver resolver = mock(NetworkAddressResolver.class); when(resolver.resolve(HOST1)).thenReturn(asSet(HOST1_IP1, HOST1_IP2)).thenReturn(asSet(HOST1_IP1, HOST1_IP2, HOST1_IP3)); when(resolver.resolve(HOST2)).thenReturn(asSet(HOST2_IP1, HOST2_IP2)).thenReturn(asSet(HOST2_IP3)); when(resolver.resolve(HOST3)).thenReturn(asSet(HOST3_IP1, HOST3_IP2)).thenReturn(asSet(HOST3_IP3, HOST3_IP2, HOST3_IP1)); final SessionRecycler recycler = new SessionRecycler(sessionFactory, resolver, hosts, 5000); // spin recycler.run(); // verify new sessions opened verify(sessionFactory, times(6)).openSession(any(InetSocketAddress.class)); verify(sessionFactory).openSession(host11); verify(sessionFactory).openSession(host21); verify(sessionFactory).openSession(host31); verify(sessionFactory).openSession(host12); verify(sessionFactory).openSession(host22); verify(sessionFactory).openSession(host32); Set<SocketAddress> sessionAddresses = new HashSet<SocketAddress>(asList(host11, host21, host31, host12, host22, host32)); when(sessionFactory.getCurrentSessionAddresses()).thenReturn(sessionAddresses); // spin recycler.run(); // verify new sessions opened verify(sessionFactory, times(9)).openSession(any(InetSocketAddress.class)); verify(sessionFactory).openSession(host13); verify(sessionFactory).openSession(host23); verify(sessionFactory).openSession(host33); // verify sessions closed verify(sessionFactory, times(2)).closeSession(any(SocketAddress.class), eq(false)); verify(sessionFactory).closeSession(host21, false); verify(sessionFactory).closeSession(host22, false); } @Test public void testSessionsAreNotRecycledWhenEndpointsDoNotChange() throws Exception { final InetSocketAddress host11 = new InetSocketAddress(HOST1_IP1, 9003); final InetSocketAddress host21 = new InetSocketAddress(HOST2_IP1, 9003); final InetSocketAddress host31 = new InetSocketAddress(HOST3_IP1, 9003); final InetSocketAddress host12 = new InetSocketAddress(HOST1_IP2, 9003); final InetSocketAddress host22 = new InetSocketAddress(HOST2_IP2, 9003); final InetSocketAddress host32 = new InetSocketAddress(HOST3_IP2, 9003); NetworkAddressResolver resolver = mock(NetworkAddressResolver.class); when(resolver.resolve(HOST1)).thenReturn(asSet(HOST1_IP1, HOST1_IP2)); when(resolver.resolve(HOST2)).thenReturn(asSet(HOST2_IP1, HOST2_IP2)); when(resolver.resolve(HOST3)).thenReturn(asSet(HOST3_IP1, HOST3_IP2)); final SessionRecycler recycler = new SessionRecycler(sessionFactory, resolver, hosts, 5000); // spin recycler.run(); // verify new sessions opened verify(sessionFactory, times(6)).openSession(any(InetSocketAddress.class)); verify(sessionFactory).openSession(host11); verify(sessionFactory).openSession(host21); verify(sessionFactory).openSession(host31); verify(sessionFactory).openSession(host12); verify(sessionFactory).openSession(host22); verify(sessionFactory).openSession(host32); final Set<SocketAddress> sessions = new HashSet(asList(host11, host21, host31, host12, host22, host32)); when(sessionFactory.getCurrentSessionAddresses()).thenReturn(sessions); // spin recycler.run(); // verify no new sessions opened verify(sessionFactory, times(6)).openSession(any(InetSocketAddress.class)); // verify no sessions closed verify(sessionFactory, never()).closeSession(any(SocketAddress.class), eq(false)); } @Test public void testPortNumberResolution() throws Exception { final InetSocketAddress host11 = new InetSocketAddress(HOST1_IP1, 9003); final InetSocketAddress host12 = new InetSocketAddress(HOST1_IP2, 9003); final InetSocketAddress host21 = new InetSocketAddress(HOST2_IP1, 9004); final InetSocketAddress host22 = new InetSocketAddress(HOST2_IP2, 9004); final InetSocketAddress host31 = new InetSocketAddress(HOST3_IP1, 9005); final InetSocketAddress host32 = new InetSocketAddress(HOST3_IP2, 9005); NetworkAddressResolver resolver = mock(NetworkAddressResolver.class); when(resolver.resolve(HOST1)).thenReturn(asSet(HOST1_IP1, HOST1_IP2)); when(resolver.resolve(HOST2)).thenReturn(asSet(HOST2_IP1, HOST2_IP2)); when(resolver.resolve(HOST3)).thenReturn(asSet(HOST3_IP1 + ":9005", HOST3_IP2 + ":9005")); String hostsString = "HOST1,HOST2:9004,HOST3:9001"; final SessionRecycler recycler = new SessionRecycler(sessionFactory, resolver, hostsString, 5000); // spin recycler.run(); // verify new sessions opened verify(sessionFactory, times(6)).openSession(any(InetSocketAddress.class)); verify(sessionFactory).openSession(host11); verify(sessionFactory).openSession(host21); verify(sessionFactory).openSession(host31); verify(sessionFactory).openSession(host12); verify(sessionFactory).openSession(host22); verify(sessionFactory).openSession(host32); } private Set<String> asSet(String... values) { if (values == null || values.length == 0) { return Collections.emptySet(); } Set<String> result = new HashSet(values.length); for (String value : values) { result.add(value); } return result; } private IoSession getSession(InetSocketAddress address) { IoSession ioSession = getSession(1); when(ioSession.getRemoteAddress()).thenReturn(address); return ioSession; } private IoSession getSession(int id) { final IoSession ioSession = mock(IoSession.class); when(ioSession.isConnected()).thenReturn(true); when(ioSession.isClosing()).thenReturn(false); when(ioSession.containsAttribute(ProtocolMessage.ProtocolMessageType.SUSPEND.name())).thenReturn(false); when(ioSession.containsAttribute(ProtocolMessage.ProtocolMessageType.DISCONNECT.name())).thenReturn(false); return ioSession; } }