Skip to content
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

Add stopSession() and resumeSession() to Client #429

Merged
merged 19 commits into from
Feb 27, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
d031a9c
feat: add stopSession() and resumeSession() to Client
fractalwrench Feb 13, 2019
19a2ef9
test: add mazerunner scenarios for stopping/resuming a session
fractalwrench Feb 13, 2019
0d07dfe
test: add mazerunner scenarios to verify that fatal errors contain se…
fractalwrench Feb 14, 2019
47898c6
feat: implement stopping sessions for NDK
fractalwrench Feb 14, 2019
3fd8417
feat: update START_SESSION ndk message to include handled count
fractalwrench Feb 15, 2019
9e86464
feat: add stopSession and resumeSession to bugsnag interface
fractalwrench Feb 18, 2019
7d5253e
refactor: avoid adding additional field to bugsnag_report when stoppi…
fractalwrench Feb 18, 2019
2fd81c8
refactor: address review feedback by increasing test coverage and inl…
fractalwrench Feb 18, 2019
d8eb89d
Merge pull request #432 from bugsnag/stop-sessions-ndk
fractalwrench Feb 18, 2019
c4f52be
docs: update javadoc for session API to match docs repo
fractalwrench Feb 18, 2019
62954c7
tests: Update locked version of maze-runner
Cawllec Feb 19, 2019
f3ec09a
tests: Add session id & time comparison to stoppedSessions
Cawllec Feb 19, 2019
c3be0e4
test: reorganise test order
fractalwrench Feb 19, 2019
c1b89bc
docs: add changelog entry
fractalwrench Feb 19, 2019
9988dc5
tests: Add new session scenario to session_stopping feature
Cawllec Feb 19, 2019
8c90a00
tests: Fix tests comment
Cawllec Feb 19, 2019
6181d68
Merge pull request #430 from bugsnag/stop-sessions-mazerunner-tests
fractalwrench Feb 19, 2019
c1cd182
test: wait for session scenarios to send session before crashing
fractalwrench Feb 25, 2019
eeed649
Merge pull request #435 from bugsnag/fix-ci
fractalwrench Feb 26, 2019
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
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# Changelog

## 4.X.X (TBD)

### Enhancements

* Add stopSession() and resumeSession() to Client
[#429](https://github.com/bugsnag/bugsnag-android/pull/429)

## 4.11.0 (2019-01-22)

### Enhancements
Expand Down
16 changes: 9 additions & 7 deletions Gemfile.lock
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
GIT
remote: https://github.com/bugsnag/maze-runner
revision: 24f53756011b1247a166b70fe65ddf1c40b4fc89
revision: 6f5af2c98c6fa1cfb07d6466a5cf3eaca5dcbc90
specs:
bugsnag-maze-runner (1.0.0)
cucumber (~> 3.1.0)
cucumber-expressions (= 5.0.15)
minitest (~> 5.0)
os (~> 1.0.0)
rack (~> 2.0.0)
rake (~> 12.3.0)
test-unit (~> 3.2.0)
Expand Down Expand Up @@ -34,17 +35,18 @@ GEM
cucumber-wire (0.0.1)
diff-lcs (1.3)
gherkin (5.1.0)
method_source (0.9.0)
method_source (0.9.2)
minitest (5.11.3)
multi_json (1.13.1)
multi_test (0.1.2)
os (1.0.0)
power_assert (1.1.3)
pry (0.11.3)
pry (0.12.2)
coderay (~> 1.1.0)
method_source (~> 0.9.0)
rack (2.0.5)
rake (12.3.1)
test-unit (3.2.8)
rack (2.0.6)
rake (12.3.2)
test-unit (3.2.9)
power_assert

PLATFORMS
Expand All @@ -55,4 +57,4 @@ DEPENDENCIES
pry

BUNDLED WITH
1.16.2
1.16.1
20 changes: 20 additions & 0 deletions features/fixtures/mazerunner/src/main/cpp/bugsnags.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,26 @@ Java_com_bugsnag_android_mazerunner_scenarios_CXXAutoContextScenario_activate(JN
(char *)"This is a new world", BSG_SEVERITY_INFO);
}

JNIEXPORT int JNICALL
Java_com_bugsnag_android_mazerunner_scenarios_CXXStartSessionScenario_crash(JNIEnv *env,
jobject instance,
jint value) {
int x = 22;
if (x > 0)
__builtin_trap();
return 338;
}

