use of org.eclipse.hono.auth.Device in project hono by eclipse.
the class VertxBasedAmqpProtocolAdapterTest method testAdapterSkipsTtdEventOnCmdConnectionCloseIfRemoveConsumerFails.
/**
* Verifies that the adapter doesn't send a 'disconnectedTtdEvent' on connection loss
* when removal of the command consumer mapping entry fails (which would be the case
* when another command consumer mapping had been registered in the mean time, meaning
* the device has already reconnected).
*
* @param ctx The vert.x test context.
* @throws InterruptedException if the test execution gets interrupted.
*/
@Test
public void testAdapterSkipsTtdEventOnCmdConnectionCloseIfRemoveConsumerFails(final VertxTestContext ctx) throws InterruptedException {
// GIVEN an AMQP adapter
givenAnAdapter(properties);
givenAnEventSenderForAnyTenant();
final Promise<Void> startupTracker = Promise.promise();
startupTracker.future().onComplete(ctx.succeedingThenComplete());
adapter.start(startupTracker);
assertThat(ctx.awaitCompletion(2, TimeUnit.SECONDS)).isTrue();
// to which a device is connected
final Device authenticatedDevice = new Device(TEST_TENANT_ID, TEST_DEVICE);
final Record record = new RecordImpl();
record.set(AmqpAdapterConstants.KEY_CLIENT_DEVICE, Device.class, authenticatedDevice);
final ProtonConnection deviceConnection = mock(ProtonConnection.class);
when(deviceConnection.attachments()).thenReturn(record);
final ArgumentCaptor<Handler<ProtonConnection>> connectHandler = VertxMockSupport.argumentCaptorHandler();
verify(server).connectHandler(connectHandler.capture());
connectHandler.getValue().handle(deviceConnection);
// that wants to receive commands
final CommandConsumer commandConsumer = mock(CommandConsumer.class);
when(commandConsumer.close(any())).thenReturn(Future.failedFuture(new ClientErrorException(HttpURLConnection.HTTP_PRECON_FAILED)));
when(commandConsumerFactory.createCommandConsumer(eq(TEST_TENANT_ID), eq(TEST_DEVICE), VertxMockSupport.anyHandler(), any(), any())).thenReturn(Future.succeededFuture(commandConsumer));
final String sourceAddress = getCommandEndpoint();
final ProtonSender sender = getSender(sourceAddress);
adapter.handleRemoteSenderOpenForCommands(deviceConnection, sender);
// WHEN the connection to the device is lost
final ArgumentCaptor<Handler<AsyncResult<ProtonConnection>>> closeHandler = VertxMockSupport.argumentCaptorHandler();
verify(deviceConnection).closeHandler(closeHandler.capture());
closeHandler.getValue().handle(Future.succeededFuture(deviceConnection));
// THEN the adapter closes the command consumer
verify(commandConsumer).close(any());
// and since closing the command consumer fails with a precon-failed exception
// there is only one notification sent during consumer creation,
assertEmptyNotificationHasBeenSentDownstream(TEST_TENANT_ID, TEST_DEVICE, -1);
// no 'disconnectedTtdEvent' event with TTD = 0
assertEmptyNotificationHasNotBeenSentDownstream(TEST_TENANT_ID, TEST_DEVICE, 0);
}
use of org.eclipse.hono.auth.Device in project hono by eclipse.
the class VertxBasedAmqpProtocolAdapterTest method getConnection.
private ProtonConnection getConnection(final Device device) {
final ProtonConnection conn = mock(ProtonConnection.class);
final Record record = mock(Record.class);
when(record.get(anyString(), eq(Device.class))).thenReturn(device);
when(conn.attachments()).thenReturn(record);
return conn;
}
use of org.eclipse.hono.auth.Device in project hono by eclipse.
the class VertxBasedAmqpProtocolAdapterTest method testConnectionFailsForAuthenticatedDeviceIfAdapterLevelConnectionLimitIsExceeded.
/**
* Verifies that an authenticated device's attempt to establish a connection fails if
* the adapter's connection limit is exceeded.
*/
@Test
public void testConnectionFailsForAuthenticatedDeviceIfAdapterLevelConnectionLimitIsExceeded() {
// GIVEN an AMQP adapter that requires devices to authenticate
properties.setAuthenticationRequired(true);
givenAnAdapter(properties);
// WHEN the adapter's connection limit exceeds
when(connectionLimitManager.isLimitExceeded()).thenReturn(true);
// WHEN a device connects
final Device authenticatedDevice = new Device(TEST_TENANT_ID, TEST_DEVICE);
final Record record = new RecordImpl();
record.set(AmqpAdapterConstants.KEY_CLIENT_DEVICE, Device.class, authenticatedDevice);
record.set(AmqpAdapterConstants.KEY_TLS_CIPHER_SUITE, String.class, "BUMLUX_CIPHER");
final ProtonConnection deviceConnection = mock(ProtonConnection.class);
when(deviceConnection.attachments()).thenReturn(record);
adapter.onConnectRequest(deviceConnection);
@SuppressWarnings("unchecked") final ArgumentCaptor<Handler<AsyncResult<ProtonConnection>>> openHandler = ArgumentCaptor.forClass(Handler.class);
verify(deviceConnection).openHandler(openHandler.capture());
openHandler.getValue().handle(Future.succeededFuture(deviceConnection));
// THEN the connection count should be incremented when the connection is opened
final InOrder metricsInOrderVerifier = inOrder(metrics);
metricsInOrderVerifier.verify(metrics).incrementConnections(TEST_TENANT_ID);
// AND the adapter should close the connection right after it opened it
final ArgumentCaptor<Handler<AsyncResult<ProtonConnection>>> closeHandler = VertxMockSupport.argumentCaptorHandler();
verify(deviceConnection).closeHandler(closeHandler.capture());
closeHandler.getValue().handle(Future.succeededFuture());
final ArgumentCaptor<ErrorCondition> errorConditionCaptor = ArgumentCaptor.forClass(ErrorCondition.class);
verify(deviceConnection).setCondition(errorConditionCaptor.capture());
assertEquals(AmqpError.UNAUTHORIZED_ACCESS, errorConditionCaptor.getValue().getCondition());
// AND the connection count should be decremented accordingly when the connection is closed
metricsInOrderVerifier.verify(metrics).decrementConnections(TEST_TENANT_ID);
verify(metrics).reportConnectionAttempt(ConnectionAttemptOutcome.ADAPTER_CONNECTIONS_EXCEEDED, TEST_TENANT_ID, "BUMLUX_CIPHER");
}
use of org.eclipse.hono.auth.Device in project hono by eclipse.
the class VertxBasedAmqpProtocolAdapterTest method testAdapterSupportsAnonymousRelay.
/**
* Verifies that the adapter offers the ANONYMOUS-RELAY capability
* in its open frame when a device connects.
*/
@Test
public void testAdapterSupportsAnonymousRelay() {
// GIVEN an AMQP adapter with a configured server.
givenAnAdapter(properties);
// WHEN a device connects
final Device authenticatedDevice = new Device(TEST_TENANT_ID, TEST_DEVICE);
final Record record = new RecordImpl();
record.set(AmqpAdapterConstants.KEY_CLIENT_DEVICE, Device.class, authenticatedDevice);
final ProtonConnection deviceConnection = mock(ProtonConnection.class);
when(deviceConnection.attachments()).thenReturn(record);
when(deviceConnection.getRemoteContainer()).thenReturn("deviceContainer");
adapter.onConnectRequest(deviceConnection);
final ArgumentCaptor<Handler<AsyncResult<ProtonConnection>>> openHandler = VertxMockSupport.argumentCaptorHandler();
verify(deviceConnection).openHandler(openHandler.capture());
openHandler.getValue().handle(Future.succeededFuture(deviceConnection));
// THEN the adapter's open frame contains the ANONYMOUS-RELAY capability
verify(deviceConnection).setOfferedCapabilities(argThat(caps -> Arrays.asList(caps).contains(Constants.CAP_ANONYMOUS_RELAY)));
}
use of org.eclipse.hono.auth.Device in project hono by eclipse.
the class VertxBasedAmqpProtocolAdapterTest method testAdapterClosesCommandConsumer.
/**
* Verifies that the adapter closes a corresponding command consumer if
* the connection to a device fails unexpectedly.
*
* @param ctx The vert.x test context.
* @throws InterruptedException if the test execution gets interrupted.
*/
private void testAdapterClosesCommandConsumer(final VertxTestContext ctx, final Handler<ProtonConnection> connectionLossTrigger) throws InterruptedException {
// GIVEN an AMQP adapter
givenAnAdapter(properties);
givenAnEventSenderForAnyTenant();
final Promise<Void> startupTracker = Promise.promise();
startupTracker.future().onComplete(ctx.succeedingThenComplete());
adapter.start(startupTracker);
assertThat(ctx.awaitCompletion(2, TimeUnit.SECONDS)).isTrue();
// to which a device is connected
final Device authenticatedDevice = new Device(TEST_TENANT_ID, TEST_DEVICE);
final Record record = new RecordImpl();
record.set(AmqpAdapterConstants.KEY_CLIENT_DEVICE, Device.class, authenticatedDevice);
final ProtonConnection deviceConnection = mock(ProtonConnection.class);
when(deviceConnection.attachments()).thenReturn(record);
final ArgumentCaptor<Handler<ProtonConnection>> connectHandler = VertxMockSupport.argumentCaptorHandler();
verify(server).connectHandler(connectHandler.capture());
connectHandler.getValue().handle(deviceConnection);
// that wants to receive commands
final CommandConsumer commandConsumer = mock(CommandConsumer.class);
when(commandConsumer.close(any())).thenReturn(Future.succeededFuture());
when(commandConsumerFactory.createCommandConsumer(eq(TEST_TENANT_ID), eq(TEST_DEVICE), VertxMockSupport.anyHandler(), any(), any())).thenReturn(Future.succeededFuture(commandConsumer));
final String sourceAddress = getCommandEndpoint();
final ProtonSender sender = getSender(sourceAddress);
adapter.handleRemoteSenderOpenForCommands(deviceConnection, sender);
// WHEN the connection to the device is lost
connectionLossTrigger.handle(deviceConnection);
// THEN the adapter closes the command consumer
verify(commandConsumer).close(any());
// and sends an empty event with TTD = 0 downstream
assertEmptyNotificationHasBeenSentDownstream(TEST_TENANT_ID, TEST_DEVICE, 0);
}
Aggregations