Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions settings.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ hideFromDependabot(":smoke-tests:apps:CoreAndFilter3xUsingOld3xAgent")
hideFromDependabot(":smoke-tests:apps:CustomDimensions")
hideFromDependabot(":smoke-tests:apps:CustomInstrumentation")
hideFromDependabot(":smoke-tests:apps:DetectUnexpectedOtelMetrics")
hideFromDependabot(":smoke-tests:apps:ExceptionMessageHandling")
hideFromDependabot(":smoke-tests:apps:Diagnostics")
hideFromDependabot(":smoke-tests:apps:Diagnostics:JfrFileReader")
hideFromDependabot(":smoke-tests:apps:DiagnosticExtension:MockExtension")
Expand Down
11 changes: 11 additions & 0 deletions smoke-tests/apps/ExceptionMessageHandling/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
plugins {
id("ai.smoke-test-war")
}

dependencies {
implementation("org.springframework.boot:spring-boot-starter-web:2.5.12") {
exclude("org.springframework.boot", "spring-boot-starter-tomcat")
}
// this dependency is needed to make wildfly happy
implementation("org.reactivestreams:reactive-streams:1.0.3")
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

package com.microsoft.applicationinsights.smoketestapp;

import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;

@SpringBootApplication
public class SpringBootApp extends SpringBootServletInitializer {
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder applicationBuilder) {
return applicationBuilder.sources(SpringBootApp.class);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

package com.microsoft.applicationinsights.smoketestapp;

import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class TestController {

private static final Logger logger = LoggerFactory.getLogger("smoketestapp");

@GetMapping("/")
public String root() {
return "OK";
}

@GetMapping("/testExceptionWithoutMessage")
public String testExceptionWithoutMessage(HttpServletResponse response) {
// This reproduces the original issue: exceptions without messages
// that would cause 206 errors from Application Insights service
logger.error("Exception without message test", new NullPointerException());
return "Exception logged";
}

@GetMapping("/testExceptionWithEmptyMessage")
public String testExceptionWithEmptyMessage(HttpServletResponse response) {
// Test exception with empty message
logger.error("Exception with empty message test", new RuntimeException(""));
return "Exception logged";
}

@GetMapping("/testExceptionWithWhitespaceMessage")
public String testExceptionWithWhitespaceMessage(HttpServletResponse response) {
// Test exception with whitespace-only message
logger.error("Exception with whitespace message test", new IllegalArgumentException(" "));
return "Exception logged";
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

package com.microsoft.applicationinsights.smoketest;

import static com.microsoft.applicationinsights.smoketest.EnvironmentValue.TOMCAT_8_JAVA_11;
import static com.microsoft.applicationinsights.smoketest.EnvironmentValue.TOMCAT_8_JAVA_17;
import static com.microsoft.applicationinsights.smoketest.EnvironmentValue.TOMCAT_8_JAVA_21;
import static com.microsoft.applicationinsights.smoketest.EnvironmentValue.TOMCAT_8_JAVA_8;
import static org.assertj.core.api.Assertions.assertThat;

import com.microsoft.applicationinsights.smoketest.schemav2.Data;
import com.microsoft.applicationinsights.smoketest.schemav2.Envelope;
import com.microsoft.applicationinsights.smoketest.schemav2.ExceptionData;
import com.microsoft.applicationinsights.smoketest.schemav2.SeverityLevel;
import java.util.List;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;

@UseAgent
abstract class ExceptionMessageHandlingTest {

@RegisterExtension static final SmokeTestExtension testing = SmokeTestExtension.create();

@Test
@TargetUri("/testExceptionWithoutMessage")
void testExceptionWithoutMessage() throws Exception {
List<Envelope> rdList = testing.mockedIngestion.waitForItems("RequestData", 1);

Envelope rdEnvelope = rdList.get(0);
String operationId = rdEnvelope.getTags().get("ai.operation.id");
List<Envelope> edList =
testing.mockedIngestion.waitForItemsInOperation("ExceptionData", 1, operationId);

Envelope edEnvelope = edList.get(0);
ExceptionData ed = (ExceptionData) ((Data<?>) edEnvelope.getData()).getBaseData();

// Verify that exceptions without messages have their class name as the message
// This prevents the 206 error: "Field 'message' on type 'ExceptionDetails' is required but
// missing or empty"
assertThat(ed.getExceptions().get(0).getTypeName()).isEqualTo("java.lang.NullPointerException");
assertThat(ed.getExceptions().get(0).getMessage()).isEqualTo("java.lang.NullPointerException");
assertThat(ed.getExceptions().get(0).getMessage()).isNotEmpty();
assertThat(ed.getSeverityLevel()).isEqualTo(SeverityLevel.ERROR);
}

@Test
@TargetUri("/testExceptionWithEmptyMessage")
void testExceptionWithEmptyMessage() throws Exception {
List<Envelope> rdList = testing.mockedIngestion.waitForItems("RequestData", 1);

Envelope rdEnvelope = rdList.get(0);
String operationId = rdEnvelope.getTags().get("ai.operation.id");
List<Envelope> edList =
testing.mockedIngestion.waitForItemsInOperation("ExceptionData", 1, operationId);

Envelope edEnvelope = edList.get(0);
ExceptionData ed = (ExceptionData) ((Data<?>) edEnvelope.getData()).getBaseData();

// Verify that exceptions with empty messages have their class name as the message
assertThat(ed.getExceptions().get(0).getTypeName()).isEqualTo("java.lang.RuntimeException");
assertThat(ed.getExceptions().get(0).getMessage()).isEqualTo("java.lang.RuntimeException");
assertThat(ed.getExceptions().get(0).getMessage()).isNotEmpty();
assertThat(ed.getSeverityLevel()).isEqualTo(SeverityLevel.ERROR);
}

@Test
@TargetUri("/testExceptionWithWhitespaceMessage")
void testExceptionWithWhitespaceMessage() throws Exception {
List<Envelope> rdList = testing.mockedIngestion.waitForItems("RequestData", 1);

Envelope rdEnvelope = rdList.get(0);
String operationId = rdEnvelope.getTags().get("ai.operation.id");
List<Envelope> edList =
testing.mockedIngestion.waitForItemsInOperation("ExceptionData", 1, operationId);

Envelope edEnvelope = edList.get(0);
ExceptionData ed = (ExceptionData) ((Data<?>) edEnvelope.getData()).getBaseData();

// Verify that exceptions with whitespace-only messages have their class name as the message
assertThat(ed.getExceptions().get(0).getTypeName())
.isEqualTo("java.lang.IllegalArgumentException");
assertThat(ed.getExceptions().get(0).getMessage())
.isEqualTo("java.lang.IllegalArgumentException");
assertThat(ed.getExceptions().get(0).getMessage()).isNotEmpty();
assertThat(ed.getSeverityLevel()).isEqualTo(SeverityLevel.ERROR);
}

@Environment(TOMCAT_8_JAVA_8)
static class Tomcat8Java8Test extends ExceptionMessageHandlingTest {}

@Environment(TOMCAT_8_JAVA_11)
static class Tomcat8Java11Test extends ExceptionMessageHandlingTest {}

@Environment(TOMCAT_8_JAVA_17)
static class Tomcat8Java17Test extends ExceptionMessageHandlingTest {}

@Environment(TOMCAT_8_JAVA_21)
static class Tomcat8Java21Test extends ExceptionMessageHandlingTest {}
}