Skip to content

Commit

Permalink
Merge branch 'next' into enable-session-tracking
Browse files Browse the repository at this point in the history
  • Loading branch information
fractalwrench committed May 17, 2018
2 parents ceb8cfe + 48a807f commit abbcc28
Show file tree
Hide file tree
Showing 38 changed files with 1,415 additions and 192 deletions.
20 changes: 19 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,31 @@
# Changelog

## 4.4.0 (TBD)
## 4.X.X (TBD)

**Note**: this release alters the behaviour of the notifier to track session automatically. If you
use Bugsnag On-Premise, it is now also recommended that you set your notify and session endpoints
via `config.setEndpoints(String notify, String sessions)`.

* Enable automatic session tracking by default [#314](https://github.com/bugsnag/bugsnag-android/pull/314)

## 4.4.0 (2018-05-17)

### Features

Deprecation notice:

SessionTrackingApiClient and ErrorApiClient are now deprecated in favour of the Delivery interface.
If you configure a custom HTTP client with Bugsnag, it is recommended that you migrate over to this new API.
Further information is available [in the docs.](https://docs.bugsnag.com/platforms/android/sdk/configuration-options/).

* Expose Delivery API interface for configuring custom HTTP clients
[#299](https://github.com/bugsnag/bugsnag-android/pull/299)

### Enhancements

* Use buffered streams for IO (perf improvement)
[#307](https://github.com/bugsnag/bugsnag-android/pull/307)

## 4.3.4 (2018-05-02)

### Bug fixes
Expand Down
9 changes: 5 additions & 4 deletions Gemfile.lock
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
GIT
remote: git@github.com:bugsnag/maze-runner
revision: 65bdcb7a135ef0a5864d03c454f7a1654f850237
revision: f7123450d5a75b719911c6dd3baa0507e6062c2d
specs:
bugsnag-maze-runner (1.0.0)
cucumber (~> 3.1.0)
cucumber-expressions (= 5.0.15)
minitest (~> 5.0)
rack (~> 2.0.0)
test-unit (~> 3.2.0)

GEM
remote: https://rubygems.org/
specs:
backports (3.11.1)
backports (3.11.3)
builder (3.2.3)
coderay (1.1.2)
cucumber (3.1.0)
Expand All @@ -27,7 +28,7 @@ GEM
backports (>= 3.8.0)
cucumber-tag_expressions (~> 1.1.0)
gherkin (>= 5.0.0)
cucumber-expressions (5.0.13)
cucumber-expressions (5.0.15)
cucumber-tag_expressions (1.1.1)
cucumber-wire (0.0.1)
diff-lcs (1.3)
Expand All @@ -40,7 +41,7 @@ GEM
pry (0.11.3)
coderay (~> 1.1.0)
method_source (~> 0.9.0)
rack (2.0.4)
rack (2.0.5)
test-unit (3.2.7)
power_assert

Expand Down
32 changes: 32 additions & 0 deletions features/custom_client.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
Feature: Using custom API clients for reporting errors

Scenario: Set a custom session client and flush a stored session
When I run "CustomClientSessionFlushScenario" with the defaults
When I force stop the "com.bugsnag.android.mazerunner" Android app
And I set environment variable "EVENT_TYPE" to "CustomClientSessionFlushScenario"
And I set environment variable "EVENT_METADATA" to "DeliverSessions"
And I start the "com.bugsnag.android.mazerunner" Android app using the "com.bugsnag.android.mazerunner.MainActivity" activity
Then I should receive 2 requests
And the "Custom-Client" header equals "Hello World" for request 0
And the "Custom-Client" header equals "Hello World" for request 1

Scenario: Set a custom error API client and notify an error
When I run "CustomClientErrorScenario" with the defaults
Then I should receive 1 request
And the "Custom-Client" header equals "Hello World"
And the request is a valid for the error reporting API

Scenario: Set a custom session API client and start a session
When I run "CustomClientSessionScenario" with the defaults
Then I should receive 1 request
And the "Custom-Client" header equals "Hello World"
And the request is a valid for the session tracking API

Scenario: Set a custom error client and flush a stored error
When I run "CustomClientErrorFlushScenario" with the defaults
When I force stop the "com.bugsnag.android.mazerunner" Android app
And I set environment variable "EVENT_TYPE" to "CustomClientErrorFlushScenario"
And I set environment variable "EVENT_METADATA" to "DeliverReports"
And I start the "com.bugsnag.android.mazerunner" Android app using the "com.bugsnag.android.mazerunner.MainActivity" activity
Then I should receive 1 request
And the "Custom-Client" header equals "Hello World"
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ org.gradle.jvmargs=-Xmx1536m
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true
VERSION_NAME=4.3.4
VERSION_NAME=4.4.0
GROUP=com.bugsnag
POM_SCM_URL=https://github.com/bugsnag/bugsnag-android
POM_SCM_CONNECTION=scm:git@github.com:bugsnag/bugsnag-android.git
Expand Down
62 changes: 46 additions & 16 deletions mazerunner/src/main/java/com/bugsnag/android/TestHarnessHooks.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package com.bugsnag.android

import android.content.Context
import android.net.ConnectivityManager
import com.bugsnag.android.Bugsnag.client

/**
* Accesses the session tracker and flushes all stored sessions
Expand All @@ -11,31 +10,62 @@ internal fun flushAllSessions() {
Bugsnag.getClient().sessionTracker.flushStoredSessions()
}

internal fun flushErrorStoreAsync(client: Client, apiClient: ErrorReportApiClient) {
client.errorStore.flushAsync(apiClient)
internal fun flushErrorStoreAsync(client: Client) {
client.errorStore.flushAsync()
}

internal fun flushErrorStoreOnLaunch(client: Client, apiClient: ErrorReportApiClient) {
client.errorStore.flushOnLaunch(apiClient)
internal fun flushErrorStoreOnLaunch(client: Client) {
client.errorStore.flushOnLaunch()
}

/**
* Creates an error API client with a 500ms delay, emulating poor network connectivity
* Creates a delivery API client with a 500ms delay, emulating poor network connectivity
*/
internal fun createSlowErrorApiClient(context: Context): ErrorReportApiClient {
internal fun createSlowDelivery(context: Context): Delivery {
val cm = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager?
val defaultHttpClient = DefaultHttpClient(cm)

return ErrorReportApiClient({ url: String?,
report: Report?,
headers: MutableMap<String, String>? ->
Thread.sleep(500)
defaultHttpClient.postReport(url, report, headers)
})
val delivery = DefaultDelivery(cm)

return object : Delivery {
override fun deliver(payload: SessionTrackingPayload?, config: Configuration?) {
Thread.sleep(500)
delivery.deliver(payload, config)
}

override fun deliver(report: Report?, config: Configuration?) {
Thread.sleep(500)
delivery.deliver(report, config)
}
}
}

internal fun createDefaultDelivery(context: Context): DefaultDelivery {
val cm = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager?
return DefaultDelivery(cm)
}

internal fun createCustomHeaderDelivery(context: Context): Delivery {
return object : Delivery {
val delivery: DefaultDelivery = createDefaultDelivery(context)

override fun deliver(payload: SessionTrackingPayload?, config: Configuration?) {
deliver(config?.sessionEndpoint, payload, config?.sessionApiHeaders)
}

override fun deliver(report: Report?, config: Configuration?) {
deliver(config?.endpoint, report, config?.errorApiHeaders)
}

fun deliver(endpoint: String?,
streamable: JsonStream.Streamable?,
headers: MutableMap<String, String>?) {
headers!!["Custom-Client"] = "Hello World"
delivery.deliver(endpoint, streamable, headers)
}
}
}


internal fun writeErrorToStore(client: Client) {
val error = Error.Builder(Configuration("api-key"), RuntimeException(), null).build()
client.errorStore.write(error)
}

Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@ internal class AsyncErrorConnectivityScenario(config: Configuration,
context: Context) : Scenario(config, context) {

override fun run() {
val delivery = createSlowDelivery(context)
config.delivery = delivery
super.run()
val apiClient = createSlowErrorApiClient(context)
Bugsnag.setErrorReportApiClient(apiClient)

writeErrorToStore(Bugsnag.getClient())
flushErrorStoreAsync(Bugsnag.getClient(), apiClient)
flushErrorStoreOnLaunch(Bugsnag.getClient(), apiClient)
flushErrorStoreAsync(Bugsnag.getClient())
flushErrorStoreOnLaunch(Bugsnag.getClient())
Thread.sleep(50)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,12 @@ internal class AsyncErrorDoubleFlushScenario(config: Configuration,
context: Context) : Scenario(config, context) {

override fun run() {
config.delivery = createSlowDelivery(context)
super.run()
val apiClient = createSlowErrorApiClient(context)
Bugsnag.setErrorReportApiClient(apiClient)

writeErrorToStore(Bugsnag.getClient())
flushErrorStoreAsync(Bugsnag.getClient(), apiClient)
flushErrorStoreAsync(Bugsnag.getClient(), apiClient)
flushErrorStoreAsync(Bugsnag.getClient())
flushErrorStoreAsync(Bugsnag.getClient())
Thread.sleep(50)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,12 @@ internal class AsyncErrorLaunchScenario(config: Configuration,
context: Context) : Scenario(config, context) {

override fun run() {
config.delivery = createSlowDelivery(context)
super.run()
val apiClient = createSlowErrorApiClient(context)
Bugsnag.setErrorReportApiClient(apiClient)

writeErrorToStore(Bugsnag.getClient())
flushErrorStoreOnLaunch(Bugsnag.getClient(), apiClient)
flushErrorStoreAsync(Bugsnag.getClient(), apiClient)
flushErrorStoreOnLaunch(Bugsnag.getClient())
flushErrorStoreAsync(Bugsnag.getClient())
Thread.sleep(50)
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package com.bugsnag.android.mazerunner.scenarios

import android.content.Context
import com.bugsnag.android.Bugsnag
import com.bugsnag.android.Configuration
import com.bugsnag.android.createCustomHeaderDelivery

/**
* Sends an unhandled exception which is cached on disk to Bugsnag, then sent on a separate launch,
* using a custom API client which modifies the request.
*/
internal class CustomClientErrorFlushScenario(config: Configuration,
context: Context) : Scenario(config, context) {

override fun run() {
if ("DeliverReports" == eventMetaData) {
config.delivery = createCustomHeaderDelivery(context)
}
super.run()

if ("DeliverReports" != eventMetaData) {
disableAllDelivery()
throw RuntimeException("ReportCacheScenario")
}

}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.bugsnag.android.mazerunner.scenarios

import android.content.Context
import com.bugsnag.android.Bugsnag
import com.bugsnag.android.Configuration
import com.bugsnag.android.createCustomHeaderDelivery

/**
* Sends a handled exception to Bugsnag using a custom API client which modifies the request.
*/
internal class CustomClientErrorScenario(config: Configuration,
context: Context) : Scenario(config, context) {

override fun run() {
config.delivery = createCustomHeaderDelivery(context)
super.run()
Bugsnag.notify(RuntimeException("Hello"))
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package com.bugsnag.android.mazerunner.scenarios

import android.content.Context
import com.bugsnag.android.Bugsnag
import com.bugsnag.android.Configuration
import com.bugsnag.android.createCustomHeaderDelivery
import com.bugsnag.android.createDefaultDelivery

/**
* Sends a session which is cached on disk to Bugsnag, then sent on a separate launch,
* using a custom API client which modifies the request.
*/
internal class CustomClientSessionFlushScenario(config: Configuration,
context: Context) : Scenario(config, context) {

override fun run() {
super.run()

if ("DeliverSessions" == eventMetaData) {
// simulate activity lifecycle callback occurring before api client can be set
Bugsnag.startSession()
config.delivery = createCustomHeaderDelivery(context)
} else {
disableAllDelivery()
Bugsnag.startSession()
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.bugsnag.android.mazerunner.scenarios

import android.content.Context
import com.bugsnag.android.Bugsnag
import com.bugsnag.android.Configuration
import com.bugsnag.android.createCustomHeaderDelivery
import com.bugsnag.android.createDefaultDelivery

/**
* Sends a session using a custom API client which modifies the request.
*/
internal class CustomClientSessionScenario(config: Configuration,
context: Context) : Scenario(config, context) {

override fun run() {
config.delivery = createCustomHeaderDelivery(context)
super.run()
Bugsnag.startSession()
}

}

0 comments on commit abbcc28

Please sign in to comment.