Skip to content

Commit 24ce66d

Browse files
authored
Fix StringIndexOutOfBoundsException (#1827)
* Fix StringIndexOutOfBoundsException * spotless * Fix test logging
1 parent 05cd9e6 commit 24ce66d

File tree

8 files changed

+135
-28
lines changed

8 files changed

+135
-28
lines changed

agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/common/Strings.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,14 @@ public static boolean isNullOrEmpty(@Nullable String string) {
3131
return string == null || string.isEmpty();
3232
}
3333

34+
public static String trimAndEmptyToNull(String str) {
35+
if (str == null) {
36+
return null;
37+
}
38+
String trimmed = str.trim();
39+
return trimmed.isEmpty() ? null : trimmed;
40+
}
41+
3442
public static Map<String, String> splitToMap(String str) {
3543
Map<String, String> map = new HashMap<>();
3644
for (String part : str.split(";")) {

agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/configuration/ConfigurationBuilder.java

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -445,7 +445,7 @@ private static String getConfigPath() {
445445
}
446446
// intentionally not checking system properties for other system properties
447447
// with the intention to keep configuration paths minimal to help with supportability
448-
return trimAndEmptyToNull(System.getProperty("applicationinsights.configuration.file"));
448+
return Strings.trimAndEmptyToNull(System.getProperty("applicationinsights.configuration.file"));
449449
}
450450

451451
private static String getWebsiteSiteNameEnvVar() {
@@ -500,21 +500,12 @@ static boolean overlayWithEnvVar(String name, boolean defaultValue) {
500500

501501
// never returns empty string (empty string is normalized to null)
502502
protected static String getSystemProperty(String name) {
503-
return trimAndEmptyToNull(System.getProperty(name));
503+
return Strings.trimAndEmptyToNull(System.getProperty(name));
504504
}
505505

506506
// never returns empty string (empty string is normalized to null)
507507
protected static String getEnvVar(String name) {
508-
return trimAndEmptyToNull(System.getenv(name));
509-
}
510-
511-
// visible for testing
512-
static String trimAndEmptyToNull(String str) {
513-
if (str == null) {
514-
return null;
515-
}
516-
String trimmed = str.trim();
517-
return trimmed.isEmpty() ? null : trimmed;
508+
return Strings.trimAndEmptyToNull(System.getenv(name));
518509
}
519510

520511
private static boolean isTrimEmpty(String value) {

agent/agent-tooling/src/main/java/com/microsoft/applicationinsights/agent/internal/exporter/Exceptions.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323

2424
import static java.util.Collections.singletonList;
2525

26+
import com.microsoft.applicationinsights.agent.internal.common.Strings;
2627
import com.microsoft.applicationinsights.agent.internal.exporter.models.TelemetryExceptionDetails;
2728
import java.util.ArrayList;
2829
import java.util.List;
@@ -45,7 +46,7 @@ public static List<TelemetryExceptionDetails> minimalParse(String str) {
4546
// at the end of the loop, current will be end of the first line
4647
if (separator != -1) {
4748
details.setTypeName(str.substring(0, separator));
48-
details.setMessage(str.substring(separator + 2, current));
49+
details.setMessage(Strings.trimAndEmptyToNull(str.substring(separator + 1, current)));
4950
} else {
5051
details.setTypeName(str.substring(0, current));
5152
}
@@ -80,10 +81,10 @@ void process(String line) {
8081
line = line.substring("Caused by: ".length());
8182
}
8283
current = new TelemetryExceptionDetails();
83-
int index = line.indexOf(": ");
84+
int index = line.indexOf(':');
8485
if (index != -1) {
8586
current.setTypeName(line.substring(0, index));
86-
current.setMessage(line.substring(index + 2));
87+
current.setMessage(Strings.trimAndEmptyToNull(line.substring(index + 1)));
8788
} else {
8889
current.setTypeName(line);
8990
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/*
2+
* ApplicationInsights-Java
3+
* Copyright (c) Microsoft Corporation
4+
* All rights reserved.
5+
*
6+
* MIT License
7+
* Permission is hereby granted, free of charge, to any person obtaining a copy of this
8+
* software and associated documentation files (the ""Software""), to deal in the Software
9+
* without restriction, including without limitation the rights to use, copy, modify, merge,
10+
* publish, distribute, sublicense, and/or sell copies of the Software, and to permit
11+
* persons to whom the Software is furnished to do so, subject to the following conditions:
12+
* The above copyright notice and this permission notice shall be included in all copies or
13+
* substantial portions of the Software.
14+
* THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
15+
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
16+
* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
17+
* FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
18+
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
19+
* DEALINGS IN THE SOFTWARE.
20+
*/
21+
22+
package com.microsoft.applicationinsights.agent.internal.common;
23+
24+
import static org.assertj.core.api.Assertions.assertThat;
25+
26+
import org.junit.jupiter.api.Test;
27+
28+
public class StringsTest {
29+
30+
@Test
31+
void testEmptyToNull() {
32+
assertThat(Strings.trimAndEmptyToNull(" ")).isNull();
33+
assertThat(Strings.trimAndEmptyToNull("")).isNull();
34+
assertThat(Strings.trimAndEmptyToNull(null)).isNull();
35+
assertThat(Strings.trimAndEmptyToNull("a")).isEqualTo("a");
36+
assertThat(Strings.trimAndEmptyToNull(" a ")).isEqualTo("a");
37+
assertThat(Strings.trimAndEmptyToNull("\t")).isNull();
38+
}
39+
}

agent/agent-tooling/src/test/java/com/microsoft/applicationinsights/agent/internal/configuration/ConfigurationBuilderTest.java

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121

2222
package com.microsoft.applicationinsights.agent.internal.configuration;
2323

24-
import static com.microsoft.applicationinsights.agent.internal.configuration.ConfigurationBuilder.trimAndEmptyToNull;
2524
import static org.assertj.core.api.Assertions.assertThat;
2625
import static org.assertj.core.api.Assertions.assertThatThrownBy;
2726

@@ -39,16 +38,6 @@ Path getConfigFilePath(String resourceName) {
3938
return file.toPath();
4039
}
4140

42-
@Test
43-
void testEmptyToNull() {
44-
assertThat(trimAndEmptyToNull(" ")).isNull();
45-
assertThat(trimAndEmptyToNull("")).isNull();
46-
assertThat(trimAndEmptyToNull(null)).isNull();
47-
assertThat(trimAndEmptyToNull("a")).isEqualTo("a");
48-
assertThat(trimAndEmptyToNull(" a ")).isEqualTo("a");
49-
assertThat(trimAndEmptyToNull("\t")).isNull();
50-
}
51-
5241
@Test
5342
void testGetConfigFilePath() {
5443
Path path = getConfigFilePath("applicationinsights.json");

agent/agent-tooling/src/test/java/com/microsoft/applicationinsights/agent/internal/exporter/ExceptionsTest.java

Lines changed: 74 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,55 @@
3232
class ExceptionsTest {
3333

3434
@Test
35-
void test() {
35+
void testMinimalParse() {
36+
// given
37+
String str = toString(new IllegalStateException("test"));
38+
39+
// when
40+
List<TelemetryExceptionDetails> list = Exceptions.minimalParse(str);
41+
42+
// then
43+
assertThat(list.size()).isEqualTo(1);
44+
45+
TelemetryExceptionDetails details = list.get(0);
46+
assertThat(details.getTypeName()).isEqualTo(IllegalStateException.class.getName());
47+
assertThat(details.getMessage()).isEqualTo("test");
48+
}
49+
50+
@Test
51+
void testMinimalParseWithNoMessage() {
52+
// given
53+
String str = toString(new IllegalStateException());
54+
55+
// when
56+
List<TelemetryExceptionDetails> list = Exceptions.minimalParse(str);
57+
58+
// then
59+
assertThat(list.size()).isEqualTo(1);
60+
61+
TelemetryExceptionDetails details = list.get(0);
62+
assertThat(details.getTypeName()).isEqualTo(IllegalStateException.class.getName());
63+
assertThat(details.getMessage()).isNull();
64+
}
65+
66+
@Test
67+
void testMinimalParseWithProblematicMessage() {
68+
// given
69+
String str = toString(new ProblematicException());
70+
71+
// when
72+
List<TelemetryExceptionDetails> list = Exceptions.minimalParse(str);
73+
74+
// then
75+
assertThat(list.size()).isEqualTo(1);
76+
77+
TelemetryExceptionDetails details = list.get(0);
78+
assertThat(details.getTypeName()).isEqualTo(ProblematicException.class.getName());
79+
assertThat(details.getMessage()).isNull();
80+
}
81+
82+
@Test
83+
void testFullParse() {
3684
// given
3785
String str = toString(new IllegalStateException("test"));
3886

@@ -48,7 +96,7 @@ void test() {
4896
}
4997

5098
@Test
51-
void testWithNoMessage() {
99+
void testFullParseWithNoMessage() {
52100
// given
53101
String str = toString(new IllegalStateException());
54102

@@ -63,6 +111,22 @@ void testWithNoMessage() {
63111
assertThat(details.getMessage()).isNull();
64112
}
65113

114+
@Test
115+
void testFullParseWithProblematicMessage() {
116+
// given
117+
String str = toString(new ProblematicException());
118+
119+
// when
120+
List<TelemetryExceptionDetails> list = Exceptions.fullParse(str);
121+
122+
// then
123+
assertThat(list.size()).isEqualTo(1);
124+
125+
TelemetryExceptionDetails details = list.get(0);
126+
assertThat(details.getTypeName()).isEqualTo(ProblematicException.class.getName());
127+
assertThat(details.getMessage()).isNull();
128+
}
129+
66130
@Test
67131
void testWithCausedBy() {
68132
// given
@@ -108,4 +172,12 @@ private static String toString(Throwable t) {
108172
t.printStackTrace(new PrintWriter(out));
109173
return out.toString();
110174
}
175+
176+
@SuppressWarnings("OverrideThrowableToString")
177+
private static class ProblematicException extends Exception {
178+
@Override
179+
public String toString() {
180+
return ProblematicException.class.getName() + ":";
181+
}
182+
}
111183
}

buildSrc/src/main/kotlin/ai.java-conventions.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ tasks.withType<Test>().configureEach {
109109
}
110110

111111
testLogging {
112+
showStandardStreams = true
112113
exceptionFormat = TestExceptionFormat.FULL
113114
}
114115
}

buildSrc/src/main/kotlin/ai.smoke-test.gradle.kts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import com.microsoft.applicationinsights.gradle.AiSmokeTestExtension
22
import gradle.kotlin.dsl.accessors._94a23f0be9141f27f052e4809bb3869b.java
3+
import org.gradle.api.tasks.testing.logging.TestExceptionFormat
34

45
plugins {
56
`java-library`
@@ -110,6 +111,11 @@ tasks {
110111
jvmArgs("-Dio.opentelemetry.javaagent.shaded.io.opentelemetry.context.enableStrictContext=true")
111112
}
112113

114+
testLogging {
115+
showStandardStreams = true
116+
exceptionFormat = TestExceptionFormat.FULL
117+
}
118+
113119
// TODO (trask) is this still a problem?
114120
//outputs.upToDateWhen { false }
115121
}

0 commit comments

Comments
 (0)