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 1 commit
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
package com.bugsnag.android

import com.bugsnag.android.BugsnagTestUtils.generateClient
import com.bugsnag.android.BugsnagTestUtils.generateConfiguration
import com.bugsnag.android.BugsnagTestUtils.generateSessionStore
import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
import org.junit.Assert.assertNotEquals
import org.junit.Assert.assertNotNull
import org.junit.Assert.assertNull
import org.junit.Assert.assertTrue
import org.junit.Before
import org.junit.Test

class SessionTrackerStopResumeTest {

private val configuration = generateConfiguration().also {
it.autoCaptureSessions = false
}
private val sessionStore = generateSessionStore()
private lateinit var tracker: SessionTracker

@Before
fun setUp() {
tracker = SessionTracker(configuration, generateClient(), sessionStore)
}

/**
* Verifies that a session can be resumed after it is stopped
*/
@Test
fun resumeFromStoppedSession() {
tracker.startSession(false)
val originalSession = tracker.currentSession
assertNotNull(originalSession)

tracker.stopSession()
assertNull(tracker.currentSession)

assertTrue(tracker.resumeSession())
assertEquals(originalSession, tracker.currentSession)
}

/**
* Verifies that a new session is started when calling [SessionTracker.resumeSession],
* if there is no stopped session
*/
@Test
fun resumeWithNoStoppedSession() {
assertNull(tracker.currentSession)
assertFalse(tracker.resumeSession())
assertNotNull(tracker.currentSession)
}

/**
* Verifies that a new session can be created after the previous one is stopped
*/
@Test
fun startNewAfterStoppedSession() {
tracker.startSession(false)
val originalSession = tracker.currentSession

tracker.stopSession()
tracker.startSession(false)
assertNotEquals(originalSession, tracker.currentSession)
}

/**
* Verifies that calling [SessionTracker.resumeSession] multiple times only starts one session
*/
@Test
fun multipleResumesHaveNoEffect() {
tracker.startSession(false)
val original = tracker.currentSession
tracker.stopSession()

assertTrue(tracker.resumeSession())
assertEquals(original, tracker.currentSession)

assertFalse(tracker.resumeSession())
assertEquals(original, tracker.currentSession)
}

/**
* Verifies that calling [SessionTracker.stopSession] multiple times only stops one session
*/
@Test
fun multipleStopsHaveNoEffect() {
tracker.startSession(false)
assertNotNull(tracker.currentSession)

tracker.stopSession()
assertNull(tracker.currentSession)

tracker.stopSession()
assertNull(tracker.currentSession)
}

/**
* Verifies that if a handled or unhandled error occurs when a session is stopped, the
* error count is not updated
*/
@Test
fun stoppedSessionDoesNotIncrement() {
tracker.startSession(false)
tracker.incrementHandledError()
tracker.incrementUnhandledError()
assertEquals(1, tracker.currentSession?.handledCount)
assertEquals(1, tracker.currentSession?.unhandledCount)

tracker.stopSession()
tracker.incrementHandledError()
tracker.incrementUnhandledError()
tracker.resumeSession()
assertEquals(1, tracker.currentSession?.handledCount)
assertEquals(1, tracker.currentSession?.unhandledCount)

tracker.incrementHandledError()
tracker.incrementUnhandledError()
assertEquals(2, tracker.currentSession?.handledCount)
assertEquals(2, tracker.currentSession?.unhandledCount)
}
}
10 changes: 9 additions & 1 deletion sdk/src/main/java/com/bugsnag/android/Client.java
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,15 @@ public void update(@NonNull Observable observable, @NonNull Object arg) {
* session everytime the app enters the foreground.
*/
public void startSession() {
sessionTracker.startNewSession(new Date(), user, false);
sessionTracker.startSession(false);
}

public final void stopSession() {
fractalwrench marked this conversation as resolved.
Show resolved Hide resolved
sessionTracker.stopSession();
}

public final boolean resumeSession() {
return sessionTracker.resumeSession();
}

/**
Expand Down
1 change: 1 addition & 0 deletions sdk/src/main/java/com/bugsnag/android/Session.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ public Session(String id, Date startedAt, User user, boolean autoCaptured) {
private AtomicInteger unhandledCount = new AtomicInteger();
private AtomicInteger handledCount = new AtomicInteger();
private AtomicBoolean tracked = new AtomicBoolean(false);
final AtomicBoolean isStopped = new AtomicBoolean(false);

String getId() {
return id;
Expand Down
39 changes: 35 additions & 4 deletions sdk/src/main/java/com/bugsnag/android/SessionTracker.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.VisibleForTesting;

import java.io.File;
import java.util.Arrays;
Expand Down Expand Up @@ -65,7 +66,9 @@ class SessionTracker extends Observable implements Application.ActivityLifecycle
* @param date the session start date
* @param user the session user (if any)
*/
@Nullable Session startNewSession(@NonNull Date date, @Nullable User user,
@Nullable
@VisibleForTesting
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This documents that the method has been left package-visible for existing unit tests, and would otherwise be private.

Session startNewSession(@NonNull Date date, @Nullable User user,
boolean autoCaptured) {
if (configuration.getSessionEndpoint() == null) {
Logger.warn("The session tracking endpoint has not been set. "
Expand All @@ -78,6 +81,29 @@ class SessionTracker extends Observable implements Application.ActivityLifecycle
return session;
}

void startSession(boolean autoCaptured) {
startNewSession(new Date(), client.getUser(), autoCaptured);
}

void stopSession() {
Session session = currentSession.get();

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

boolean resumeSession() {
Session session = currentSession.get();

if (session == null) {
startSession(false);
return false;
} else {
return session.isStopped.compareAndSet(true, false);
fractalwrench marked this conversation as resolved.
Show resolved Hide resolved
}
}

/**
* Determines whether or not a session should be tracked. If this is true, the session will be
* stored and sent to the Bugsnag API, otherwise no action will occur in this method.
Expand Down Expand Up @@ -141,18 +167,23 @@ private String getReleaseStage() {

@Nullable
Session getCurrentSession() {
return currentSession.get();
Session session = currentSession.get();

if (session != null && !session.isStopped.get()) {
return session;
}
return null;
}

void incrementUnhandledError() {
Session session = currentSession.get();
Session session = getCurrentSession();
if (session != null) {
session.incrementUnhandledErrCount();
}
}

void incrementHandledError() {
Session session = currentSession.get();
Session session = getCurrentSession();
if (session != null) {
session.incrementHandledErrCount();
}
Expand Down