Skip to content

Commit

Permalink
Merge pull request #136 from bugsnag/stop-sessions
Browse files Browse the repository at this point in the history
Add stopSession() and resumeSession() to public API
  • Loading branch information
fractalwrench authored Mar 13, 2019
2 parents af4e3a2 + 4499aab commit 4784ad6
Show file tree
Hide file tree
Showing 19 changed files with 303 additions and 42 deletions.
23 changes: 23 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,28 @@
# Changelog

## 4.X.X (TBD)

Add StopSession() and ResumeSession() to public API [#136](https://github.com/bugsnag/bugsnag-unity/pull/136)

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

* Prevent overwriting config.projectPackages if already set
[#428](https://github.com/bugsnag/bugsnag-android/pull/428)

* Fix incorrect session handledCount when notifying in quick succession
[#434](https://github.com/bugsnag/bugsnag-android/pull/434)

Update bugsnag-cocoa dependency to v5.19.0:
* Update workspace to recommended settings suggested by XCode 10
[#324](https://github.com/bugsnag/bugsnag-cocoa/pull/324)
* Add stopSession() and resumeSession() to Bugsnag
[#325](https://github.com/bugsnag/bugsnag-cocoa/pull/325)
* Capture basic report diagnostics in the file path in case of crash report
content corruption
[#327](https://github.com/bugsnag/bugsnag-cocoa/pull/327)

## 4.2.2 (2019-02-26)

### Bug fixes
Expand Down
32 changes: 1 addition & 31 deletions Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -225,41 +225,11 @@ namespace :plugin do
end
end

task :check_package do
expected_guids = []
package_guids = []

cd current_directory do
Open3.popen2("git", "ls-files", "--", "unity/**/*.meta") do |stdin, stdout, wait_thr|
stdout.each_line do |file|
File.open(file.gsub("\n", "")).each_line do |line|
if match = /guid: ([a-z0-9]+)/.match(line)
expected_guids << match[1]
break
end
end
end
end

Open3.popen2("tar", "-tf", "Bugsnag.unitypackage", "*/asset.meta") do |stdin, stdout, wait_thr|
stdout.each_line do |line|
if match = /\.\/([a-z0-9]+)\/asset.meta/.match(line)
package_guids << match[1]
end
end
end
end

unless expected_guids.sort == package_guids.sort
raise "package contains unknown files"
end
end

task :export_package do
export_package
end

task export: %w[plugin:build:all export_package check_package]
task export: %w[plugin:build:all export_package]

task maze_runner: %w[plugin:export] do
sh "bundle", "exec", "bugsnag-maze-runner"
Expand Down
2 changes: 1 addition & 1 deletion bugsnag-android
Submodule bugsnag-android updated 35 files
+15 −0 CHANGELOG.md
+9 −7 Gemfile.lock
+1 −1 README.md
+20 −0 features/fixtures/mazerunner/src/main/cpp/bugsnags.cpp
+43 −0 ...res/fixtures/mazerunner/src/main/java/com/bugsnag/android/mazerunner/scenarios/CXXStartSessionScenario.java
+44 −0 ...ures/fixtures/mazerunner/src/main/java/com/bugsnag/android/mazerunner/scenarios/CXXStopSessionScenario.java
+37 −0 features/fixtures/mazerunner/src/main/java/com/bugsnag/android/mazerunner/scenarios/NewSessionScenario.kt
+35 −0 features/fixtures/mazerunner/src/main/java/com/bugsnag/android/mazerunner/scenarios/ResumedSessionScenario.kt
+34 −0 features/fixtures/mazerunner/src/main/java/com/bugsnag/android/mazerunner/scenarios/StoppedSessionScenario.kt
+23 −0 features/native_session_tracking.feature
+32 −0 features/session_stopping.feature
+1 −1 gradle.properties
+16 −4 ndk/src/main/java/com/bugsnag/android/ndk/NativeBridge.java
+21 −3 ndk/src/main/jni/bugsnag_ndk.c
+6 −2 ndk/src/main/jni/report.c
+3 −1 ndk/src/main/jni/report.h
+8 −7 ndk/src/main/jni/utils/serializer.c
+2 −1 sdk/src/androidTest/java/com/bugsnag/android/BeforeNotifyTest.kt
+1 −1 sdk/src/androidTest/java/com/bugsnag/android/ErrorStoreTest.java
+27 −20 sdk/src/androidTest/java/com/bugsnag/android/ErrorTest.java
+2 −1 sdk/src/androidTest/java/com/bugsnag/android/ExceptionsTest.java
+10 −6 sdk/src/androidTest/java/com/bugsnag/android/NullMetadataTest.java
+11 −1 sdk/src/androidTest/java/com/bugsnag/android/ObserverInterfaceTest.java
+26 −0 sdk/src/androidTest/java/com/bugsnag/android/ProjectPackagesTest.kt
+2 −1 sdk/src/androidTest/java/com/bugsnag/android/ReportTest.java
+47 −0 sdk/src/androidTest/java/com/bugsnag/android/SessionTest.kt
+123 −0 sdk/src/androidTest/java/com/bugsnag/android/SessionTrackerStopResumeTest.kt
+5 −7 sdk/src/androidTest/java/com/bugsnag/android/SessionTrackerTest.java
+59 −5 sdk/src/main/java/com/bugsnag/android/Bugsnag.java
+85 −36 sdk/src/main/java/com/bugsnag/android/Client.java
+25 −11 sdk/src/main/java/com/bugsnag/android/Error.java
+6 −0 sdk/src/main/java/com/bugsnag/android/NativeInterface.java
+1 −1 sdk/src/main/java/com/bugsnag/android/Notifier.java
+13 −2 sdk/src/main/java/com/bugsnag/android/Session.java
+70 −13 sdk/src/main/java/com/bugsnag/android/SessionTracker.java
2 changes: 1 addition & 1 deletion bugsnag-cocoa
Submodule bugsnag-cocoa updated 76 files
+2 −2 Bugsnag.podspec.json
+20 −0 CHANGELOG.md
+2 −5 Makefile
+8 −0 OSX.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
+9 −1 OSX/Bugsnag.xcodeproj/project.pbxproj
+1 −3 OSX/Bugsnag.xcodeproj/xcshareddata/xcschemes/Bugsnag.xcscheme
+5 −4 README.md
+52 −5 Source/Bugsnag.h
+14 −0 Source/Bugsnag.m
+6 −6 Source/BugsnagApiClient.h
+9 −9 Source/BugsnagApiClient.m
+16 −0 Source/BugsnagCrashReport.h
+67 −6 Source/BugsnagCrashReport.m
+2 −2 Source/BugsnagErrorReportApiClient.m
+6 −0 Source/BugsnagFileStore.h
+7 −3 Source/BugsnagFileStore.m
+1 −0 Source/BugsnagKeys.h
+2 −0 Source/BugsnagNotifier.h
+11 −2 Source/BugsnagNotifier.m
+3 −0 Source/BugsnagSession.h
+12 −0 Source/BugsnagSession.m
+7 −2 Source/BugsnagSessionTracker.h
+38 −5 Source/BugsnagSessionTracker.m
+5 −5 Source/BugsnagSessionTrackingApiClient.m
+16 −13 Source/BugsnagSink.m
+13 −8 Source/KSCrash/Source/KSCrash/Recording/BSG_KSCrash.m
+5 −1 Source/KSCrash/Source/KSCrash/Recording/BSG_KSCrashAdvanced.h
+48 −4 Source/KSCrash/Source/KSCrash/Recording/BSG_KSCrashC.c
+1 −0 Source/KSCrash/Source/KSCrash/Recording/BSG_KSCrashC.h
+2 −2 Source/KSCrash/Source/KSCrash/Recording/Sentry/BSG_KSCrashSentry.c
+2 −2 Source/KSCrash/Source/KSCrash/Recording/Sentry/BSG_KSCrashSentry.h
+3 −1 Source/KSCrash/Source/KSCrash/Recording/Sentry/BSG_KSCrashSentry_CPPException.mm
+1 −1 Source/KSCrash/Source/KSCrash/Recording/Sentry/BSG_KSCrashSentry_Deadlock.m
+3 −1 Source/KSCrash/Source/KSCrash/Recording/Sentry/BSG_KSCrashSentry_MachException.c
+3 −1 Source/KSCrash/Source/KSCrash/Recording/Sentry/BSG_KSCrashSentry_NSException.m
+12 −1 Source/KSCrash/Source/KSCrash/Recording/Sentry/BSG_KSCrashSentry_Signal.c
+6 −1 Source/KSCrash/Source/KSCrash/Recording/Sentry/BSG_KSCrashSentry_User.c
+1 −0 Source/KSCrash/Source/KSCrash/Recording/Sentry/BSG_KSCrashSentry_User.h
+2 −2 Source/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSCrashCallCompletion.h
+2 −2 Source/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSCrashCallCompletion.m
+1 −1 Source/KSCrash/Source/KSCrash/Reporting/Filters/BSG_KSCrashReportFilter.h
+2 −3 Source/KSCrash/Source/KSCrash/Reporting/Filters/BSG_KSCrashReportFilterCompletion.h
+64 −0 Tests/BSGFilepathTests.m
+4 −4 Tests/BugsnagConfigurationTests.m
+40 −1 Tests/BugsnagCrashReportTests.m
+119 −0 Tests/BugsnagSessionTrackerStopTest.m
+14 −14 Tests/BugsnagSessionTrackerTest.m
+1 −1 Tests/KSCrash/KSCrashSentry_Tests.m
+1 −1 VERSION
+5 −1 examples/objective-c-ios/Bugsnag Test App.xcodeproj/project.pbxproj
+8 −0 examples/objective-c-ios/Bugsnag Test App.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
+3 −3 examples/objective-c-ios/Podfile.lock
+3 −3 examples/objective-c-osx/Podfile.lock
+5 −1 examples/objective-c-osx/objective-c-osx.xcodeproj/project.pbxproj
+8 −0 examples/objective-c-osx/objective-c-osx.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
+3 −3 examples/swift-ios/Podfile.lock
+5 −1 examples/swift-ios/bugsnag-example.xcodeproj/project.pbxproj
+8 −0 examples/swift-ios/bugsnag-example.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
+12 −0 features/crashprobe.feature
+2 −2 features/fixtures/ios-swift-cocoapods/Podfile.lock
+12 −0 features/fixtures/ios-swift-cocoapods/iOSTestApp.xcodeproj/project.pbxproj
+30 −0 features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/NewSessionScenario.swift
+28 −0 features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/ResumedSessionScenario.swift
+27 −0 features/fixtures/ios-swift-cocoapods/iOSTestApp/scenarios/StoppedSessionScenario.swift
+0 −50 features/fixtures/json/minimal-crash-ios.json
+7 −1 features/minimal_crash.feature
+29 −0 features/session_stopping.feature
+1 −1 features/session_tracking.feature
+20 −1 features/steps/ios_steps.rb
+8 −0 iOS.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
+13 −1 iOS/Bugsnag.xcodeproj/project.pbxproj
+3 −5 iOS/Bugsnag.xcodeproj/xcshareddata/xcschemes/Bugsnag.xcscheme
+8 −0 tvOS.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
+9 −1 tvOS/Bugsnag.xcodeproj/project.pbxproj
+1 −3 tvOS/Bugsnag.xcodeproj/xcshareddata/xcschemes/Bugsnag.xcscheme
+1 −3 tvOS/Bugsnag.xcodeproj/xcshareddata/xcschemes/Tests.xcscheme
14 changes: 7 additions & 7 deletions example/Assets/Main.cs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ void Start ()
private static extern void Crash();

[DllImport("__Internal")]
private static extern void CrashCrashInBackground();
private static extern void CrashInBackground();
#endif

private void OnNativeCrashClick()
Expand All @@ -82,7 +82,7 @@ private void OnNativeCrashClick()
private void OnNativeBackgroundCrashClick()
{
#if UNITY_IOS
CrashCrashInBackground();
CrashInBackground();
#elif UNITY_ANDROID
using (var java = new AndroidJavaObject("BugsnagCrash"))
{
Expand Down Expand Up @@ -112,17 +112,17 @@ private void OnDivideByZeroClick()
int b = 1;
int c = b / a;
} catch (Exception e) {
//BugsnagUnity.Bugsnag.Client.Notify(e);
BugsnagUnity.Bugsnag.Client.Notify(e);
}
}

private void OnNotifyClick()
{
Debug.Log ("Notify clicked");
// BugsnagUnity.Bugsnag.Client.Notify(new Exception ("Notify clicked!"), report =>
// {
// report.Event.Context = "NotifyClicked";
// });
BugsnagUnity.Bugsnag.Client.Notify(new Exception ("Notify clicked!"), report =>
{
report.Context = "NotifyClicked";
});
}

private void OnManagedCrashClick()
Expand Down
35 changes: 35 additions & 0 deletions features/fixtures/Main.cs
Original file line number Diff line number Diff line change
Expand Up @@ -106,9 +106,44 @@ void LoadScenario() {
DoLogWarning();
UncaughtExceptionAsUnhandled();
break;
case "StoppedSession":
Bugsnag.StartSession();
Bugsnag.StopSession();
DoNotify();
break;
case "ResumedSession":
RunResumedSession();
break;
case "NewSession":
RunNewSession();
break;
}
}

void RunResumedSession() {
// send 1st exception which should include session info
Bugsnag.StartSession();
Bugsnag.Notify(new System.Exception("First Error"));

// send 2nd exception after resuming a session
Bugsnag.StopSession();
Bugsnag.ResumeSession();
Bugsnag.Notify(new System.Exception("Second Error"));
}

void RunNewSession() {
// send 1st exception which should include session info
Bugsnag.StartSession();
Bugsnag.Notify(new System.Exception("First Error"));

// stop tracking the existing session
Bugsnag.StopSession();
Bugsnag.StartSession();

// send 2nd exception which should contain new session info
Bugsnag.Notify(new System.Exception("Second Error"));
}

void UncaughtExceptionAsUnhandled() {
Bugsnag.Configuration.ReportUncaughtExceptionsAsHandled = false;
throw new ExecutionEngineException("Invariant state failure");
Expand Down
32 changes: 32 additions & 0 deletions features/stopping_sessions.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 the game in the "StoppedSession" state
Then I should receive 2 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 payload field "events.0.session" is null for request 1

Scenario: When a session is resumed the error uses the previous session information
When I run the game in the "ResumedSession" state
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.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
And the events in requests "1,2" match one of:
| message | handled | unhandled |
| First Error | 1 | 0 |
| Second Error | 2 | 0 |

Scenario: When a new session is started the error uses different session information
When I run the game in the "NewSession" state
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 session tracking API
And the request 2 is valid for the error reporting 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 2
And the payload field "events.0.session.events.handled" equals 1 for request 3
And the payload field "events.0.session.id" of request 2 does not equal the payload field "events.0.session.id" of request 3
4 changes: 4 additions & 0 deletions src/BugsnagUnity/Bugsnag.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,10 @@ public static void SetUser(string id, string email, string name) {

public static void StartSession() => InternalClient.SessionTracking.StartSession();

public static void StopSession() => InternalClient.SessionTracking.StopSession();

public static bool ResumeSession() => InternalClient.SessionTracking.ResumeSession();

/// <summary>
/// Used to signal to the Bugsnag client that the focused state of the
/// application has changed. This is used for session tracking and also
Expand Down
2 changes: 1 addition & 1 deletion src/BugsnagUnity/Client.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

namespace BugsnagUnity
{
class Client : IClient
internal class Client : IClient
{
public IConfiguration Configuration => NativeClient.Configuration;

Expand Down
3 changes: 3 additions & 0 deletions src/BugsnagUnity/INativeClient.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
using BugsnagUnity.Payload;
using System.Collections.Generic;
using System.Runtime.CompilerServices;

[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")]

namespace BugsnagUnity
{
Expand Down
2 changes: 2 additions & 0 deletions src/BugsnagUnity/Payload/Session.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ public class Session : Dictionary<string, object>

internal SessionEvents Events { get; }

internal bool Stopped { get; set; }

internal Session() : this(DateTime.UtcNow, 0, 0)
{

Expand Down
40 changes: 39 additions & 1 deletion src/BugsnagUnity/SessionTracker.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,18 @@
using BugsnagUnity.Payload;
using System.Runtime.CompilerServices;

[assembly: InternalsVisibleTo("BugsnagUnity.Tests")]

namespace BugsnagUnity
{
public interface ISessionTracker
{
void StartSession();

void StopSession();

bool ResumeSession();

Session CurrentSession { get; }

void AddException(Report report);
Expand All @@ -19,7 +26,14 @@ class SessionTracker : ISessionTracker

public Session CurrentSession
{
get => _currentSession?.Copy();
get {
var session = _currentSession;

if (session != null && !session.Stopped) {
return session?.Copy();
}
return null;
}
private set => _currentSession = value;
}

Expand All @@ -43,6 +57,30 @@ public void StartSession()

Client.Send(payload);
}

public void StopSession()
{
var session = _currentSession;

if (session != null) {
session.Stopped = true;
}
}

public bool ResumeSession()
{
var session = _currentSession;
var resumed = false;

if (session == null) {
StartSession();
resumed = false;
} else {
resumed = session.Stopped;
session.Stopped = false;
}
return resumed;
}

public void AddException(Report report)
{
Expand Down
92 changes: 92 additions & 0 deletions tests/BugsnagUnity.Tests/SessionTrackerTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
using NUnit.Framework;
using System.Linq;
using System.Threading;
using UnityEngine;

namespace BugsnagUnity.Payload.Tests
{
[TestFixture]
class SessionTrackerTests
{

public SessionTracker Tracker { get; set; }

public SessionTrackerTests()
{
Client client = new Client(new NativeClient(new Configuration("api-key")));
Tracker = new SessionTracker(client);
Assert.IsNotNull(Tracker);
}

/**
* Verifies that a session can be resumed after it is stopped
*/
[Test]
public void ResumeFromStoppedSession() {
Tracker.StartSession();
var originalSession = Tracker.CurrentSession;
Assert.IsNotNull(originalSession);

Tracker.StopSession();
Assert.IsNull(Tracker.CurrentSession);

Assert.IsTrue(Tracker.ResumeSession());
Assert.AreEqual(originalSession, Tracker.CurrentSession);
}

/**
* Verifies that the previous session is resumed when calling SessionTracker.ResumeSession
*/
[Test]
public void ResumeWithNoStoppedSession() {
Tracker.StartSession();
Tracker.StopSession();
Assert.IsTrue(Tracker.ResumeSession());
Assert.IsFalse(Tracker.ResumeSession());
}

/**
* Verifies that a new session can be created after the previous one is stopped
*/
[Test]
public void StartNewAfterStoppedSession() {
Tracker.StartSession();
var originalSession = Tracker.CurrentSession;

Tracker.StopSession();
Tracker.StartSession();
Assert.AreNotEqual(originalSession, Tracker.CurrentSession);
}

/**
* Verifies that calling SessionTracker.ResumeSession multiple times only starts one session
*/
[Test]
public void MultipleResumesHaveNoEffect() {
Tracker.StartSession();
var original = Tracker.CurrentSession;
Tracker.StopSession();

Assert.IsTrue(Tracker.ResumeSession());
Assert.AreEqual(original, Tracker.CurrentSession);

Assert.IsFalse(Tracker.ResumeSession());
Assert.AreEqual(original, Tracker.CurrentSession);
}

/**
* Verifies that calling SessionTracker.StopSession multiple times only stops one session
*/
[Test]
public void MultipleStopsHaveNoEffect() {
Tracker.StartSession();
Assert.IsNotNull(Tracker.CurrentSession);

Tracker.StopSession();
Assert.IsNull(Tracker.CurrentSession);

Tracker.StopSession();
Assert.IsNull(Tracker.CurrentSession);
}
}
}
Loading

0 comments on commit 4784ad6

Please sign in to comment.