void endpointCrashed(Endpoint endpoint) { QueueConnectionImpl deadConnection = null; // We must be synchronized while checking to see if we have a queue connection for the endpoint, // because when we need to prevent a race between adding a queue connection to the map // and the endpoint for that connection crashing. synchronized (lock) { deadConnection = queueConnections.getConnection(endpoint); if (deadConnection != null) { queueConnections = queueConnections.removeConnection(deadConnection); } } if (deadConnection != null) { logger .info("{} subscription endpoint {} crashed. Scheduling recovery.", new Object[] {deadConnection.getUpdater() != null ? (deadConnection.getUpdater().isPrimary() ? "Primary" : "Redundant") : "Queue", endpoint}); scheduleRedundancySatisfierIfNeeded(0); deadConnection.internalDestroy(); } else { if (logger.isDebugEnabled()) { logger.debug("Ignoring crashed endpoint {} it does not have a queue.", endpoint); } } }
@Test public void testInternalDestroyFollowedByInternalClose() { // Mock ClientUpdater and Connection ClientUpdater updater = mock(ClientUpdater.class); Connection connection = mock(Connection.class); // Create a QueueConnectionImpl on the mocks QueueConnectionImpl qci = new QueueConnectionImpl(null, connection, updater, null); // Invoke internalDestroy (which sets the updater to null) qci.internalDestroy(); // Assert that invoking internalClose throws a ConnectionDestroyedException and not a // NullPointerException assertThatThrownBy(() -> qci.internalClose(false)) .isInstanceOf(ConnectionDestroyedException.class); } }