Skip to content

feat: enhance non-fatals support #1194

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 24 commits into from
Jun 4, 2024
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
5185cb6
add non fatal api
ahmedAlaaInstabug Apr 25, 2024
bfed04a
add non fatal api
ahmedAlaaInstabug Apr 25, 2024
4d16686
fix android_testing issue
ahmedAlaaInstabug Apr 26, 2024
e8260b1
fix android_testing issue
ahmedAlaaInstabug Apr 26, 2024
667505d
fix android_testing issue
ahmedAlaaInstabug Apr 27, 2024
559cc5f
feat: add non fatal api
ahmedAlaaInstabug Apr 28, 2024
27b4e2e
fix pr comments
ahmedAlaaInstabug Apr 30, 2024
6055f81
fix pr comments
ahmedAlaaInstabug Apr 30, 2024
b8f6157
fix pr comments
ahmedAlaaInstabug Apr 30, 2024
771a919
fix: use correct diff link for v13.0.0, v12.9.0 releases (#1198)
a7medev Apr 30, 2024
2288041
Merge remote-tracking branch 'refs/remotes/origin/dev' into feat/add-…
ahmedAlaaInstabug Apr 30, 2024
5dadcf1
fix: PR comments
ahmedAlaaInstabug Apr 30, 2024
b7f10bc
fix: PR comments
ahmedAlaaInstabug Apr 30, 2024
de0a12a
fix: PR comments
ahmedAlaaInstabug Apr 30, 2024
4a81db8
Merge remote-tracking branch 'origin/master' into feat/add-non-fatal-api
ahmedAlaaInstabug May 23, 2024
648936f
extra logs for injazat 11495
ahmedAlaaInstabug May 23, 2024
4c46823
fix: mapping non-fatal type
ahmedAlaaInstabug May 26, 2024
963af0e
fix: conflict issue
ahmedAlaaInstabug May 27, 2024
f7fd035
upgrade ios version
ahmedAlaaInstabug May 30, 2024
ef1519a
Merge remote-tracking branch 'origin/dev' into feat/add-non-fatal-api
ahmedAlaaInstabug Jun 4, 2024
87f13f2
Update Podfile
ahmedAlaaInstabug Jun 4, 2024
1bcb9c0
merge
ahmedAlaaInstabug Jun 4, 2024
307a9b9
Merge remote-tracking branch 'origin/feat/add-non-fatal-api' into fea…
ahmedAlaaInstabug Jun 4, 2024
01a981c
merge
ahmedAlaaInstabug Jun 4, 2024
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
10 changes: 8 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
# Changelog

## [13.0.0](https://github.com/Instabug/Instabug-React-Native/compare/v12.9.0...dev) (April 19, 2024)
## [Unreleased](https://github.com/Instabug/Instabug-React-Native/compare/v13.0.0...dev)

### Added

- Add support for passing a grouping fingerprint, error level, and user attributes to the `CrashReporting.reportError` non-fatals API ([#1194](https://github.com/Instabug/Instabug-React-Native/pull/1194)).

## [13.0.0](https://github.com/Instabug/Instabug-React-Native/compare/v12.9.0...v13.0.0) (April 19, 2024)

### Added

Expand All @@ -12,7 +18,7 @@
- Bump Instabug iOS SDK to v13.0.0 ([#1189](https://github.com/Instabug/Instabug-React-Native/pull/1189)). [See release notes](https://github.com/instabug/instabug-ios/releases/tag/13.0.0).
- Bump Instabug Android SDK to v13.0.0 ([#1188](https://github.com/Instabug/Instabug-React-Native/pull/1188)). [See release notes](https://github.com/Instabug/android/releases/tag/v13.0.0).

## [12.9.0](https://github.com/Instabug/Instabug-React-Native/compare/v12.8.0...dev)(April 2, 2024)
## [12.9.0](https://github.com/Instabug/Instabug-React-Native/compare/v12.8.0...v12.9.0) (April 2, 2024)

### Added

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import com.instabug.bug.BugReporting;
import com.instabug.bug.invocation.Option;
import com.instabug.crash.models.IBGNonFatalException;
import com.instabug.featuresrequest.ActionType;
import com.instabug.library.InstabugColorTheme;
import com.instabug.library.InstabugCustomTextPlaceHolder.Key;
Expand Down Expand Up @@ -54,11 +55,19 @@ static Map<String, Object> getAll() {
putAll(extendedBugReportStates);
putAll(reproModes);
putAll(sdkLogLevels);
putAll(nonFatalExceptionLevel);
putAll(locales);
putAll(placeholders);
}};
}

public static ArgsMap<IBGNonFatalException.Level> nonFatalExceptionLevel = new ArgsMap<IBGNonFatalException.Level>() {{
put("nonFatalErrorTypeCritical", IBGNonFatalException.Level.CRITICAL);
put("nonFatalErrorTypeError", IBGNonFatalException.Level.ERROR);
put("nonFatalErrorTypeWarning", IBGNonFatalException.Level.WARNING);
put("nonFatalErrorTypeInfo", IBGNonFatalException.Level.INFO);
}};

static ArgsMap<InstabugInvocationEvent> invocationEvents = new ArgsMap<InstabugInvocationEvent>() {{
put("invocationEventNone", InstabugInvocationEvent.NONE);
put("invocationEventShake", InstabugInvocationEvent.SHAKE);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,24 @@

import static com.instabug.reactlibrary.utils.InstabugUtil.getMethod;

import androidx.annotation.NonNull;

import com.facebook.react.bridge.Promise;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.ReadableMap;
import com.instabug.crash.CrashReporting;
import com.instabug.crash.models.IBGNonFatalException;
import com.instabug.library.Feature;
import com.instabug.reactlibrary.utils.MainThreadHandler;

import org.json.JSONObject;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
Expand Down Expand Up @@ -79,41 +85,61 @@ public void run() {
* Send handled JS error object
*
* @param exceptionObject Exception object to be sent to Instabug's servers
* @param userAttributes (Optional) extra user attributes attached to the crash
* @param fingerprint (Optional) key used to customize how crashes are grouped together
* @param levelType different severity levels for errors
*/
@ReactMethod
public void sendHandledJSCrash(final String exceptionObject) {
public void sendHandledJSCrash(final String exceptionObject, @Nullable ReadableMap userAttributes, @Nullable String fingerprint, @Nullable String levelType) {
try {
JSONObject jsonObject = new JSONObject(exceptionObject);
sendJSCrashByReflection(jsonObject, true, null);
} catch (Exception e) {
MainThreadHandler.runOnMainThread(new Runnable() {
@Override
public void run() {
try {
Method method = getMethod(Class.forName("com.instabug.crash.CrashReporting"), "reportException", JSONObject.class, boolean.class,
Map.class, JSONObject.class, IBGNonFatalException.Level.class);
if (method != null) {
IBGNonFatalException.Level nonFatalExceptionLevelType = ArgsRegistry.nonFatalExceptionLevel.getOrDefault(levelType, IBGNonFatalException.Level.ERROR);
method.invoke(null, jsonObject, true, userAttributes == null ? null : userAttributes.toHashMap(), fingerprint == null ? null : CrashReporting.getFingerprintObject(fingerprint), nonFatalExceptionLevelType);

RNInstabugReactnativeModule.clearCurrentReport();
}
} catch (ClassNotFoundException | IllegalAccessException |
InvocationTargetException e) {
e.printStackTrace();
}
}
});
} catch (Throwable e) {
e.printStackTrace();
}
}

private void sendJSCrashByReflection(final JSONObject exceptionObject, final boolean isHandled, @Nullable final Runnable onComplete) {
MainThreadHandler.runOnMainThread(new Runnable() {
@Override
public void run() {
try {
Method method = getMethod(Class.forName("com.instabug.crash.CrashReporting"), "reportException", JSONObject.class, boolean.class);
if (method != null) {
method.invoke(null, exceptionObject, isHandled);
RNInstabugReactnativeModule.clearCurrentReport();
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} finally {
if (onComplete != null) {
onComplete.run();
}
}
}
});
}
private void sendJSCrashByReflection(final JSONObject exceptionObject, final boolean isHandled, @Nullable final Runnable onComplete) {
MainThreadHandler.runOnMainThread(new Runnable() {
@Override
public void run() {
try {
Method method = getMethod(Class.forName("com.instabug.crash.CrashReporting"), "reportException", JSONObject.class, boolean.class);
if (method != null) {
method.invoke(null, exceptionObject, isHandled);
RNInstabugReactnativeModule.clearCurrentReport();
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} finally {
if (onComplete != null) {
onComplete.run();
}
}
}
});
}

/**
* Enables and disables capturing native C++ NDK crash reporting.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,25 @@
package com.instabug.reactlibrary;

import static com.instabug.crash.CrashReporting.getFingerprintObject;
import static com.instabug.reactlibrary.util.GlobalMocks.reflected;
import static org.mockito.AdditionalMatchers.cmpEq;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.same;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.mockStatic;

import android.os.Looper;

import com.instabug.crash.CrashReporting;
import com.instabug.crash.models.IBGNonFatalException;
import com.instabug.library.Feature;
import com.instabug.reactlibrary.util.GlobalMocks;
import com.instabug.reactlibrary.util.MockReflected;
import com.instabug.reactlibrary.utils.MainThreadHandler;

import org.json.JSONException;
import org.json.JSONObject;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
Expand All @@ -19,6 +28,9 @@
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;

import java.util.HashMap;
import java.util.Map;


public class RNInstabugCrashReportingModuleTest {
private final RNInstabugCrashReportingModule rnModule = new RNInstabugCrashReportingModule(null);
Expand All @@ -38,6 +50,7 @@ public void mockMainThreadHandler() throws Exception {
// Mock Looper class
Looper mockMainThreadLooper = mock(Looper.class);
Mockito.when(Looper.getMainLooper()).thenReturn(mockMainThreadLooper);
GlobalMocks.setUp();


// Override runOnMainThread
Expand All @@ -58,6 +71,8 @@ public void tearDown() {
mockLooper.close();
mockMainThreadHandler.close();
mockCrashReporting.close();
GlobalMocks.close();

}

/********Crashes*********/
Expand All @@ -80,6 +95,18 @@ public void testSetNDKCrashesEnabledGivenFalse() {
mockCrashReporting.verify(() -> CrashReporting.setNDKCrashesState(Feature.State.DISABLED));
}

@Test
public void testSendNonFatalError() {
String jsonCrash = "{}";
boolean isHandled = true;
String fingerPrint = "test";
String level = ArgsRegistry.nonFatalExceptionLevel.keySet().iterator().next();
JSONObject expectedFingerprint = getFingerprintObject(fingerPrint);
IBGNonFatalException.Level expectedLevel = ArgsRegistry.nonFatalExceptionLevel.get(level);
rnModule.sendHandledJSCrash(jsonCrash, null, fingerPrint, level);
reflected.verify(() -> MockReflected.reportException(any(JSONObject.class), eq(isHandled), eq(null), eq(expectedFingerprint), eq(expectedLevel)));
}

@Test
public void givenString$sendHandledJSCrash_whenQuery_thenShouldCallNativeApiWithArgs() throws Exception {
// JSONObject json = mock(JSONObject.class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@

import android.util.Log;

import com.instabug.crash.models.IBGNonFatalException;
import com.instabug.reactlibrary.utils.InstabugUtil;

import org.json.JSONObject;
import org.mockito.MockedStatic;

import java.lang.reflect.Method;
Expand Down Expand Up @@ -37,6 +39,14 @@ public static void setUp() throws NoSuchMethodException {
reflection
.when(() -> InstabugUtil.getMethod(Class.forName("com.instabug.library.util.InstabugDeprecationLogger"), "setBaseUrl", String.class))
.thenReturn(mSetBaseUrl);

// reportException mock
Method mCrashReportException = MockReflected.class.getDeclaredMethod("reportException", JSONObject.class, boolean.class, java.util.Map.class, JSONObject.class, IBGNonFatalException.Level.class);
mCrashReportException.setAccessible(true);
reflection
.when(() -> InstabugUtil.getMethod(Class.forName("com.instabug.crash.CrashReporting"), "reportException", JSONObject.class,
boolean.class, java.util.Map.class, JSONObject.class, IBGNonFatalException.Level.class))
.thenReturn(mCrashReportException);
}

public static void close() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
package com.instabug.reactlibrary.util;

import com.instabug.crash.models.IBGNonFatalException;

import org.json.JSONObject;

import java.util.Map;

/**
* Includes fake implementations of methods called by reflection.
* Used to verify whether or not a private methods was called.
Expand All @@ -16,4 +22,9 @@ public static void setCurrentPlatform(int platform) {}
* Instabug.util.InstabugDeprecationLogger.setBaseUrl
*/
public static void setBaseUrl(String baseUrl) {}
/**
* CrashReporting.reportException
*/
public static void reportException(JSONObject exception, boolean isHandled, Map userAttributes, JSONObject fingerPrint, IBGNonFatalException.Level level) {}

}
10 changes: 10 additions & 0 deletions examples/default/ios/InstabugExample.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
9A3D962AB03F97E25566779F /* Pods-InstabugExample.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InstabugExample.debug.xcconfig"; path = "Target Support Files/Pods-InstabugExample/Pods-InstabugExample.debug.xcconfig"; sourceTree = "<group>"; };
BAED0D0441A708AE2390E153 /* libPods-InstabugExample.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-InstabugExample.a"; sourceTree = BUILT_PRODUCTS_DIR; };
BD54B44E2DF85672BB2D4DEE /* Pods-InstabugExample.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InstabugExample.release.xcconfig"; path = "Target Support Files/Pods-InstabugExample/Pods-InstabugExample.release.xcconfig"; sourceTree = "<group>"; };
BE3328762BDACE030078249A /* IBGCrashReporting+CP.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "IBGCrashReporting+CP.h"; sourceTree = "<group>"; };
C3C8C24386310A3120006604 /* CrashReportingExampleModule.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CrashReportingExampleModule.m; sourceTree = "<group>"; };
C3C8C784EADC037C5A752B94 /* CrashReportingExampleModule.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CrashReportingExampleModule.h; sourceTree = "<group>"; };
CC3DF8852A1DFC99003E9914 /* InstabugCrashReportingTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = InstabugCrashReportingTests.m; sourceTree = "<group>"; };
Expand Down Expand Up @@ -91,6 +92,7 @@
00E356EF1AD99517003FC87E /* InstabugTests */ = {
isa = PBXGroup;
children = (
BE3328752BDACE030078249A /* Util */,
CC3DF8892A1DFC99003E9914 /* IBGConstants.h */,
CC3DF88D2A1DFC9A003E9914 /* IBGConstants.m */,
CC3DF88C2A1DFC99003E9914 /* InstabugAPMTests.m */,
Expand Down Expand Up @@ -181,6 +183,14 @@
path = Pods;
sourceTree = "<group>";
};
BE3328752BDACE030078249A /* Util */ = {
isa = PBXGroup;
children = (
BE3328762BDACE030078249A /* IBGCrashReporting+CP.h */,
);
path = Util;
sourceTree = "<group>";
};
C3C8C1DDCEA91410F27A3683 /* native */ = {
isa = PBXGroup;
children = (
Expand Down
24 changes: 24 additions & 0 deletions examples/default/ios/InstabugTests/InstabugCrashReportingTests.m
Original file line number Diff line number Diff line change
@@ -1,15 +1,21 @@
#import <XCTest/XCTest.h>
#import "Instabug/Instabug.h"
#import "InstabugCrashReportingBridge.h"
#import "OCMock/OCMock.h"
#import "Util/IBGCrashReporting+CP.h"

@interface InstabugCrashReportingTests : XCTestCase
@property (nonatomic, retain) InstabugCrashReportingBridge *bridge;
@property (nonatomic, strong) id mCrashReporting;

@end

@implementation InstabugCrashReportingTests

- (void)setUp {
self.bridge = [[InstabugCrashReportingBridge alloc] init];
self.mCrashReporting = OCMClassMock([IBGCrashReporting class]);

}

- (void)testSetEnabled {
Expand All @@ -20,4 +26,22 @@ - (void)testSetEnabled {
XCTAssertFalse(IBGCrashReporting.enabled);
}

- (void)testSendNonFatalErrorJsonCrash {
NSDictionary<NSString *,NSString * > *jsonCrash = @{};
NSString *fingerPrint = @"fingerprint";
RCTPromiseResolveBlock resolve = ^(id result) {};
RCTPromiseRejectBlock reject = ^(NSString *code, NSString *message, NSError *error) {};
NSDictionary *userAttributes = @{ @"key" : @"value", };
IBGNonFatalLevel ibgNonFatalLevel = IBGNonFatalLevelInfo;


[self.bridge sendHandledJSCrash:jsonCrash userAttributes:userAttributes fingerprint:fingerPrint nonFatalExceptionLevel:ibgNonFatalLevel resolver:resolve rejecter:reject];

OCMVerify([self.mCrashReporting cp_reportNonFatalCrashWithStackTrace:jsonCrash
level:IBGNonFatalLevelInfo
groupingString:fingerPrint
userAttributes:userAttributes
]);
}

@end
13 changes: 13 additions & 0 deletions examples/default/ios/InstabugTests/Util/IBGCrashReporting+CP.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#import <Instabug/Instabug.h>


@interface IBGCrashReporting (CP)

+ (void)cp_reportFatalCrashWithStackTrace:(NSDictionary*)stackTrace;

+ (void)cp_reportNonFatalCrashWithStackTrace:(NSDictionary*)stackTrace
level:(IBGNonFatalLevel)level
groupingString:(NSString *)groupingString
userAttributes:(NSDictionary<NSString *, NSString*> *)userAttributes;
@end

2 changes: 2 additions & 0 deletions examples/default/ios/Podfile
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ target 'InstabugExample' do
target 'InstabugTests' do
inherit! :complete
pod 'OCMock'
pod 'Instabug', :podspec => 'https://ios-releases.instabug.com/custom/feature-crash-reporting-support-non-fatal/12.7.1/Instabug.podspec'

# Pods for testing
end

Expand Down
Loading