Skip to content

Commit

Permalink
Merge pull request #1180 from Instabug/dev
Browse files Browse the repository at this point in the history
Release:v12.9.0
  • Loading branch information
mzelzoghbi authored Apr 14, 2024
2 parents ee7f33d + 430c088 commit 70e349c
Show file tree
Hide file tree
Showing 57 changed files with 1,936 additions and 138 deletions.
14 changes: 7 additions & 7 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
version: 2.1

orbs:
android: circleci/android@2.0
android: circleci/android@2.5.0
advanced-checkout: vsco/advanced-checkout@1.1.0
node: circleci/node@5.1.0
node: circleci/node@5.2.0

references:
release_dependencies: &release_dependencies
Expand All @@ -26,7 +26,7 @@ commands:
steps:
- node/install:
install-yarn: true
node-version: 'v18.17.0'
node-version: 'v20.11.1'
- node/install-packages:
pkg-manager: yarn
# Network concurrency is set to 1 for installation from GitHub to work.
Expand Down Expand Up @@ -113,13 +113,13 @@ jobs:
test_android:
executor:
name: android/android-machine
tag: '2022.03.1'
tag: default
working_directory: ~/project/examples/default
environment:
INSTABUG_SOURCEMAPS_UPLOAD_DISABLE: true
steps:
- advanced-checkout/shallow-checkout
- node/install-yarn
# - node/install-yarn
- install_node_modules
- android/run-tests:
working-directory: android
Expand Down Expand Up @@ -227,13 +227,13 @@ jobs:
e2e_android:
executor:
name: android/android-machine
tag: 2022.03.1
tag: default
resource-class: large
environment:
INSTABUG_SOURCEMAPS_UPLOAD_DISABLE: true
steps:
- advanced-checkout/shallow-checkout
- node/install-yarn
# - node/install-yarn
- install_node_modules
- node/install-packages:
pkg-manager: yarn
Expand Down
12 changes: 11 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,16 @@
# Changelog

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

### Added