JNIEXPORT int JNICALL
Java_com_bugsnag_android_mazerunner_scenarios_CXXStopSessionScenario_crash(JNIEnv *env,
jobject instance,
jint value) {
int x = 22552;
if (x > 0)
__builtin_trap();
return 555;
}

JNIEXPORT int JNICALL
Java_com_bugsnag_android_mazerunner_scenarios_CXXUpdateContextCrashScenario_crash(JNIEnv *env,
jobject instance,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package com.bugsnag.android.mazerunner.scenarios;

import android.content.Context;
import android.os.Handler;

import com.bugsnag.android.Bugsnag;
import com.bugsnag.android.Configuration;

import android.support.annotation.NonNull;

public class CXXStartSessionScenario extends Scenario {
static {
System.loadLibrary("bugsnag-ndk");
System.loadLibrary("monochrome");
System.loadLibrary("entrypoint");
}

private Handler handler = new Handler();

public native int crash(int counter);

public CXXStartSessionScenario(@NonNull Configuration config, @NonNull Context context) {
super(config, context);
config.setAutoCaptureSessions(false);
}

@Override
public void run() {
super.run();
String metadata = getEventMetaData();

if (metadata == null || !metadata.equals("non-crashy")) {
Bugsnag.getClient().startSession();

handler.postDelayed(new Runnable() {
@Override
public void run() {
crash(0);
}
}, 8000);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package com.bugsnag.android.mazerunner.scenarios;

import android.content.Context;
import android.os.Handler;

import com.bugsnag.android.Bugsnag;
import com.bugsnag.android.Configuration;

import android.support.annotation.NonNull;

public class CXXStopSessionScenario extends Scenario {
static {
System.loadLibrary("bugsnag-ndk");
System.loadLibrary("monochrome");
System.loadLibrary("entrypoint");
}

private Handler handler = new Handler();

public native int crash(int counter);

public CXXStopSessionScenario(@NonNull Configuration config, @NonNull Context context) {
super(config, context);
config.setAutoCaptureSessions(false);
}

@Override
public void run() {
super.run();
String metadata = getEventMetaData();

if (metadata == null || !metadata.equals("non-crashy")) {
Bugsnag.getClient().startSession();
Bugsnag.getClient().stopSession();

handler.postDelayed(new Runnable() {
@Override
public void run() {
crash(0);
}
}, 8000);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package com.bugsnag.android.mazerunner.scenarios

import android.content.Context
import com.bugsnag.android.Bugsnag
import com.bugsnag.android.Configuration
import android.os.Handler
import android.os.HandlerThread

/**
* Sends an exception after stopping the session
*/
internal class NewSessionScenario(config: Configuration,
context: Context) : Scenario(config, context) {
init {
config.setAutoCaptureSessions(false)
}

override fun run() {
super.run()
val client = Bugsnag.getClient()
val thread = HandlerThread("HandlerThread")
thread.start()

Handler(thread.looper).post {
// send 1st exception which should include session info
client.startSession()
client.notifyBlocking(generateException())

// stop tracking the existing session
client.stopSession()

// send 2nd exception which should contain new session info
client.startSession()
client.notifyBlocking(generateException())
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package com.bugsnag.android.mazerunner.scenarios

import android.content.Context
import com.bugsnag.android.Bugsnag
import com.bugsnag.android.Configuration
import android.os.Handler
import android.os.HandlerThread

/**
* Sends 2 exceptions, 1 before resuming a session, and 1 after resuming a session.
*/
internal class ResumedSessionScenario(config: Configuration,
context: Context) : Scenario(config, context) {
init {
config.setAutoCaptureSessions(false)
}

override fun run() {
super.run()
val client = Bugsnag.getClient()
val thread = HandlerThread("HandlerThread")
thread.start()

Handler(thread.looper).post {
// send 1st exception
client.startSession()
client.notifyBlocking(generateException())

// send 2nd exception after resuming a session
client.stopSession()
client.resumeSession()
client.notifyBlocking(generateException())
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package com.bugsnag.android.mazerunner.scenarios

import android.content.Context
import com.bugsnag.android.Bugsnag
import com.bugsnag.android.Configuration
import android.os.Handler
import android.os.HandlerThread

/**
* Sends an exception after stopping the session
*/
internal class StoppedSessionScenario(config: Configuration,
context: Context) : Scenario(config, context) {
init {
config.setAutoCaptureSessions(false)
}

override fun run() {
super.run()
val client = Bugsnag.getClient()
val thread = HandlerThread("HandlerThread")
thread.start()

Handler(thread.looper).post {
// send 1st exception which should include session info
client.startSession()
client.notifyBlocking(generateException())

// send 2nd exception which should not include session info
client.stopSession()
client.notifyBlocking(generateException())
}
}
}
23 changes: 23 additions & 0 deletions features/native_session_tracking.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
Feature: NDK Session Tracking

Scenario: Stopped session is not in payload of unhandled NDK error
When I run "CXXStopSessionScenario"
And I wait a bit
And I wait a bit
And I configure the app to run in the "non-crashy" state
And I relaunch the app
Then I should receive 2 requests
And the request 0 is a valid for the session tracking API
And the request 1 is a valid for the error reporting API
And the payload field "events.0.session" is null for request 1

Scenario: Started session is in payload of unhandled NDK error
When I run "CXXStartSessionScenario"
And I wait a bit
And I wait a bit
And I configure the app to run in the "non-crashy" state
And I relaunch the app
Then I should receive 2 requests
And the request 0 is a valid for the session tracking API
And the request 1 is a valid for the error reporting API
And the payload field "events.0.session.events.unhandled" equals 1 for request 1
32 changes: 32 additions & 0 deletions features/session_stopping.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
Feature: Stopping and resuming sessions

Scenario: When a session is stopped the error has no session information
When I run "StoppedSessionScenario"
Then I should receive 3 requests
And the request 0 is valid for the session tracking API
And the request 1 is valid for the error reporting API
And the request 2 is valid for the error reporting API
And the payload field "events.0.session" is not null for request 1
And the payload field "events.0.session" is null for request 2

Scenario: When a session is resumed the error uses the previous session information
When I run "ResumedSessionScenario"
Then I should receive 3 requests
And the request 0 is valid for the session tracking API
And the request 1 is valid for the error reporting API
And the request 2 is valid for the error reporting API
And the payload field "events.0.session.events.handled" equals 1 for request 1
And the payload field "events.0.session.events.handled" equals 2 for request 2
And the payload field "events.0.session.id" of request 1 equals the payload field "events.0.session.id" of request 2
And the payload field "events.0.session.startedAt" of request 1 equals the payload field "events.0.session.startedAt" of request 2

Scenario: When a new session is started the error uses different session information
When I run "NewSessionScenario"
Then I should receive 4 requests
And the request 0 is valid for the session tracking API
And the request 1 is valid for the error reporting API
And the request 2 is valid for the session tracking API
And the request 3 is valid for the error reporting API
And the payload field "events.0.session.events.handled" equals 1 for request 1
And the payload field "events.0.session.events.handled" equals 1 for request 3
And the payload field "events.0.session.id" of request 1 does not equal the payload field "events.0.session.id" of request 3
20 changes: 16 additions & 4 deletions ndk/src/main/java/com/bugsnag/android/ndk/NativeBridge.java
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,9 @@ public static native void addBreadcrumb(String name, String type, String timesta

public static native void removeMetadata(String tab, String key);

public static native void startedSession(String sessionID, String key);
public static native void startedSession(String sessionID, String key, int handledCount);
fractalwrench marked this conversation as resolved.
Show resolved Hide resolved

public static native void stoppedSession();

public static native void updateAppVersion(String appVersion);

Expand Down Expand Up @@ -131,6 +133,9 @@ public void update(Observable observable, Object rawMessage) {
case START_SESSION:
handleStartSession(arg);
break;
case STOP_SESSION:
stoppedSession();
break;
case UPDATE_APP_VERSION:
handleAppVersionChange(arg);
break;
Expand Down Expand Up @@ -313,11 +318,14 @@ private void handleStartSession(Object arg) {
if (arg instanceof List) {
@SuppressWarnings("unchecked")
List<Object> metadata = (List<Object>)arg;
if (metadata.size() == 2) {
if (metadata.size() == 3) {
Object id = metadata.get(0);
Object startTime = metadata.get(1);
if (id instanceof String && startTime instanceof String) {
startedSession((String)id, (String)startTime);
Object handledCount = metadata.get(2);

if (id instanceof String && startTime instanceof String
&& handledCount instanceof Integer) {
startedSession((String)id, (String)startTime, (Integer) handledCount);
return;
}
}
Expand All @@ -326,6 +334,10 @@ private void handleStartSession(Object arg) {
warn("START_SESSION object is invalid: " + arg);
}

private void handleStopSession() {
stoppedSession();
}

private void handleReleaseStageChange(Object arg) {
if (arg instanceof String) {
updateReleaseStage((String)arg);
Expand Down
Loading