@Test public void multiple_connected_same_ip() throws Exception { final InetSocketAddress remoteAddress = new InetSocketAddress("10.0.0.0", 43); when(channel.getRemoteAddress()).thenReturn(remoteAddress); final ChannelEvent openEvent = new UpstreamChannelStateEvent(channel, ChannelState.OPEN, Boolean.TRUE); subject.handleUpstream(ctx, openEvent); subject.handleUpstream(ctx, openEvent); subject.handleUpstream(ctx, openEvent); verify(ctx, times(2)).sendUpstream(openEvent); verify(channel, times(1)).write(argThat(new ArgumentMatcher<Object>() { @Override public boolean matches(Object argument) { return QueryMessages.connectionsExceeded(MAX_CONNECTIONS_PER_IP).equals(argument); } })); verify(channelFuture, times(1)).addListener(ChannelFutureListener.CLOSE); verify(whoisLog).logQueryResult(anyString(), eq(0), eq(0), eq(QueryCompletionInfo.REJECTED), eq(0L), (InetAddress) Mockito.anyObject(), Mockito.anyInt(), eq("")); verify(ctx, times(2)).sendUpstream(openEvent); }
@Test public void multiple_connected_limit_disabled() throws Exception { subject.setMaxConnectionsPerIp(0); final InetSocketAddress remoteAddress = new InetSocketAddress("10.0.0.0", 43); when(channel.getRemoteAddress()).thenReturn(remoteAddress); final ChannelEvent openEvent = new UpstreamChannelStateEvent(channel, ChannelState.OPEN, Boolean.TRUE); subject.handleUpstream(ctx, openEvent); subject.handleUpstream(ctx, openEvent); subject.handleUpstream(ctx, openEvent); final ChannelEvent closeEvent = new UpstreamChannelStateEvent(channel, ChannelState.OPEN, Boolean.FALSE); subject.handleUpstream(ctx, closeEvent); subject.handleUpstream(ctx, closeEvent); subject.handleUpstream(ctx, closeEvent); verify(ctx, times(3)).sendUpstream(openEvent); verify(ctx, times(3)).sendUpstream(closeEvent); verify(channel, never()).close(); verify(channel, never()).write(anyObject()); verify(channelFuture, never()).addListener(ChannelFutureListener.CLOSE); }
@Test public void multiple_connected_unlimited_allowed() throws Exception { final InetSocketAddress remoteAddress = new InetSocketAddress("10.0.0.0", 43); when(ipResourceConfiguration.isUnlimitedConnections(any(IpInterval.class))).thenReturn(true); when(channel.getRemoteAddress()).thenReturn(remoteAddress); final ChannelEvent event = new UpstreamChannelStateEvent(channel, ChannelState.OPEN, Boolean.TRUE); subject.handleUpstream(ctx, event); subject.handleUpstream(ctx, event); subject.handleUpstream(ctx, event); verify(ctx, times(3)).sendUpstream(event); verify(channel, never()).close(); verify(channel, never()).write(anyObject()); verify(channelFuture, never()).addListener(ChannelFutureListener.CLOSE); }
@Test public void multiple_connected_proxy_allowed() throws Exception { final InetSocketAddress remoteAddress = new InetSocketAddress("10.0.0.0", 43); when(ipResourceConfiguration.isProxy(any(IpInterval.class))).thenReturn(true); when(channel.getRemoteAddress()).thenReturn(remoteAddress); final ChannelEvent event = new UpstreamChannelStateEvent(channel, ChannelState.OPEN, Boolean.TRUE); subject.handleUpstream(ctx, event); subject.handleUpstream(ctx, event); subject.handleUpstream(ctx, event); verify(ctx, times(3)).sendUpstream(event); verify(channel, never()).close(); verify(channel, never()).write(anyObject()); verify(channelFuture, never()).addListener(ChannelFutureListener.CLOSE); }
@Test public void multiple_connected_different_ip() throws Exception { final InetSocketAddress remoteAddress = new InetSocketAddress("10.0.0.0", 43); final InetSocketAddress remoteAddress2 = new InetSocketAddress("10.0.0.1", 43); when(channel.getRemoteAddress()).thenReturn(remoteAddress).thenReturn(remoteAddress).thenReturn(remoteAddress2); final ChannelEvent event = new UpstreamChannelStateEvent(channel, ChannelState.OPEN, Boolean.TRUE); subject.handleUpstream(ctx, event); subject.handleUpstream(ctx, event); final ChannelEvent event2 = new UpstreamChannelStateEvent(channel, ChannelState.OPEN, Boolean.TRUE); subject.handleUpstream(ctx, event2); verify(ctx, times(2)).sendUpstream(event); verify(ctx, times(1)).sendUpstream(event2); verify(channel, never()).close(); verify(channel, never()).write(anyObject()); verify(channelFuture, never()).addListener(ChannelFutureListener.CLOSE); }
@Test public void multiple_connected_same_ip_and_closed() throws Exception { final InetSocketAddress remoteAddress = new InetSocketAddress("10.0.0.0", 43); when(channel.getRemoteAddress()).thenReturn(remoteAddress); final ChannelEvent openEvent = new UpstreamChannelStateEvent(channel, ChannelState.OPEN, Boolean.TRUE); subject.handleUpstream(ctx, openEvent); subject.handleUpstream(ctx, openEvent); final ChannelEvent closeEvent = new UpstreamChannelStateEvent(channel, ChannelState.OPEN, Boolean.FALSE); subject.handleUpstream(ctx, closeEvent); subject.handleUpstream(ctx, closeEvent); subject.handleUpstream(ctx, openEvent); subject.handleUpstream(ctx, openEvent); verify(ctx, times(4)).sendUpstream(openEvent); verify(ctx, times(2)).sendUpstream(closeEvent); verify(channel, never()).close(); verify(channel, never()).write(anyObject()); verify(channelFuture, never()).addListener(ChannelFutureListener.CLOSE); }
@Test public void shouldThrowExceptionIfBadHandshakeIsReceived() throws Exception { final InetSocketAddress remoteAddress = new InetSocketAddress(0); // start off by simulating a 'channelConnected' event // this should set the internal state properly handler.channelConnected(ctx, new UpstreamChannelStateEvent(channel, ChannelState.CONNECTED, remoteAddress)); // we shouldn't forward the event on Mockito.verifyNoMoreInteractions(ctx); // now simulate an incoming message // the handler is expecting a handshake message // but we're going to feed it something else, and we expect an exception as a result ChannelBuffer badHandshakeBuffer = ChannelBuffers.wrappedBuffer(new byte[]{0, 1, 3, 4}); expectedException.expect(IOException.class); handler.messageReceived(ctx, new UpstreamMessageEvent(channel, badHandshakeBuffer, remoteAddress)); }
@Test public void one_connected() throws Exception { final InetSocketAddress remoteAddress = new InetSocketAddress("10.0.0.0", 43); when(channel.getRemoteAddress()).thenReturn(remoteAddress); final ChannelEvent event = new UpstreamChannelStateEvent(channel, ChannelState.OPEN, Boolean.TRUE); subject.handleUpstream(ctx, event); subject.handleUpstream(ctx, event); verify(ctx, times(2)).sendUpstream(event); verify(channel, never()).close(); verify(channel, never()).write(anyObject()); verify(channelFuture, never()).addListener(ChannelFutureListener.CLOSE); }
@Test public void shouldThrowExceptionIfMultipleChannelConnectedEventsAreReceived() throws Exception { // first channel connected event handler.channelConnected(ctx, new UpstreamChannelStateEvent(channel, ChannelState.CONNECTED, new InetSocketAddress(0))); // second channel connected event expectedException.expect(IllegalStateException.class); handler.channelConnected(ctx, new UpstreamChannelStateEvent(channel, ChannelState.CONNECTED, new InetSocketAddress(0))); }
@Test public void shouldNotForwardChannelConnectedEventUntilHandshakeMessageReceived() throws Exception { // simulate a channelConnected event handler.channelConnected(ctx, new UpstreamChannelStateEvent(channel, ChannelState.CONNECTED, new InetSocketAddress(0))); // verify that no event is forwarded on (if an event is forwarded, it _must_ use the ctx object) Mockito.verifyNoMoreInteractions(ctx); }
@Test public void shouldDropConnectedEvent() { UpstreamChannelStateEvent event = spy(new UpstreamChannelStateEvent(channel, ChannelState.CONNECTED, InetSocketAddress.createUnresolved("remote-host", 8888))); handler.channelConnected(ctx, event); verifyNoMoreInteractions(ctx, event); }
@Test public void shouldDropChannelClosedEvent() { UpstreamChannelStateEvent event = spy(new UpstreamChannelStateEvent(channel, ChannelState.CONNECTED, null)); handler.channelConnected(ctx, event); verifyNoMoreInteractions(ctx, event); }
@SuppressWarnings("ThrowableResultOfMethodCallIgnored") @Test public void shouldFailOriginalConnectFutureAndCloseChannelIfHandshakeWriteFutureFails() throws Exception { ChannelFuture originalConnectFuture = Channels.future(channel); // pretend that a connectRequested event was sent over this channel handler.setConnectFutureForUnitTestOnly(originalConnectFuture); // signal that the connect succeeded handler.channelConnected(ctx, new UpstreamChannelStateEvent(channel, ChannelState.CONNECTED, new InetSocketAddress(0))); // instead of passing events upstream, the handler should // attempt to write an handshake out and send nothing upstream ArgumentCaptor<DownstreamMessageEvent> downstreamEvent = ArgumentCaptor.forClass(DownstreamMessageEvent.class); verify(ctx, atLeastOnce()).getChannel(); verify(ctx).sendDownstream(downstreamEvent.capture()); verifyNoMoreInteractions(ctx); // fail the write DownstreamMessageEvent handshakeEvent = downstreamEvent.getValue(); IOException cause = new IOException(); handshakeEvent.getFuture().setFailure(cause); // verify that the original future failed as well assertThat(originalConnectFuture.isDone(), equalTo(true)); assertThat(originalConnectFuture.isSuccess(), equalTo(false)); assertThat((IOException) originalConnectFuture.getCause(), is(cause)); // and that the channel was closed verify(channel).close(); }
private void checkIsUpstreamChannelStateEvent(ChannelEvent ev, Channel expectedChannel, ChannelState expectedState, Object expectedValue) { assertTrue(ev instanceof UpstreamChannelStateEvent); UpstreamChannelStateEvent checkedEv = (UpstreamChannelStateEvent) ev; assertSame(expectedChannel, checkedEv.getChannel()); assertEquals(expectedState, checkedEv.getState()); assertEquals(expectedValue, checkedEv.getValue()); }
@Test public void shouldProperlyHandleIncomingHandshakeMessage() throws Exception { // the following actions should be performed for a incoming handshake // 1. set attachment to "S_01" // 2. remove self from pipeline // 3. forward channelConnected event on when(ctx.getChannel()).thenReturn(channel); when(ctx.getPipeline()).thenReturn(pipeline); // go through the full handshake flow: // address we expect in the channelConnected event final InetSocketAddress remoteAddress = new InetSocketAddress(0); // start off by simulating the original incoming 'channelConnected' event // this should set the internal state properly handler.channelConnected(ctx, new UpstreamChannelStateEvent(channel, ChannelState.CONNECTED, remoteAddress)); // we shouldn't forward the event on Mockito.verifyNoMoreInteractions(ctx); // now simulate the incoming handshake message ChannelBuffer handshakeBuffer = Handshakers.createHandshakeMessage(S_01, mapper); handler.messageReceived(ctx, new UpstreamMessageEvent(channel, handshakeBuffer, remoteAddress)); // captor for the event that's sent in response to this handshake ArgumentCaptor<ChannelEvent> upstreamEventCaptor = ArgumentCaptor.forClass(ChannelEvent.class); // verify the actions InOrder inOrder = Mockito.inOrder(channel, pipeline, ctx); inOrder.verify(ctx).getChannel(); inOrder.verify(channel).setAttachment(S_01); inOrder.verify(ctx).getPipeline(); inOrder.verify(pipeline).remove(handler); inOrder.verify(ctx).sendUpstream(upstreamEventCaptor.capture()); inOrder.verifyNoMoreInteractions(); ChannelEvent event = upstreamEventCaptor.getValue(); assertThat(event, instanceOf(UpstreamChannelStateEvent.class)); // now check that the event is actually a channelConnected event UpstreamChannelStateEvent channelStateEvent = (UpstreamChannelStateEvent) event; assertThat(channelStateEvent.getChannel(), is(channel)); assertThat(channelStateEvent.getState(), is(ChannelState.CONNECTED)); assertThat(channelStateEvent.getValue(), instanceOf(InetSocketAddress.class)); assertThat((InetSocketAddress) channelStateEvent.getValue(), is(remoteAddress)); }
@Test public void shouldThrowExceptionIfOriginalConnectFutureIsNull() throws Exception { // this handler only works for _user-initiated_ connect requests expectedException.expect(NullPointerException.class); handler.channelConnected(ctx, new UpstreamChannelStateEvent(channel, ChannelState.CONNECTED, new InetSocketAddress(0))); }
@Test public void shouldIndicateThatConnectSucceededIfHandshakeWriteSucceeds() throws Exception { ChannelFuture originalConnectFuture = Mockito.mock(ChannelFuture.class); InetSocketAddress connectedAddress = new InetSocketAddress(0); // pretend that a connectRequested event was sent over this channel handler.setConnectFutureForUnitTestOnly(originalConnectFuture); // signal that the connect succeeded handler.channelConnected(ctx, new UpstreamChannelStateEvent(channel, ChannelState.CONNECTED, connectedAddress)); // check the order of operations for the handshake write ArgumentCaptor<DownstreamMessageEvent> downstreamEvent = ArgumentCaptor.forClass(DownstreamMessageEvent.class); InOrder preWriteEventOrder = Mockito.inOrder(ctx); preWriteEventOrder.verify(ctx, atLeastOnce()).getChannel(); preWriteEventOrder.verify(ctx).sendDownstream(downstreamEvent.capture()); preWriteEventOrder.verifyNoMoreInteractions(); // check that the handshake is valid DownstreamMessageEvent handshakeEvent = downstreamEvent.getValue(); assertThat(Handshakers.getServerIdFromHandshake((ChannelBuffer) handshakeEvent.getMessage(), mapper), equalTo(SELF)); // mark the handshake write as having succeeded handshakeEvent.getFuture().setSuccess(); // check the order of operations after the handshake write succeeded // the following actions must be performed, in order: // 1. the handler is removed // 2. the original connect future is triggered // 3. a channelConnected event is forwarded on ArgumentCaptor<UpstreamChannelStateEvent> upstreamEvent = ArgumentCaptor.forClass(UpstreamChannelStateEvent.class); InOrder postWriteEventOrder = Mockito.inOrder(originalConnectFuture, ctx, pipeline); postWriteEventOrder.verify(ctx).getPipeline(); postWriteEventOrder.verify(pipeline).remove(handler); postWriteEventOrder.verify(originalConnectFuture).setSuccess(); postWriteEventOrder.verify(ctx).sendUpstream(upstreamEvent.capture()); postWriteEventOrder.verifyNoMoreInteractions(); // and that an appropriate upstream event was sent UpstreamChannelStateEvent connectedEvent = upstreamEvent.getValue(); assertThat(connectedEvent.getChannel(), is(channel)); assertThat(connectedEvent.getState(), is(ChannelState.CONNECTED)); assertThat((InetSocketAddress) connectedEvent.getValue(), is(connectedAddress)); }