- Adds symbol files upload script ([#1137](https://github.com/Instabug/Instabug-React-Native/pull/1137))
- Support enabling NDK crash capturing on Android ([#1132](https://github.com/Instabug/Instabug-React-Native/pull/1132)).

### Changed

- Bump Instabug Android SDK to v12.9.0 ([#1168](https://github.com/Instabug/Instabug-React-Native/pull/1168)). [See release notes](https://github.com/Instabug/android/releases/tag/v12.9.0).
- Bump Instabug iOS SDK to v12.9.0 ([#1168](https://github.com/Instabug/Instabug-React-Native/pull/1168)). [See release notes](https://github.com/instabug/instabug-ios/releases/tag/12.9.0).

### Fixed

Expand Down
2 changes: 1 addition & 1 deletion android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ android {
minSdkVersion getExtOrDefault('minSdkVersion').toInteger()
targetSdkVersion getExtOrDefault('targetSdkVersion').toInteger()
versionCode 1
versionName "12.8.0"
versionName "12.9.0"
multiDexEnabled true
ndk {
abiFilters "armeabi-v7a", "x86"
Expand Down
2 changes: 1 addition & 1 deletion android/native.gradle
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
project.ext.instabug = [
version: '12.8.0'
version: '12.9.0'
]

dependencies {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ public void run() {
}

/**
* Send Apm network log by Reflection
* Send Apm network log by Reflection
*/
@ReactMethod
public void networkLog(String networkData) throws JSONException {
Expand All @@ -242,8 +242,8 @@ public void networkLog(String networkData) throws JSONException {
final Integer statusCode = (Integer) jsonObject.get("responseCode");
final long requestDuration = ((Number) jsonObject.get("duration")).longValue();
final long requestStartTime = ((Number) jsonObject.get("startTime")).longValue() * 1000;
final String requestHeaders = (String) jsonObject.get("requestHeaders").toString();
final String responseHeaders = (String) jsonObject.get("responseHeaders").toString();
final String requestHeaders = (String) jsonObject.get("requestHeaders").toString();
final String responseHeaders = (String) jsonObject.get("responseHeaders").toString();
final String errorMessage;
if(errorDomain.equals("")) {
errorMessage = null;
Expand All @@ -254,25 +254,21 @@ public void networkLog(String networkData) throws JSONException {
String gqlQueryName = null;
if(jsonObject.has("gqlQueryName")){
gqlQueryName = (String) jsonObject.get("gqlQueryName");
}
}
final String serverErrorMessage = (String) jsonObject.get("serverErrorMessage");

try {
Method method = getMethod(Class.forName("com.instabug.apm.networking.APMNetworkLogger"), "log", long.class, long.class, String.class, String.class, long.class, String.class, String.class, String.class, String.class, String.class, long.class, int.class, String.class, String.class, String.class, String.class);
if (method != null) {
method.invoke(apmNetworkLogger, requestStartTime, requestDuration, requestHeaders, requestBody, requestBodySize, requestMethod, requestUrl, requestContentType, responseHeaders, responseBody, responseBodySize, statusCode, responseContentType, errorMessage, gqlQueryName, serverErrorMessage);
} else {
Log.e("IB-CP-Bridge", "apmNetworkLogByReflection was not found by reflection");
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
} catch (Throwable e) {
e.printStackTrace();
}
}
catch(Exception e) {
catch(Throwable e) {
e.printStackTrace();
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,28 @@ public void run() {
}
}
});
}

/**
* Enables and disables capturing native C++ NDK crash reporting.
*
* @param isEnabled boolean indicating enabled or disabled.
*/
@ReactMethod
public void setNDKCrashesEnabled(final boolean isEnabled) {
MainThreadHandler.runOnMainThread(new Runnable() {
@Override
public void run() {
try {
if (isEnabled) {
CrashReporting.setNDKCrashesState(Feature.State.ENABLED);
} else {
CrashReporting.setNDKCrashesState(Feature.State.DISABLED);
}
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,85 @@
package com.instabug.reactlibrary;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.mockStatic;

import android.os.Looper;

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

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.mockito.MockedStatic;
import org.mockito.Mockito;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;


public class RNInstabugCrashReportingModuleTest {
private final RNInstabugCrashReportingModule rnModule = new RNInstabugCrashReportingModule(null);

// Mock Objects
private MockedStatic<Looper> mockLooper;
private MockedStatic<MainThreadHandler> mockMainThreadHandler;
private MockedStatic<CrashReporting> mockCrashReporting;


@Before
public void mockMainThreadHandler() throws Exception {
// Mock static functions
mockLooper = mockStatic(Looper.class);
mockMainThreadHandler = mockStatic(MainThreadHandler.class);
mockCrashReporting = mockStatic(CrashReporting.class);
// Mock Looper class
Looper mockMainThreadLooper = mock(Looper.class);
Mockito.when(Looper.getMainLooper()).thenReturn(mockMainThreadLooper);


// Override runOnMainThread
Answer<Boolean> handlerPostAnswer = new Answer<Boolean>() {
@Override
public Boolean answer(InvocationOnMock invocation) throws Throwable {
invocation.getArgument(0, Runnable.class).run();
return true;
}
};
Mockito.doAnswer(handlerPostAnswer).when(MainThreadHandler.class);
MainThreadHandler.runOnMainThread(any(Runnable.class));
}

@After
public void tearDown() {
// Remove static mocks
mockLooper.close();
mockMainThreadHandler.close();
mockCrashReporting.close();
}

/********Crashes*********/

@Test
public void testSetNDKCrashesEnabledGivenTrue() {
// when
rnModule.setNDKCrashesEnabled(true);

//then
mockCrashReporting.verify(() -> CrashReporting.setNDKCrashesState(Feature.State.ENABLED));
}

@Test
public void testSetNDKCrashesEnabledGivenFalse() {
// when
rnModule.setNDKCrashesEnabled(false);

//then
mockCrashReporting.verify(() -> CrashReporting.setNDKCrashesState(Feature.State.DISABLED));
}

@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 @@ -10,6 +10,7 @@
import com.facebook.react.bridge.WritableMap;
import com.instabug.chat.Replies;
import com.instabug.library.Feature;
import com.instabug.reactlibrary.utils.InstabugUtil;
import com.instabug.reactlibrary.utils.MapUtil;
import com.instabug.reactlibrary.utils.MainThreadHandler;

Expand Down Expand Up @@ -42,13 +43,15 @@ public class RNInstabugRepliesModuleTest {
private MockedStatic<Looper> mockLooper;
private MockedStatic <MainThreadHandler> mockMainThreadHandler;
private MockedStatic <Replies> mockReplies;
private MockedStatic <InstabugUtil> mockInstabugUtil;

@Before
public void mockMainThreadHandler() throws Exception {
// Mock static functions
mockReplies = mockStatic(Replies.class);
mockLooper = mockStatic(Looper.class);
mockMainThreadHandler = mockStatic(MainThreadHandler.class);
mockInstabugUtil = mockStatic(InstabugUtil.class);

// Mock Looper class
Looper mockMainThreadLooper = mock(Looper.class);
Expand All @@ -71,6 +74,7 @@ public void tearDown() {
mockLooper.close();
mockMainThreadHandler.close();
mockReplies.close();
mockInstabugUtil.close();
}

/********Replies*********/
Expand Down
88 changes: 88 additions & 0 deletions cli/UploadSoFiles.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import axios from 'axios';
import { Command, Option } from 'commander';
import FormData from 'form-data';
import fs from 'fs';

interface UploadSoFilesOptions {
arch: 'x86' | 'x86_64' | 'arm64-v8a' | 'armeabi-v7a';
file: string;
token: string;
name: string;
api_key: string;
}
/**
* This script uploads .so files to the specified endpoint used in NDK crash reporting.
* Usage: node upload-so-files.js --arch <arch> --file <path> --api_key <key> --token <token> --name <name>
*/

export const UploadSoFilesCommand = new Command();

UploadSoFilesCommand.name('upload-so-files')
.addOption(
new Option('-arch, --arch <value>', 'arch')
.choices(['x86', 'x86_64', 'arm64-v8a', 'armeabi-v7a'])
.makeOptionMandatory(),
)
.addOption(
new Option(
'-f, --file <path>',
'The path of the symbol files in Zip format',
).makeOptionMandatory(),
)
.addOption(new Option('--api_key <value>', 'Your App key').makeOptionMandatory())
.addOption(
new Option('-t, --token <value>', 'Your App Token')
.env('INSTABUG_APP_TOKEN')
.makeOptionMandatory(),
)
.addOption(
new Option('-n, --name <value>', 'The app version name')
.env('INSTABUG_APP_VERSION_NAME')
.makeOptionMandatory(),
)
.action(function (this: Command) {
const options = this.opts<UploadSoFilesOptions>();
UploadSoFiles(options);
})
.showHelpAfterError();

const UploadSoFiles = async (opts: UploadSoFilesOptions) => {
const fileName = opts.file;
if (fileName == null) {
console.error('Failed to upload So Files: invalid file path');
process.exit(1);
}

if (fs.existsSync(fileName) === false) {
console.error('Failed to upload So Files: File not found');
process.exit(1);
}
var fileExt = fileName.split('.').pop();

if (fileExt !== 'zip') {
console.error('Failed to upload So Files: You can only upload ZIP files');
process.exit(1);
}

const fileBlob = fs.readFileSync(opts.file);

const form = new FormData();
form.append('app_version', opts.name);
form.append('so_file', fileBlob, fileName);
form.append('application_token', opts.token);
form.append('api_key', opts.api_key);
form.append('arch', opts.arch);

console.log('Uploading So files...');
const uploadEndpoint = 'https://api.instabug.com/api/web/public/so_files';
try {
await axios.post(uploadEndpoint, form, {
headers: form.getHeaders(),
});

console.log(`Successfully uploaded So Files for version: ${opts.name} with arch ${opts.arch}`);
} catch (err) {
console.error('Failed to upload So Files:', axios.isAxiosError(err) ? err.response?.data : err);
process.exit(1);
}
};
4 changes: 3 additions & 1 deletion cli/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import { Command } from 'commander';

import { uploadSourcemapsCommand } from './UploadSourcemaps';
import { UploadSoFilesCommand } from './UploadSoFiles';

const program = new Command();

Expand All @@ -10,6 +11,7 @@ program
.version('1.0.0-beta1')
.description('A CLI for uploading source maps to Instabug dashboard.')
.usage('[command]')
.addCommand(uploadSourcemapsCommand);
.addCommand(uploadSourcemapsCommand)
.addCommand(UploadSoFilesCommand);

program.parse(process.argv);
1 change: 1 addition & 0 deletions examples/default/.env
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
GOOGLE_MAPS_API_KEY = API_KEY
Loading

0 comments on commit 70e349c

Please sign in to comment.