From 004a235ef03cf72dd39e91a2085fa94fd5c1c80d Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Wed, 30 Aug 2017 15:46:39 -0700 Subject: [PATCH] BUG-9079 Make PCEP session recoverable from exception This patch makes PCEP session recoverable from any netty exception. Whenever an exception happens, PCEP session will be closed. So it will be at a clean state when the next session retry comes. Change-Id: I38a983c44519fd5c12cb9cd0da09fa14c4177ac7 Signed-off-by: Kevin Wang --- .../protocol/pcep/impl/PCEPSessionImpl.java | 26 +++++++++++-- .../pcep/impl/PCEPSessionImplTest.java | 37 +++++++++++++++++++ .../pcep/impl/SimpleSessionListener.java | 1 + 3 files changed, 61 insertions(+), 3 deletions(-) diff --git a/pcep/impl/src/main/java/org/opendaylight/protocol/pcep/impl/PCEPSessionImpl.java b/pcep/impl/src/main/java/org/opendaylight/protocol/pcep/impl/PCEPSessionImpl.java index 22ff18e53e..e85362b386 100644 --- a/pcep/impl/src/main/java/org/opendaylight/protocol/pcep/impl/PCEPSessionImpl.java +++ b/pcep/impl/src/main/java/org/opendaylight/protocol/pcep/impl/PCEPSessionImpl.java @@ -175,6 +175,16 @@ public class PCEPSessionImpl extends SimpleChannelInboundHandler implem } } + /** + * Handle exception occurred in the PCEP session. The session in error state should be closed + * properly so that it can be restored later. + */ + @VisibleForTesting + void handleException(final Throwable cause) { + LOG.error("Exception captured for session {}, closing session.", this, cause); + terminate(TerminationReason.UNKNOWN); + } + /** * Sends message to serialization. * @@ -360,12 +370,17 @@ public class PCEPSessionImpl extends SimpleChannelInboundHandler implem } @VisibleForTesting - public void sessionUp() { - this.listener.onSessionUp(this); + void sessionUp() { + try { + this.listener.onSessionUp(this); + } catch (final Exception e) { + handleException(e); + throw e; + } } @VisibleForTesting - protected final Queue getUnknownMessagesTimes() { + final Queue getUnknownMessagesTimes() { return this.unknownMessagesTimes; } @@ -417,6 +432,11 @@ public class PCEPSessionImpl extends SimpleChannelInboundHandler implem this.sessionUp(); } + @Override + public void exceptionCaught(final ChannelHandlerContext ctx, final Throwable cause) { + handleException(cause); + } + @Override public Tlvs localSessionCharacteristics() { return this.localOpen.getTlvs(); diff --git a/pcep/impl/src/test/java/org/opendaylight/protocol/pcep/impl/PCEPSessionImplTest.java b/pcep/impl/src/test/java/org/opendaylight/protocol/pcep/impl/PCEPSessionImplTest.java index 033324a078..c6267f455e 100644 --- a/pcep/impl/src/test/java/org/opendaylight/protocol/pcep/impl/PCEPSessionImplTest.java +++ b/pcep/impl/src/test/java/org/opendaylight/protocol/pcep/impl/PCEPSessionImplTest.java @@ -12,7 +12,9 @@ import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; +import org.mockito.Matchers; import org.mockito.Mockito; +import org.opendaylight.protocol.pcep.PCEPSession; import org.opendaylight.protocol.pcep.TerminationReason; import org.opendaylight.protocol.pcep.impl.spi.Util; import org.opendaylight.protocol.pcep.spi.PCEPErrors; @@ -149,4 +151,39 @@ public class PCEPSessionImplTest extends AbstractPCEPSessionTest { Assert.assertEquals(PCEPErrors.UNKNOWN_PLSP_ID.getErrorType(), errMsgs2.getLastSentError().getErrorType().shortValue()); Assert.assertEquals(PCEPErrors.UNKNOWN_PLSP_ID.getErrorValue(), errMsgs2.getLastSentError().getErrorValue().shortValue()); } + + @Test + public void testExceptionCaught() throws Exception { + Assert.assertFalse(this.session.isClosed()); + Assert.assertTrue(this.listener.up); + this.session.exceptionCaught(null, new Throwable("PCEP exception.")); + Assert.assertFalse(this.listener.up); + Assert.assertTrue(this.session.isClosed()); + } + + @Test + public void testSessionRecoveryOnException() throws Exception { + this.listener = new SimpleExceptionSessionListener(); + this.session = Mockito.spy(new PCEPSessionImpl(this.listener, 0, this.channel, + this.openMsg.getOpenMessage().getOpen(), this.openMsg.getOpenMessage().getOpen())); + Mockito.verify(this.session, Mockito.never()).handleException(Matchers.any()); + Mockito.verify(this.session, Mockito.never()).sendMessage(Matchers.any()); + Mockito.verify(this.session, Mockito.never()).closeChannel(); + try { + this.session.sessionUp(); + Assert.fail(); // expect the exception to be populated + } catch (final RuntimeException ignored) {} + Assert.assertFalse(this.listener.up); + Mockito.verify(this.session).handleException(Matchers.any()); + Mockito.verify(this.session).sendMessage(Matchers.any(CloseMessage.class)); + Mockito.verify(this.session).closeChannel(); + } + + private static class SimpleExceptionSessionListener extends SimpleSessionListener { + @Override + public synchronized void onSessionUp(final PCEPSession session) { + super.onSessionUp(session); + throw new RuntimeException("Mocked runtime exception."); + } + } } diff --git a/pcep/impl/src/test/java/org/opendaylight/protocol/pcep/impl/SimpleSessionListener.java b/pcep/impl/src/test/java/org/opendaylight/protocol/pcep/impl/SimpleSessionListener.java index b0d3cf7250..4c3ba69252 100644 --- a/pcep/impl/src/test/java/org/opendaylight/protocol/pcep/impl/SimpleSessionListener.java +++ b/pcep/impl/src/test/java/org/opendaylight/protocol/pcep/impl/SimpleSessionListener.java @@ -55,5 +55,6 @@ public class SimpleSessionListener implements PCEPSessionListener { @Override public void onSessionTerminated(final PCEPSession session, final PCEPTerminationReason cause) { LOG.debug("Session terminated. Cause : {}", cause.toString()); + this.up = false; } } -- 2.36.6