@Before public void beforeMethod() { successCallbackMock = mock(SuccessCallback.class); inObj = new Object(); throwExceptionDuringCall = false; currentSpanStackWhenSuccessCallbackWasCalled = new ArrayList<>(); currentMdcInfoWhenSuccessCallbackWasCalled = new ArrayList<>(); doAnswer(invocation -> { currentSpanStackWhenSuccessCallbackWasCalled.add(Tracer.getInstance().getCurrentSpanStackCopy()); currentMdcInfoWhenSuccessCallbackWasCalled.add(MDC.getCopyOfContextMap()); if (throwExceptionDuringCall) throw new RuntimeException("kaboom"); return null; }).when(successCallbackMock).onSuccess(inObj); resetTracing(); }
@Override public void addCallback(SuccessCallback<? super V> successCallback, FailureCallback failureCallback) { try { successCallback.onSuccess(this.value); } catch (Throwable ex) { failureCallback.onFailure(ex); } }
/** * Subscribe to device's commands * @param device device * @param successCallback Callback called when the device is correctly unregistered * @param failureCallback Callback called when an error occurs * @throws AgentException throws if an error occurs */ private void subscribeToCommands(Device device, SuccessCallback<String> successCallback, AgentFailureCallback failureCallback) throws AgentException { // If the device doesn't contain a command, the subscription is not necessary if (device.getCommands() != null && device.getCommands().size() > 0) { ngsiManager.subscribeToCommands(device).addCallback( result -> { if (result != null && result.getSubscribeError() == null && result.getSubscribeResponse() != null) { logger.debug("Device (EUI:{}) correctly subscribed in the NGSI Context Broker ", device.getDeviceEUI()); if (successCallback != null) { successCallback.onSuccess(result.getSubscribeResponse().getSubscriptionId()); } } else { logger.error("Unable to subscribe for device (EUI: {})", device.getDeviceEUI()); launchFailureCallback(failureCallback, new AgentException("Unable to subscribe in the NGSI Context Broker.")); } }, ex -> { String errorMsg = String.format("Unable to subscribe device in the NGSI Context Broker (%s)", device.getDeviceEUI()); logger.error(errorMsg, ex); launchFailureCallback(failureCallback, new AgentException(errorMsg, ex)); } ); } else { if (successCallback != null) { successCallback.onSuccess(null); } } }
private void simulateMqttConnectionSuccess() { doAnswer(invocationOnMock -> { SuccessCallback<String> originalArgument = invocationOnMock.getArgumentAt(0, SuccessCallback.class); originalArgument.onSuccess("connectedClientId"); return null; }).when(mockOpenLpwaMqttProvider).connect(Matchers.any(), any(FailureCallback.class)); }
private void simulateMqttDisconnectionSuccess() { doAnswer(invocationOnMock -> { SuccessCallback<String> originalArgument = invocationOnMock.getArgumentAt(0, SuccessCallback.class); originalArgument.onSuccess("disconnectedClientId"); return null; }).when(mockOpenLpwaMqttProvider).disconnect(Matchers.any(), any(FailureCallback.class)); }
private void simulateMqttSubscriptionSuccess() { doAnswer(invocationOnMock -> { SuccessCallback<String> originalArgument = invocationOnMock.getArgumentAt(0, SuccessCallback.class); originalArgument.onSuccess("subscribedClientId"); return null; }).when(mockOpenLpwaMqttProvider).subscribe(Matchers.any(), any(FailureCallback.class)); }
private void simulateOpenLpwaProviderGetDeviceInformationSuccess(DeviceInfo.DeviceStatus deviceStatus) throws ConfigurationException { ArgumentCaptor<SuccessCallback> successArg = ArgumentCaptor.forClass(SuccessCallback.class); ListenableFuture<DeviceInfo> responseFuture = mock(ListenableFuture.class); when(mockLpwaProvider.getDeviceInformation(anyString())).thenReturn(responseFuture); doAnswer(invocationOnMock -> { SuccessCallback<DeviceInfo> originalArgument = invocationOnMock.getArgumentAt(0, SuccessCallback.class); DeviceInfo deviceInfo = new DeviceInfo(); deviceInfo.setDeviceStatus(deviceStatus); originalArgument.onSuccess(deviceInfo); return null; }).when(responseFuture).addCallback(successArg.capture(), any()); }
private void simulateNgsiManagerSubscribeToCommandsSuccess(Boolean responseError) throws AgentException { ArgumentCaptor<SuccessCallback> successArg = ArgumentCaptor.forClass(SuccessCallback.class); ListenableFuture<SubscribeContextResponse> responseFuture = mock(ListenableFuture.class); when(mockNgsiManager.subscribeToCommands(any(Device.class))).thenReturn(responseFuture); doAnswer(invocationOnMock -> { SuccessCallback<SubscribeContextResponse> originalArgument = invocationOnMock.getArgumentAt(0, SuccessCallback.class); SubscribeContextResponse subscribeContextResponse = new SubscribeContextResponse(); subscribeContextResponse.setSubscribeError(responseError ? new SubscribeError() : null); SubscribeResponse subscribeResponse = new SubscribeResponse(); subscribeResponse.setSubscriptionId(subscriptionId); subscribeContextResponse.setSubscribeResponse(subscribeResponse); originalArgument.onSuccess(subscribeContextResponse); return null; }).when(responseFuture).addCallback(successArg.capture(), any()); }
private void simulateNgsiManagerUnsubscribeSuccess(Boolean responseError) throws AgentException { ArgumentCaptor<SuccessCallback> successArg = ArgumentCaptor.forClass(SuccessCallback.class); ListenableFuture<UnsubscribeContextResponse> responseFuture = mock(ListenableFuture.class); when(mockNgsiManager.unsubscribe(anyString())).thenReturn(responseFuture); doAnswer(invocationOnMock -> { SuccessCallback<UnsubscribeContextResponse> originalArgument = invocationOnMock.getArgumentAt(0, SuccessCallback.class); UnsubscribeContextResponse unsubscribeContextResponse = new UnsubscribeContextResponse(); StatusCode statusCode = new StatusCode(responseError ? CODE_500 : CODE_200, ""); unsubscribeContextResponse.setStatusCode(statusCode); originalArgument.onSuccess(unsubscribeContextResponse); return null; }).when(responseFuture).addCallback(successArg.capture(), any()); }
private void simulateOpenLpwaProviderRegisterDeviceCommandSuccess(DeviceCommand.DeviceCommandStatus deviceCommandStatus) throws ConfigurationException { ArgumentCaptor<SuccessCallback> successArg = ArgumentCaptor.forClass(SuccessCallback.class); ListenableFuture<DeviceCommand> responseFuture = mock(ListenableFuture.class); when(mockLpwaProvider.registerDeviceCommand(anyString(), any(RegisterDeviceCommandParameter.class))).thenReturn(responseFuture); doAnswer(invocationOnMock -> { SuccessCallback<DeviceCommand> originalArgument = invocationOnMock.getArgumentAt(0, SuccessCallback.class); DeviceCommand deviceCommand = new DeviceCommand(); deviceCommand.setCommandStatus(deviceCommandStatus); deviceCommand.setCreationTs(new Date()); originalArgument.onSuccess(deviceCommand); return null; }).when(responseFuture).addCallback(successArg.capture(), any()); }
/** * Constructor that uses the given trace and MDC information, which will be associated with the thread when the * given operation is executed. * * <p>The operation you pass in cannot be null (an {@link IllegalArgumentException} will be thrown if you pass in * null for the operation). * * <p>The trace and/or MDC info can be null and no error will be thrown, however any trace or MDC info that is null * means the corresponding info will not be available to the thread when the operation is executed. */ public SuccessCallbackWithTracing(SuccessCallback<T> origSuccessCallback, Deque<Span> spanStackForExecution, Map<String, String> mdcContextMapForExecution) { if (origSuccessCallback == null) throw new IllegalArgumentException("origSuccessCallback cannot be null"); this.origSuccessCallback = origSuccessCallback; this.spanStackForExecution = spanStackForExecution; this.mdcContextMapForExecution = mdcContextMapForExecution; }
/** * @return A {@link SuccessCallback} that wraps the given original so that the given distributed tracing and MDC * information is registered with the thread and therefore available during execution and unregistered after * execution. You can pass in a {@link TracingState} for clearer less verbose code since it extends * {@code Pair<Deque<Span>, Map<String, String>>}. */ public static <T> SuccessCallback<T> successCallbackWithTracing( SuccessCallback<T> successCallback, Pair<Deque<Span>, Map<String, String>> threadInfoToLink ) { return new SuccessCallbackWithTracing<>(successCallback, threadInfoToLink); }
/** * @return A {@link SuccessCallback} that wraps the given original so that the given distributed tracing and MDC * information is registered with the thread and therefore available during execution and unregistered after * execution. */ public static <T> SuccessCallback<T> successCallbackWithTracing( SuccessCallback<T> successCallback, Deque<Span> spanStackToLink, Map<String, String> mdcContextMapToLink ) { return new SuccessCallbackWithTracing<>(successCallback, spanStackToLink, mdcContextMapToLink); }
@Before public void beforeMethod() { resetTracing(); httpMessageMock = mock(HttpMessage.class); headersMock = mock(HttpHeaders.class); doReturn(headersMock).when(httpMessageMock).getHeaders(); successCallbackMock = mock(SuccessCallback.class); failureCallbackMock = mock(FailureCallback.class); listenableFutureCallbackMock = mock(ListenableFutureCallback.class); }
private void verifySuccessCallbackWithTracing(SuccessCallback result, SuccessCallback expectedCoreInstance, Deque<Span> expectedSpanStack, Map<String, String> expectedMdcInfo) { assertThat(result).isInstanceOf(SuccessCallbackWithTracing.class); assertThat(Whitebox.getInternalState(result, "origSuccessCallback")).isSameAs(expectedCoreInstance); assertThat(Whitebox.getInternalState(result, "spanStackForExecution")).isEqualTo(expectedSpanStack); assertThat(Whitebox.getInternalState(result, "mdcContextMapForExecution")).isEqualTo(expectedMdcInfo); }
@Test public void successCallbackWithTracing_using_current_thread_info_works_as_expected() { // given Pair<Deque<Span>, Map<String, String>> setupInfo = setupCurrentThreadWithTracingInfo(); // when SuccessCallback result = successCallbackWithTracing(successCallbackMock); // then verifySuccessCallbackWithTracing(result, successCallbackMock, setupInfo.getLeft(), setupInfo.getRight()); }
@Test public void successCallbackWithTracing_pair_works_as_expected() { // given Pair<Deque<Span>, Map<String, String>> setupInfo = generateTracingInfo(); // when SuccessCallback result = successCallbackWithTracing(successCallbackMock, setupInfo); // then verifySuccessCallbackWithTracing(result, successCallbackMock, setupInfo.getLeft(), setupInfo.getRight()); }
@Test public void successCallbackWithTracing_separate_args_works_as_expected() { // given Pair<Deque<Span>, Map<String, String>> setupInfo = generateTracingInfo(); // when SuccessCallback result = successCallbackWithTracing( successCallbackMock, setupInfo.getLeft(), setupInfo.getRight() ); // then verifySuccessCallbackWithTracing(result, successCallbackMock, setupInfo.getLeft(), setupInfo.getRight()); }
@Override public void addCallback(SuccessCallback<? super V> successCallback, FailureCallback failureCallback) { try { if (this.executionException != null) { Throwable cause = this.executionException.getCause(); failureCallback.onFailure(cause != null ? cause : this.executionException); } else { successCallback.onSuccess(this.value); } } catch (Throwable ex) { // Ignore } }
@Test public void testUnsubscribeOnEventTypeRemoval() { // Mock the task scheduler and capture the runnable ArgumentCaptor<Runnable> runnableArg = ArgumentCaptor.forClass(Runnable.class); when(taskScheduler.scheduleWithFixedDelay(runnableArg.capture(), anyLong())).thenReturn(Mockito.mock(ScheduledFuture.class)); // Mock the response to the subsribeContext ArgumentCaptor<SuccessCallback> successArg = ArgumentCaptor.forClass(SuccessCallback.class); ListenableFuture<SubscribeContextResponse> responseFuture = Mockito.mock(ListenableFuture.class); doNothing().when(responseFuture).addCallback(successArg.capture(), any()); // Return the mocked future on subscription when(ngsiClient.subscribeContext(any(), any(), any())).thenReturn(responseFuture); Configuration configuration = getBasicConf(); subscriptionManager.setConfiguration(configuration); // Execute scheduled runnable runnableArg.getValue().run(); // Return the SubscribeContextResponse callSuccessCallback(successArg); // Mock future for unsubscribeContext ListenableFuture<UnsubscribeContextResponse> responseFuture2 = Mockito.mock(ListenableFuture.class); doNothing().when(responseFuture2).addCallback(successArg.capture(), any()); when(ngsiClient.unsubscribeContext(eq("http://iotAgent"), eq(null), eq("12345678"))).thenReturn(responseFuture2); // Set a configuration without the eventType Configuration emptyConfiguration = new Configuration(); emptyConfiguration.setEventTypeIns(Collections.emptyList()); subscriptionManager.setConfiguration(emptyConfiguration); // Check that unsubsribe is called when a later configuration removed the event type Assert.notNull(successArg.getValue()); }
@Test public void testUnsubscribeOnProviderRemoval() { // Mock the task scheduler and capture the runnable ArgumentCaptor<Runnable> runnableArg = ArgumentCaptor.forClass(Runnable.class); when(taskScheduler.scheduleWithFixedDelay(runnableArg.capture(), anyLong())).thenReturn(Mockito.mock(ScheduledFuture.class)); // Mock the response to the subsribeContext ArgumentCaptor<SuccessCallback> successArg = ArgumentCaptor.forClass(SuccessCallback.class); ListenableFuture<SubscribeContextResponse> responseFuture = Mockito.mock(ListenableFuture.class); doNothing().when(responseFuture).addCallback(successArg.capture(), any()); // Return the mocked future on subscription when(ngsiClient.subscribeContext(any(),any(), any())).thenReturn(responseFuture); Configuration configuration = getBasicConf(); subscriptionManager.setConfiguration(configuration); // Execute scheduled runnable runnableArg.getValue().run(); // Return the SubscribeContextResponse callSuccessCallback(successArg); // Mock future for unsubscribeContext ListenableFuture<UnsubscribeContextResponse> responseFuture2 = Mockito.mock(ListenableFuture.class); doNothing().when(responseFuture2).addCallback(successArg.capture(), any()); when(ngsiClient.unsubscribeContext(eq("http://iotAgent"), eq(null), eq("12345678"))).thenReturn(responseFuture2); // Reset conf should trigger unsubsribeContext Configuration emptyConfiguration = getBasicConf(); emptyConfiguration.getEventTypeIns().get(0).setProviders(Collections.emptySet()); subscriptionManager.setConfiguration(emptyConfiguration); // Check that unsubsribe is called Assert.notNull(successArg.getValue()); }
@Test public void testValidSubscription() { // add configuration // Mock the task scheduler and capture the runnable ArgumentCaptor<Runnable> runnableArg = ArgumentCaptor.forClass(Runnable.class); when(taskScheduler.scheduleWithFixedDelay(runnableArg.capture(), anyLong())).thenReturn(Mockito.mock(ScheduledFuture.class)); // Mock the response to the subsribeContext ArgumentCaptor<SuccessCallback> successArg = ArgumentCaptor.forClass(SuccessCallback.class); ListenableFuture<SubscribeContextResponse> responseFuture = Mockito.mock(ListenableFuture.class); doNothing().when(responseFuture).addCallback(successArg.capture(), any()); Configuration configuration = getBasicConf(); subscriptionManager.setConfiguration(configuration); // Capture the arg of subscription and return the mocked future ArgumentCaptor<String> urlProviderArg = ArgumentCaptor.forClass(String.class); ArgumentCaptor<SubscribeContext> subscribeContextArg = ArgumentCaptor.forClass(SubscribeContext.class); when(ngsiClient.subscribeContext(urlProviderArg.capture(), eq(null), subscribeContextArg.capture())).thenReturn(responseFuture); // Execute scheduled runnable runnableArg.getValue().run(); // Return the SubscribeContextResponse callSuccessCallback(successArg); // check ngsiClient.unsubscribe() is never called verify(ngsiClient, never()).unsubscribeContext(any(), any(), any()); subscriptionManager.validateSubscriptionId("12345678", "http://iotAgent"); }
private void callSuccessCallback (ArgumentCaptor<SuccessCallback> successArg) { SubscribeContextResponse response = new SubscribeContextResponse(); SubscribeResponse subscribeResponse = new SubscribeResponse(); subscribeResponse.setSubscriptionId("12345678"); subscribeResponse.setDuration("PT1H"); response.setSubscribeResponse(subscribeResponse); successArg.getValue().onSuccess(response); }
@Override public void addCallback(SuccessCallback<? super T> successCallback, FailureCallback failureCallback) { this.registry.addSuccessCallback(successCallback); this.registry.addFailureCallback(failureCallback); }
public void addSuccessCallback(SuccessCallback<? super ClientHttpResponse> callback) { this.callbacks.addSuccessCallback(callback); }
@Override public void addCallback(SuccessCallback<? super ClientHttpResponse> successCallback, FailureCallback failureCallback) { this.callback.addSuccessCallback(successCallback); this.callback.addFailureCallback(failureCallback); }
@Override protected <T> ListenableFuture<T> doExecute(URI url, HttpMethod method, AsyncRequestCallback requestCallback, ResponseExtractor<T> responseExtractor) throws RestClientException { final ListenableFuture<T> future = super.doExecute(url, method, requestCallback, responseExtractor); final Span span = this.tracer.getCurrentSpan(); future.addCallback(new TraceListenableFutureCallback<>(this.tracer, span, this.errorParser)); // potential race can happen here if (span != null && span.equals(this.tracer.getCurrentSpan())) { Span parent = this.tracer.detach(span); if (parent != null) { this.tracer.continueSpan(parent); } } return new ListenableFuture<T>() { @Override public boolean cancel(boolean mayInterruptIfRunning) { return future.cancel(mayInterruptIfRunning); } @Override public boolean isCancelled() { return future.isCancelled(); } @Override public boolean isDone() { return future.isDone(); } @Override public T get() throws InterruptedException, ExecutionException { return future.get(); } @Override public T get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { return future.get(timeout, unit); } @Override public void addCallback(ListenableFutureCallback<? super T> callback) { future.addCallback(new TraceListenableFutureCallbackWrapper<>(TraceAsyncRestTemplate.this.tracer, span, callback)); } @Override public void addCallback(SuccessCallback<? super T> successCallback, FailureCallback failureCallback) { future.addCallback( new TraceSuccessCallback<>(TraceAsyncRestTemplate.this.tracer, span, successCallback), new TraceFailureCallback(TraceAsyncRestTemplate.this.tracer, span, failureCallback)); } }; }
private TraceSuccessCallback(Tracer tracer, Span parent, SuccessCallback<T> delegate) { this.tracer = tracer; this.parent = parent; this.delegate = delegate; }
@Override public void addCallback(SuccessCallback<? super T> successCallback, FailureCallback failureCallback) { getWrappedFuture().addCallbacks(successCallback::onSuccess, failureCallback::onFailure); }
@Override public void addCallback(SuccessCallback<? super T> successCallback, FailureCallback failureCallback) { getWrappedFuture().addCallback(successCallback, failureCallback); }
/** * Constructor that uses the given trace and MDC information, which will be associated with the thread when the * given operation is executed. * * <p>The operation you pass in cannot be null (an {@link IllegalArgumentException} will be thrown if you pass in * null for the operation). * * <p>The {@link Pair} can be null, or you can pass null for the left and/or right side of the pair, and no error * will be thrown. Any trace or MDC info that is null means the corresponding info will not be available to the * thread when the operation is executed however. * * <p>You can pass in a {@link TracingState} for clearer less verbose code since it extends * {@code Pair<Deque<Span>, Map<String, String>>}. */ public SuccessCallbackWithTracing(SuccessCallback<T> origSuccessCallback, Pair<Deque<Span>, Map<String, String>> originalThreadInfo) { this( origSuccessCallback, (originalThreadInfo == null) ? null : originalThreadInfo.getLeft(), (originalThreadInfo == null) ? null : originalThreadInfo.getRight() ); }
/** * Constructor that extracts the current tracing and MDC information from the current thread using {@link * Tracer#getCurrentSpanStackCopy()} and {@link MDC#getCopyOfContextMap()}, and forwards the information to * the {@link SuccessCallbackWithTracing#SuccessCallbackWithTracing(SuccessCallback, Deque, Map)} * constructor. That tracing and MDC information will be associated with the thread when the given operation is * executed. * * <p>The operation you pass in cannot be null (an {@link IllegalArgumentException} will be thrown if you pass in * null for the operation). */ public SuccessCallbackWithTracing(SuccessCallback<T> origSuccessCallback) { this(origSuccessCallback, Tracer.getInstance().getCurrentSpanStackCopy(), MDC.getCopyOfContextMap()); }
/** * Equivalent to calling {@code new SuccessCallbackWithTracing(origSuccessCallback)} - this allows you to do a static method * import for cleaner looking code in some cases. This method ultimately extracts the current tracing and MDC * information from the current thread using {@link Tracer#getCurrentSpanStackCopy()} and {@link * MDC#getCopyOfContextMap()}. That tracing and MDC information will be associated with the thread when the given * operation is executed. * * <p>The operation you pass in cannot be null (an {@link IllegalArgumentException} will be thrown if you pass in * null for the operation). * * @return {@code new SuccessCallbackWithTracing(origSuccessCallback)}. * @see SuccessCallbackWithTracing#SuccessCallbackWithTracing(SuccessCallback) * @see SuccessCallbackWithTracing */ public static <T> SuccessCallbackWithTracing<T> withTracing(SuccessCallback<T> origSuccessCallback) { return new SuccessCallbackWithTracing<>(origSuccessCallback); }
/** * Equivalent to calling {@code new SuccessCallbackWithTracing(origSuccessCallback, originalThreadInfo)} - this allows you * to do a static method import for cleaner looking code in some cases. This method uses the given trace and MDC * information, which will be associated with the thread when the given operation is executed. * * <p>The operation you pass in cannot be null (an {@link IllegalArgumentException} will be thrown if you pass in * null for the operation). * * <p>The {@link Pair} can be null, or you can pass null for the left and/or right side of the pair, and no error * will be thrown. Any trace or MDC info that is null means the corresponding info will not be available to the * thread when the operation is executed however. * * <p>You can pass in a {@link TracingState} for clearer less verbose code since it extends * {@code Pair<Deque<Span>, Map<String, String>>}. * * @return {@code new SuccessCallbackWithTracing(origSuccessCallback, originalThreadInfo)}. * @see SuccessCallbackWithTracing#SuccessCallbackWithTracing(SuccessCallback, Pair) * @see SuccessCallbackWithTracing */ public static <T> SuccessCallbackWithTracing<T> withTracing(SuccessCallback<T> origSuccessCallback, Pair<Deque<Span>, Map<String, String>> originalThreadInfo) { return new SuccessCallbackWithTracing<>(origSuccessCallback, originalThreadInfo); }
/** * Equivalent to calling {@code * new SuccessCallbackWithTracing(origSuccessCallback, spanStackForExecution, mdcContextMapForExecution)} - * this allows you to do a static method import for cleaner looking code in some cases. This method uses the given * trace and MDC information, which will be associated with the thread when the given operation is executed. * * <p>The operation you pass in cannot be null (an {@link IllegalArgumentException} will be thrown if you pass in * null for the operation). * * <p>The trace and/or MDC info can be null and no error will be thrown, however any trace or MDC info that is null * means the corresponding info will not be available to the thread when the operation is executed. * * @return {@code new SuccessCallbackWithTracing(origSuccessCallback, spanStackForExecution, mdcContextMapForExecution)}. * @see SuccessCallbackWithTracing#SuccessCallbackWithTracing(SuccessCallback, Deque, Map) * @see SuccessCallbackWithTracing */ public static <T> SuccessCallbackWithTracing<T> withTracing(SuccessCallback<T> origSuccessCallback, Deque<Span> spanStackForExecution, Map<String, String> mdcContextMapForExecution) { return new SuccessCallbackWithTracing<>(origSuccessCallback, spanStackForExecution, mdcContextMapForExecution); }
/** * @return A {@link SuccessCallback} that wraps the given original so that the <b>current thread's</b> tracing and MDC * information is registered with the thread and therefore available during execution and unregistered after * execution. * * <p>NOTE: The current thread's tracing and MDC info will be extracted using {@link * Tracer#getCurrentSpanStackCopy()} and {@link MDC#getCopyOfContextMap()}. */ public static <T> SuccessCallback<T> successCallbackWithTracing(SuccessCallback<T> successCallback) { return new SuccessCallbackWithTracing<>(successCallback); }