Skip to content

Commit 48984e0

Browse files
author
Bartosz Litwiniuk
committed
Merge branch 'master' into backtrace-data-models-refactor
# Conflicts: # backtrace-library/build.gradle # backtrace-library/src/main/java/backtraceio/library/base/BacktraceBase.java # backtrace-library/src/main/java/backtraceio/library/models/json/BacktraceAttributes.java # backtrace-library/src/main/java/backtraceio/library/models/json/BacktraceReport.java
2 parents ca7cda6 + 463e766 commit 48984e0

33 files changed

+1086
-364
lines changed

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
# Backtrace Android Release Notes
22

3+
## Version 3.9.0
4+
5+
- Added a support for nested and suppressed exceptions (#158)
6+
- Improved attribute performance and metrics startup (#157)
7+
- Added metrics initialization debug information (#153)
8+
- Changed Android SDK to 34 (#155)
9+
310
## Version 3.8.4
411
- Add getter method for `BacktraceReport` field in `BacktraceData` class
512
- Update libraries (GSON and androidx.test.*)

backtrace-library/build.gradle

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,11 @@ androidGitVersion {
1010
}
1111

1212
android {
13-
14-
compileSdkVersion 33
1513
namespace "backtraceio.library"
1614
defaultConfig {
1715
minSdkVersion 21
18-
targetSdkVersion 33
16+
compileSdk 34
17+
targetSdkVersion 34
1918
versionName androidGitVersion.name()
2019
versionCode androidGitVersion.code()
2120
buildConfigField("String", "VERSION_NAME", "\"${versionName}\"")
@@ -89,9 +88,10 @@ dependencies {
8988
androidTestImplementation 'androidx.test:rules:1.6.1'
9089
androidTestImplementation 'androidx.test.ext:junit:1.2.1'
9190
androidTestImplementation 'androidx.test.espresso:espresso-core:3.6.1'
92-
androidTestImplementation 'org.mockito:mockito-core:5.2.0'
93-
androidTestImplementation "org.mockito:mockito-android:2.28.2"
9491
testImplementation "com.google.guava:guava:33.3.1-jre"
92+
androidTestImplementation 'org.mockito:mockito-core:5.12.0'
93+
androidTestImplementation "org.mockito:mockito-android:5.12.0"
94+
9595
}
9696

9797
apply from: 'publish.gradle'
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package backtraceio.library;
2+
3+
import static org.junit.Assert.assertEquals;
4+
5+
import android.content.Context;
6+
import android.content.pm.PackageInfo;
7+
import android.content.pm.PackageManager;
8+
9+
import androidx.test.ext.junit.runners.AndroidJUnit4;
10+
import androidx.test.platform.app.InstrumentationRegistry;
11+
12+
import org.junit.Before;
13+
import org.junit.Test;
14+
import org.junit.runner.RunWith;
15+
16+
import backtraceio.library.common.ApplicationMetadataCache;
17+
18+
@RunWith(AndroidJUnit4.class)
19+
public class ApplicationMetadataTest {
20+
private Context context;
21+
22+
@Before
23+
public void setUp() {
24+
context = InstrumentationRegistry.getInstrumentation().getContext();
25+
// prepare instance
26+
ApplicationMetadataCache.getInstance(context);
27+
}
28+
29+
@Test
30+
public void shouldCorrectlyRetrieveApplicationName() {
31+
ApplicationMetadataCache cache = ApplicationMetadataCache.getInstance(context);
32+
assertEquals(cache.getApplicationName(), context.getOpPackageName());
33+
}
34+
35+
@Test
36+
public void shouldCorrectlyRetrieveApplicationPackageName() {
37+
ApplicationMetadataCache cache = ApplicationMetadataCache.getInstance(context);
38+
assertEquals(cache.getPackageName(), context.getOpPackageName());
39+
}
40+
41+
@Test
42+
public void shouldCorrectlyRetrieveApplicationVersion() throws PackageManager.NameNotFoundException {
43+
ApplicationMetadataCache cache = ApplicationMetadataCache.getInstance(context);
44+
PackageInfo packageInfo = context.getPackageManager().getPackageInfo(context.getOpPackageName(), 0);
45+
assertEquals(cache.getApplicationVersion(), String.valueOf(packageInfo.versionCode));
46+
}
47+
48+
}

backtrace-library/src/androidTest/java/backtraceio/library/BacktraceClientSendTest.java

Lines changed: 54 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,11 @@
2020
import org.junit.runner.RunWith;
2121

2222
import java.io.IOException;
23+
import java.util.ArrayList;
2324
import java.util.HashMap;
25+
import java.util.List;
2426
import java.util.Map;
27+
import java.util.Stack;
2528
import java.util.concurrent.TimeUnit;
2629

2730
import backtraceio.library.common.BacktraceSerializeHelper;
@@ -34,12 +37,12 @@
3437

3538
@RunWith(AndroidJUnit4.class)
3639
public class BacktraceClientSendTest {
37-
private Context context;
38-
private BacktraceCredentials credentials;
3940
private final String resultMessage = "From request handler";
4041
private final Map<String, Object> attributes = new HashMap<String, Object>() {{
4142
put("test", "value");
4243
}};
44+
private Context context;
45+
private BacktraceCredentials credentials;
4346

4447
@Before
4548
public void setUp() {
@@ -91,7 +94,13 @@ public void sendExceptionWithManyCause() {
9194

9295
final BacktraceClient backtraceClient = new BacktraceClient(context, credentials);
9396
final Waiter waiter = new Waiter();
94-
final String mainExceptionExpectedMessage = "java.io.IOException: java.lang.IllegalArgumentException: New Exception";
97+
98+
final Stack<String> expectedExceptionMessages = new Stack<String>() {{
99+
add("New Exception");
100+
add("java.lang.IllegalArgumentException: New Exception");
101+
add("java.io.IOException: java.lang.IllegalArgumentException: New Exception");
102+
}};
103+
95104
RequestHandler rh = data -> {
96105
String jsonString = BacktraceSerializeHelper.toJson(data);
97106

@@ -100,7 +109,7 @@ public void sendExceptionWithManyCause() {
100109
final JSONObject jsonObject = new JSONObject(jsonString);
101110
final JSONObject exceptionProperties = jsonObject.getJSONObject("annotations").getJSONObject("Exception properties");
102111
final String mainExceptionMessage = jsonObject.getJSONObject("annotations").getJSONObject("Exception").getString("message");
103-
112+
final String mainExceptionExpectedMessage = expectedExceptionMessages.pop();
104113
assertEquals(mainExceptionExpectedMessage, mainExceptionMessage);
105114
assertTrue(exceptionProperties.getJSONArray("stack-trace").length() > 0);
106115
assertEquals(mainExceptionExpectedMessage, exceptionProperties.get("detail-message"));
@@ -277,6 +286,46 @@ public void onEvent(BacktraceResult backtraceResult) {
277286
}
278287
}
279288

289+
@Test
290+
public void sendExceptionWithInnerException() {
291+
// GIVEN
292+
final int expectedNumberOfReports = 2;
293+
final String innerExceptionMessage = "inner exception";
294+
final String outerExceptionMessage = "outer exception";
295+
final Exception innerException = new Exception(innerExceptionMessage);
296+
final Exception outerException = new Exception(outerExceptionMessage, innerException);
297+
final List<BacktraceData> reportData = new ArrayList<>();
298+
BacktraceClient backtraceClient = new BacktraceClient(context, credentials);
299+
backtraceClient.sendInnerExceptions(true);
300+
backtraceClient.sendSuppressedExceptions(true);
301+
final Waiter waiter = new Waiter();
302+
303+
304+
backtraceClient.setOnRequestHandler(new RequestHandler() {
305+
@Override
306+
public BacktraceResult onRequest(BacktraceData data) {
307+
reportData.add(data);
308+
if (reportData.size() == expectedNumberOfReports) {
309+
waiter.resume();
310+
}
311+
return new BacktraceResult(data.getReport(), data.getReport().exception.getMessage(),
312+
BacktraceResultStatus.Ok);
313+
}
314+
});
315+
backtraceClient.send(outerException);
316+
317+
try {
318+
waiter.await(5, TimeUnit.SECONDS, 1);
319+
} catch (Exception ex) {
320+
fail(ex.getMessage());
321+
}
322+
assertEquals(expectedNumberOfReports, reportData.size());
323+
BacktraceData outerExceptionData = reportData.get(0);
324+
assertEquals(outerExceptionMessage, outerExceptionData.attributes.get("error.message"));
325+
BacktraceData innerExceptionData = reportData.get(reportData.size() - 1);
326+
assertEquals(innerExceptionMessage, innerExceptionData.attributes.get("error.message"));
327+
}
328+
280329
@Test
281330
public void sendMultipleReports() {
282331
// GIVEN
@@ -313,4 +362,4 @@ public void onEvent(BacktraceResult backtraceResult) {
313362
fail(ex.getMessage());
314363
}
315364
}
316-
}
365+
}

backtrace-library/src/androidTest/java/backtraceio/library/BacktraceClientUniqueEventTest.java

Lines changed: 0 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -400,48 +400,4 @@ public void uniqueEventUpdateAttributes() {
400400

401401
assertEquals(expectedValue, backtraceClient.metrics.getUniqueEvents().getLast().getAttributes().get(expectedKey));
402402
}
403-
404-
@Test
405-
public void uniqueEventEmptyAttributeValueShouldNotOverridePreviousValueOnUpdate() {
406-
backtraceClient.metrics.enable(new BacktraceMetricsSettings(credentials, defaultBaseUrl, 0));
407-
408-
String expectedKey = "foo";
409-
String expectedValue = "bar";
410-
411-
backtraceClient.attributes.put(expectedKey, expectedValue);
412-
assertTrue(backtraceClient.metrics.addUniqueEvent(uniqueAttributeName[0]));
413-
414-
assertEquals(uniqueAttributeName[0], backtraceClient.metrics.getUniqueEvents().getLast().getName());
415-
assertEquals(expectedValue, backtraceClient.metrics.getUniqueEvents().getLast().getAttributes().get(expectedKey));
416-
417-
backtraceClient.attributes.put(expectedKey, "");
418-
assertEquals("", backtraceClient.attributes.get(expectedKey));
419-
420-
// Force update
421-
backtraceClient.metrics.send();
422-
423-
assertEquals(expectedValue, backtraceClient.metrics.getUniqueEvents().getLast().getAttributes().get(expectedKey));
424-
}
425-
426-
@Test
427-
public void uniqueEventNullAttributeValueShouldNotOverridePreviousValueOnUpdate() {
428-
backtraceClient.metrics.enable(new BacktraceMetricsSettings(credentials, defaultBaseUrl, 0));
429-
430-
String expectedKey = "foo";
431-
String expectedValue = "bar";
432-
433-
backtraceClient.attributes.put(expectedKey, expectedValue);
434-
assertTrue(backtraceClient.metrics.addUniqueEvent(uniqueAttributeName[0]));
435-
436-
assertEquals(uniqueAttributeName[0], backtraceClient.metrics.getUniqueEvents().getLast().getName());
437-
assertEquals(expectedValue, backtraceClient.metrics.getUniqueEvents().getLast().getAttributes().get(expectedKey));
438-
439-
backtraceClient.attributes.put(expectedKey, null);
440-
assertNull(backtraceClient.attributes.get(expectedKey));
441-
442-
// Force update
443-
backtraceClient.metrics.send();
444-
445-
assertEquals(expectedValue, backtraceClient.metrics.getUniqueEvents().getLast().getAttributes().get(expectedKey));
446-
}
447403
}

backtrace-library/src/androidTest/java/backtraceio/library/metrics/BacktraceMetricsTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ public void setUp() {
5757
@Test
5858
public void addAttributesSummedEvent() {
5959
SummedEvent summedEvent = new SummedEvent(summedEventName, null);
60-
Map<String, Object> attributes = new HashMap<String, Object>() {{
60+
Map<String, String> attributes = new HashMap<String, String>() {{
6161
put("foo", "bar");
6262
}};
6363
summedEvent.addAttributes(attributes);
@@ -67,7 +67,7 @@ public void addAttributesSummedEvent() {
6767
@Test
6868
public void addAttributesUniqueEvent() {
6969
UniqueEvent uniqueEvent = new UniqueEvent(uniqueAttributeName[0], null);
70-
Map<String, Object> attributes = new HashMap<String, Object>() {{
70+
Map<String, String> attributes = new HashMap<String, String>() {{
7171
put("foo", "bar");
7272
}};
7373
uniqueEvent.update(BacktraceTimeHelper.getTimestampSeconds(), attributes);

backtrace-library/src/androidTest/java/backtraceio/library/models/UncaughtExceptionHandlerTest.java

Lines changed: 97 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
import java.lang.reflect.Field;
2020
import java.lang.reflect.InvocationTargetException;
2121
import java.lang.reflect.Modifier;
22+
import java.util.ArrayList;
23+
import java.util.List;
2224
import java.util.concurrent.TimeUnit;
2325
import java.util.concurrent.atomic.AtomicReference;
2426

@@ -31,12 +33,6 @@ public class UncaughtExceptionHandlerTest {
3133
private Context context;
3234
private BacktraceCredentials credentials;
3335

34-
@Before
35-
public void setUp() {
36-
context = InstrumentationRegistry.getInstrumentation().getContext();
37-
credentials = new BacktraceCredentials("https://example-endpoint.com/", "");
38-
}
39-
4036
private static void setRootHandler(Thread.UncaughtExceptionHandler customRootHandler, Thread.UncaughtExceptionHandler newRootHandler) {
4137
try {
4238
Field field = BacktraceExceptionHandler.class.getDeclaredField("rootHandler");
@@ -47,7 +43,6 @@ private static void setRootHandler(Thread.UncaughtExceptionHandler customRootHan
4743
}
4844
}
4945

50-
5146
private static BacktraceExceptionHandler createBacktraceExceptionHandler(BacktraceClient client) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException, InstantiationException {
5247
Constructor<BacktraceExceptionHandler> constructor = BacktraceExceptionHandler.class.getDeclaredConstructor(BacktraceClient.class);
5348
assertTrue(Modifier.isPrivate(constructor.getModifiers()));
@@ -57,6 +52,12 @@ private static BacktraceExceptionHandler createBacktraceExceptionHandler(Backtra
5752
return exceptionHandler;
5853
}
5954

55+
@Before
56+
public void setUp() {
57+
context = InstrumentationRegistry.getInstrumentation().getContext();
58+
credentials = new BacktraceCredentials("https://example-endpoint.com/", "");
59+
}
60+
6061
@Test()
6162
public void testUncaughtException() throws InvocationTargetException, NoSuchMethodException, IllegalAccessException, InstantiationException {
6263
// GIVEN
@@ -131,4 +132,93 @@ public void testUncaughtError() throws InvocationTargetException, NoSuchMethodEx
131132
assertEquals("Unhandled Exception", testedReportData.getReport().attributes.get("error.type"));
132133
assertTrue(testedReportData.getReport().exceptionTypeReport);
133134
}
135+
136+
@Test()
137+
public void testUncaughtInnerExceptionsGeneration() throws InvocationTargetException, NoSuchMethodException, IllegalAccessException, InstantiationException {
138+
// GIVEN
139+
final int expectedNumberOfExceptions = 2;
140+
final Waiter waiter = new Waiter();
141+
final String innerExceptionMessage = "Cause exception message";
142+
final Exception cause = new IllegalArgumentException(innerExceptionMessage);
143+
final String outerExceptionMessage = "Outer exception";
144+
final Exception exception = new IllegalArgumentException(outerExceptionMessage, cause);
145+
final BacktraceClient client = new BacktraceClient(context, credentials);
146+
client.sendInnerExceptions(true);
147+
client.sendSuppressedExceptions(true);
148+
149+
final List<BacktraceData> unhandledExceptionData = new ArrayList<>();
150+
client.setOnRequestHandler(data -> {
151+
unhandledExceptionData.add(data);
152+
if (unhandledExceptionData.size() == expectedNumberOfExceptions) {
153+
waiter.resume();
154+
}
155+
return new BacktraceResult(data.getReport(), data.getReport().message,
156+
BacktraceResultStatus.Ok);
157+
});
158+
159+
final BacktraceExceptionHandler handler = createBacktraceExceptionHandler(client);
160+
161+
// WHEN
162+
handler.uncaughtException(Thread.currentThread(), exception);
163+
164+
// WAIT FOR THE RESULT FROM ANOTHER THREAD
165+
try {
166+
waiter.await(5, TimeUnit.SECONDS);
167+
} catch (Exception ex) {
168+
fail(ex.getMessage());
169+
}
170+
171+
// THEN
172+
assertEquals(expectedNumberOfExceptions, unhandledExceptionData.size());
173+
174+
final BacktraceData outerException = unhandledExceptionData.get(0);
175+
final BacktraceData innerException = unhandledExceptionData.get(unhandledExceptionData.size() - 1);
176+
assertEquals(outerExceptionMessage, outerException.attributes.get("error.message"));
177+
assertEquals(innerExceptionMessage, innerException.attributes.get("error.message"));
178+
}
179+
180+
@Test()
181+
public void testUncaughtInnerExceptionsErrorAttributes() throws InvocationTargetException, NoSuchMethodException, IllegalAccessException, InstantiationException {
182+
// GIVEN
183+
final int expectedNumberOfExceptions = 2;
184+
final Waiter waiter = new Waiter();
185+
final String innerExceptionMessage = "Cause exception message";
186+
final Exception cause = new IllegalArgumentException(innerExceptionMessage);
187+
final String outerExceptionMessage = "Outer exception";
188+
final Exception exception = new IllegalArgumentException(outerExceptionMessage, cause);
189+
final BacktraceClient client = new BacktraceClient(context, credentials);
190+
client.sendInnerExceptions(true);
191+
client.sendSuppressedExceptions(true);
192+
193+
final List<BacktraceData> unhandledExceptionData = new ArrayList<>();
194+
client.setOnRequestHandler(data -> {
195+
unhandledExceptionData.add(data);
196+
if (unhandledExceptionData.size() == expectedNumberOfExceptions) {
197+
waiter.resume();
198+
}
199+
return new BacktraceResult(data.getReport(), data.getReport().message,
200+
BacktraceResultStatus.Ok);
201+
});
202+
203+
final BacktraceExceptionHandler handler = createBacktraceExceptionHandler(client);
204+
205+
// WHEN
206+
handler.uncaughtException(Thread.currentThread(), exception);
207+
208+
// WAIT FOR THE RESULT FROM ANOTHER THREAD
209+
try {
210+
waiter.await(5, TimeUnit.SECONDS);
211+
} catch (Exception ex) {
212+
fail(ex.getMessage());
213+
}
214+
215+
// THEN
216+
final BacktraceData outerException = unhandledExceptionData.get(0);
217+
final BacktraceData innerException = unhandledExceptionData.get(unhandledExceptionData.size() - 1);
218+
assertEquals(outerException.attributes.get("error.trace"), innerException.attributes.get("error.trace"));
219+
assertEquals(outerException.uuid, innerException.attributes.get("error.parent"));
220+
assertNull(outerException.attributes.get("error.parent"));
221+
assertEquals(BacktraceAttributeConsts.UnhandledExceptionAttributeType, outerException.attributes.get("error.type"));
222+
assertEquals(BacktraceAttributeConsts.UnhandledExceptionAttributeType, innerException.attributes.get("error.type"));
223+
}
134224
}

0 commit comments

Comments
 (0)