Skip to content

Commit

Permalink
Fix NPE in end span (#35299)
Browse files Browse the repository at this point in the history
* Fix NPE in end span
  • Loading branch information
lmolkova authored Jun 5, 2023
1 parent b75df37 commit 7395f50
Show file tree
Hide file tree
Showing 7 changed files with 159 additions and 2 deletions.
3 changes: 3 additions & 0 deletions sdk/eventhubs/azure-messaging-eventhubs/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@
### Bugs Fixed

- Fixed exception when attempting to populate trace context on received `EventData`. ([#33594](https://github.com/Azure/azure-sdk-for-java/issues/33594))
- Fixed `NullPointerException` when ending span when `AmqpException` is thrown, but its `AmqpErrorCondition` is `null`.
([#35299](https://github.com/Azure/azure-sdk-for-java/issues/35299))


### Other Changes

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,9 @@ public void endSpan(Throwable throwable, Context span, AutoCloseable scope) {
String errorCondition = null;
if (throwable instanceof AmqpException) {
AmqpException exception = (AmqpException) throwable;
errorCondition = exception.getErrorCondition().getErrorCondition();
if (exception.getErrorCondition() != null) {
errorCondition = exception.getErrorCondition().getErrorCondition();
}
}

try {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

package com.azure.messaging.eventhubs.implementation.instrumentation;

import com.azure.core.amqp.exception.AmqpErrorCondition;
import com.azure.core.amqp.exception.AmqpException;
import com.azure.core.util.Context;
import com.azure.core.util.tracing.Tracer;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;

import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Stream;

import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.isNull;
import static org.mockito.ArgumentMatchers.same;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

public class EventHubsTracerTests {
@Test
public void testSpanEndNoError() {
Tracer inner = mock(Tracer.class);
when(inner.isEnabled()).thenReturn(true);

EventHubsTracer tracer = new EventHubsTracer(inner, "fqdn", "entityPath");
tracer.endSpan(null, Context.NONE, null);

verify(inner, times(1)).end(isNull(), isNull(), same(Context.NONE));
}

@Test
public void testSpanEndNoErrorAndScope() {
Tracer inner = mock(Tracer.class);
when(inner.isEnabled()).thenReturn(true);

EventHubsTracer tracer = new EventHubsTracer(inner, "fqdn", "entityPath");
AtomicBoolean closed = new AtomicBoolean();
tracer.endSpan(null, Context.NONE, () -> closed.set(true));

verify(inner, times(1)).end(isNull(), isNull(), same(Context.NONE));
assertTrue(closed.get());
}

@ParameterizedTest
@MethodSource("getAmqpException")
public void testSpanEndException(Exception amqpException, String expectedStatus) {
Tracer inner = mock(Tracer.class);
when(inner.isEnabled()).thenReturn(true);

EventHubsTracer tracer = new EventHubsTracer(inner, "fqdn", "entityPath");

tracer.endSpan(amqpException, Context.NONE, null);

verify(inner, times(1)).end(eq(expectedStatus), eq(amqpException), same(Context.NONE));
}

public static Stream<Arguments> getAmqpException() {
return Stream.of(
Arguments.of(new RuntimeException("foo"), null),
Arguments.of(new AmqpException(false, "foo", null, null), null),
Arguments.of(new AmqpException(false, AmqpErrorCondition.NOT_FOUND, "foo", null), AmqpErrorCondition.NOT_FOUND.getErrorCondition()),
Arguments.of(new AmqpException(false, AmqpErrorCondition.TIMEOUT_ERROR, "", null), AmqpErrorCondition.TIMEOUT_ERROR.getErrorCondition()),
Arguments.of(new AmqpException(false, AmqpErrorCondition.SERVER_BUSY_ERROR, null, new RuntimeException("foo"), null), AmqpErrorCondition.SERVER_BUSY_ERROR.getErrorCondition()));
}
}
3 changes: 3 additions & 0 deletions sdk/servicebus/azure-messaging-servicebus/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@

### Bugs Fixed

- Fixed `NullPointerException` when ending span when `AmqpException` is thrown, but its `AmqpErrorCondition` is `null`.
([#35299](https://github.com/Azure/azure-sdk-for-java/issues/35299))

### Other Changes

## 7.14.0 (2023-05-15)
Expand Down
1 change: 1 addition & 0 deletions sdk/servicebus/azure-messaging-servicebus/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
--add-opens com.azure.messaging.servicebus/com.azure.messaging.servicebus.administration.models=ALL-UNNAMED

--add-exports com.azure.core/com.azure.core.implementation.util=ALL-UNNAMED
--add-exports com.azure.core/com.azure.core.implementation.instrumentation=ALL-UNNAMED
--add-opens com.azure.core/com.azure.core.implementation.util=ALL-UNNAMED
--add-reads com.azure.messaging.servicebus=com.azure.http.netty
--add-reads com.azure.messaging.servicebus=com.azure.core.tracing.opentelemetry
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,9 @@ public void endSpan(Throwable throwable, Context span, AutoCloseable scope) {
String errorCondition = null;
if (throwable instanceof AmqpException) {
AmqpException exception = (AmqpException) throwable;
errorCondition = exception.getErrorCondition().getErrorCondition();
if (exception.getErrorCondition() != null) {
errorCondition = exception.getErrorCondition().getErrorCondition();
}
}

try {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

package com.azure.messaging.servicebus.implementation.instrumentation;

import com.azure.core.amqp.exception.AmqpErrorCondition;
import com.azure.core.amqp.exception.AmqpException;
import com.azure.core.util.Context;
import com.azure.core.util.tracing.Tracer;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;

import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Stream;

import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.isNull;
import static org.mockito.ArgumentMatchers.same;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

public class ServiceBusTracerTests {
@Test
public void testSpanEndNoError() {
Tracer inner = mock(Tracer.class);
when(inner.isEnabled()).thenReturn(true);

ServiceBusTracer tracer = new ServiceBusTracer(inner, "fqdn", "entityPath");
tracer.endSpan(null, Context.NONE, null);

verify(inner, times(1)).end(isNull(), isNull(), same(Context.NONE));
}

@Test
public void testSpanEndNoErrorAndScope() {
Tracer inner = mock(Tracer.class);
when(inner.isEnabled()).thenReturn(true);

ServiceBusTracer tracer = new ServiceBusTracer(inner, "fqdn", "entityPath");
AtomicBoolean closed = new AtomicBoolean();
tracer.endSpan(null, Context.NONE, () -> closed.set(true));

verify(inner, times(1)).end(isNull(), isNull(), same(Context.NONE));
assertTrue(closed.get());
}

@ParameterizedTest
@MethodSource("getAmqpException")
public void testSpanEndException(Exception amqpException, String expectedStatus) {
Tracer inner = mock(Tracer.class);
when(inner.isEnabled()).thenReturn(true);

ServiceBusTracer tracer = new ServiceBusTracer(inner, "fqdn", "entityPath");

tracer.endSpan(amqpException, Context.NONE, null);

verify(inner, times(1)).end(eq(expectedStatus), eq(amqpException), same(Context.NONE));
}

public static Stream<Arguments> getAmqpException() {
return Stream.of(
Arguments.of(new RuntimeException("foo"), null),
Arguments.of(new AmqpException(false, "foo", null, null), null),
Arguments.of(new AmqpException(false, AmqpErrorCondition.NOT_FOUND, "foo", null), AmqpErrorCondition.NOT_FOUND.getErrorCondition()),
Arguments.of(new AmqpException(false, AmqpErrorCondition.TIMEOUT_ERROR, "", null), AmqpErrorCondition.TIMEOUT_ERROR.getErrorCondition()),
Arguments.of(new AmqpException(false, AmqpErrorCondition.SERVER_BUSY_ERROR, null, new RuntimeException("foo"), null), AmqpErrorCondition.SERVER_BUSY_ERROR.getErrorCondition()));
}
}

0 comments on commit 7395f50

Please sign in to comment.