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

Update onsend-next to next and align tests #1529

Merged
merged 8 commits into from
Nov 25, 2021
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package com.bugsnag.android

import com.bugsnag.android.internal.DateUtils
import java.io.IOException
import java.util.concurrent.atomic.AtomicInteger

Expand Down Expand Up @@ -43,7 +42,8 @@ internal class BreadcrumbState(
StateEvent.AddBreadcrumb(
breadcrumb.impl.message,
breadcrumb.impl.type,
DateUtils.toIso8601(breadcrumb.impl.timestamp),
// an encoding of milliseconds since the epoch
"t${breadcrumb.impl.timestamp.time}",
breadcrumb.impl.metadata ?: mutableMapOf()
)
}
Expand Down
14 changes: 11 additions & 3 deletions bugsnag-android-core/src/main/java/com/bugsnag/android/Client.java
Original file line number Diff line number Diff line change
Expand Up @@ -771,7 +771,8 @@ void notifyInternal(@NonNull Event event,

// Run on error tasks, don't notify if any return false
if (!callbackState.runOnErrorTasks(event, logger)
|| (onError != null && !onError.onError(event))) {
|| (onError != null
&& !onError.onError(event))) {
logger.d("Skipping notification - onError task returned false");
return;
}
Expand Down Expand Up @@ -993,8 +994,15 @@ protected void finalize() throws Throwable {

private void warnIfNotAppContext(Context androidContext) {
if (!(androidContext instanceof Application)) {
logger.w("Warning - Non-Application context detected! Please ensure that you are "
+ "initializing Bugsnag from a custom Application class.");
logger.w("You should initialize Bugsnag from the onCreate() callback of your "
+ "Application subclass, as this guarantees errors are captured as early "
+ "as possible. "
+ "If a custom Application subclass is not possible in your app then you "
+ "should suppress this warning by passing the Application context instead: "
+ "Bugsnag.start(context.getApplicationContext()). "
+ "For further info see: "
+ "https://docs.bugsnag.com/platforms/android/#basic-configuration");

}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ internal class AppDataCollectorSerializationTest {
val memoryTrimState = MemoryTrimState()

// populate summary fields
config.appType = "ReactNative"
config.appType = "React Native"
config.releaseStage = "test-stage"
config.appVersion = "1.2.3"
config.versionCode = 55
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ internal class BreadcrumbSerializationTest {
val timestamp = Date(0)
return generateSerializationTestCases(
"breadcrumb",
Breadcrumb("helloworld", BreadcrumbType.MANUAL, mutableMapOf(), timestamp, NoopLogger),
Breadcrumb("hello world", BreadcrumbType.MANUAL, mutableMapOf(), timestamp, NoopLogger),
Breadcrumb(
"metadata",
BreadcrumbType.PROCESS,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,11 +57,11 @@ internal class EventSerializationTest {
createEvent {
it.addMetadata("app", "foo", 55)
it.addMetadata("device", "bar", true)
it.addMetadata("wham", "some_key", "Avalue")
it.addMetadata("wham", "some_key", "A value")
it.setUser(null, null, "Jamie")

val crumb = Breadcrumb(
"helloworld",
"hello world",
BreadcrumbType.MANUAL,
mutableMapOf(),
Date(0),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,53 @@ internal fun verifyJsonMatches(map: Map<String, Any>, resourceName: String) {
validateJson(resourceName, json)
}

/**
* To help comparing JSON we remove any whitespace that hasn't been quoted. So:
* ```
* {
* "some key": "Some Value"
* }
* ```
*
* Becomes:
* ```
* {"some key":"Some Value"}
* ```
*/
private fun removeUnquotedWhitespace(json: String): String {
val builder = StringBuilder(json.length)
var quoted = false
var index = 0

while (index < json.length) {
val ch = json[index++]

if (quoted) {
when (ch) {
'\"' -> quoted = false
'\\' -> {
builder.append('\\')
builder.append(json[index++])
}
}

builder.append(ch)
} else if (!ch.isWhitespace()) {
builder.append(ch)

if (ch == '\"') {
quoted = true
}
}
}

return builder.toString()
}

internal fun validateJson(resourceName: String, json: String) {
val whitespace = "\\s".toRegex()
val rawJson = JsonParser().read(resourceName)
val expectedJson = rawJson.replace(whitespace, "")
val generatedJson = json.replace(whitespace, "")
val expectedJson = removeUnquotedWhitespace(rawJson)
val generatedJson = removeUnquotedWhitespace(json)
Assert.assertEquals(expectedJson, generatedJson)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"codeBundleId": "foo-99",
"id": "com.example.foo",
"releaseStage": "test-stage",
"type": "ReactNative",
"type": "React Native",
"version": "1.2.3",
"versionCode": 55
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"codeBundleId": "foo-99",
"id": "com.example.foo",
"releaseStage": "test-stage",
"type": "ReactNative",
"type": "React Native",
"version": "1.2.3",
"versionCode": 55,
"duration": 0,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"timestamp": "1970-01-01T00:00:00.000Z",
"name": "helloworld",
"name": "hello world",
"type": "manual",
"metaData": {}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[
{
"timestamp": "1970-01-01T00:00:00.000Z",
"name": "helloworld",
"name": "hello world",
"type": "manual",
"metaData": {
"direction": "left"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"foo": 55
},
"wham": {
"some_key": "Avalue"
"some_key": "A value"
},
"device": {
"bar": true
Expand Down Expand Up @@ -53,7 +53,7 @@
"breadcrumbs": [
{
"timestamp": "1970-01-01T00:00:00.000Z",
"name": "helloworld",
"name": "hello world",
"type": "manual",
"metaData": {}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1 +1 @@
[{"name":"Jane","timestamp":"2018-10-08T12:07:09Z","type":"user","metaData":{"str":"Foo"}},{"name":"Something went wrong","timestamp":"2018-10-08T12:07:11Z","type":"manual","metaData":{"bool":true}},{"name":"MainActivity","timestamp":"2018-10-08T12:07:15Z","type":"navigation"},{"name":"Updated store","timestamp":"2018-10-08T12:07:16Z","type":"state"}]
[{"name":"Jane","timestamp":"2018-10-08T12:07:09Z","type":"user","metaData":{"str":"Foo"}},{"name":"Something went wrong","timestamp":"2018-10-08T12:07:11Z","type":"manual","metaData":{"bool":true}},{"name":"MainActivity","timestamp":"2018-10-08T12:07:15.563Z","type":"navigation"},{"name":"Updated store","timestamp":"2018-10-08T12:07:16Z","type":"state"}]
62 changes: 61 additions & 1 deletion bugsnag-plugin-android-ndk/src/main/jni/utils/serializer.c
Original file line number Diff line number Diff line change
Expand Up @@ -830,6 +830,54 @@ void bsg_serialize_stackframe(bugsnag_stackframe *stackframe, bool is_pc,
json_array_append_value(stacktrace, frame_val);
}

#if defined(__i386__) || defined(__arm__)
#define TIMESTAMP_T long long
#define TIMESTAMP_DECODE atoll
#define TIMESTAMP_MILLIS_FORMAT "%s.%03lldZ"
#elif defined(__x86_64__) || defined(__aarch64__)
#define TIMESTAMP_T long
#define TIMESTAMP_DECODE atol
#define TIMESTAMP_MILLIS_FORMAT "%s.%03ldZ"
#endif
/**
* Convert a string representing the number of milliseconds since the epoch
* into the date format "yyyy-MM-ddTHH:mm:ss.SSSZ". Safe for all dates earlier
* than 2038.
*
* @param source the timestamp string, should be something like: 1636710533109
* @param dest a buffer large enough to hold the 24 characters required in the
* date format
*
* @return true if the conversion succeeded
*/
static bool timestamp_to_iso8601_millis(const char *source, char *dest) {
TIMESTAMP_T timestamp = TIMESTAMP_DECODE(source);
if (timestamp) {
time_t seconds = timestamp / 1000;
TIMESTAMP_T milliseconds = timestamp - (seconds * 1000LL);
if (milliseconds > 1000) { // round to nearest second
seconds++;
milliseconds -= 1000;
}
struct tm timer;
// gmtime(3) can fail if "the year does not fit into an integer". Hopefully
// nobody is running this code by then.
if (gmtime_r(&seconds, &timer)) {
char buffer[26];
strftime(buffer, 26, "%Y-%m-%dT%H:%M:%S", &timer);
sprintf(dest, TIMESTAMP_MILLIS_FORMAT, buffer, milliseconds);
return true;
} else {
BUGSNAG_LOG("Hello, people of the far future! Please use your time "
"machine to file a bug in the year 2021.");
}
}
return false;
}
#undef TIMESTAMP_T
#undef TIMESTAMP_DECODE
#undef TIMESTAMP_MILLIS_FORMAT

void bsg_serialize_breadcrumbs(const bugsnag_event *event, JSON_Array *crumbs) {
if (event->crumb_count > 0) {
int current_index = event->crumb_first_index;
Expand All @@ -840,7 +888,19 @@ void bsg_serialize_breadcrumbs(const bugsnag_event *event, JSON_Array *crumbs) {

bugsnag_breadcrumb breadcrumb = event->breadcrumbs[current_index];
json_object_set_string(crumb, "name", breadcrumb.name);
json_object_set_string(crumb, "timestamp", breadcrumb.timestamp);
// check whether to decode milliseconds into ISO8601 date format
if (breadcrumb.timestamp[0] == 't') {
char *unix_timestamp_str = breadcrumb.timestamp + 1;
char buffer[32];
if (timestamp_to_iso8601_millis(unix_timestamp_str, buffer)) {
json_object_set_string(crumb, "timestamp", buffer);
} else {
// at least we tried.
json_object_set_string(crumb, "timestamp", unix_timestamp_str);
}
} else {
json_object_set_string(crumb, "timestamp", breadcrumb.timestamp);
}
json_object_set_string(crumb, "type",
bsg_crumb_type_string(breadcrumb.type));
bsg_serialize_breadcrumb_metadata(breadcrumb.metadata, crumb);
Expand Down
4 changes: 2 additions & 2 deletions bugsnag-plugin-android-ndk/src/test/cpp/test_serializer.c
Original file line number Diff line number Diff line change
Expand Up @@ -140,11 +140,11 @@ void loadBreadcrumbsTestCase(bugsnag_event *event) {
strcpy(data->values[0].name, "bool");
data->values[0].bool_value = true;

// third breadcrumb
// third breadcrumb - using updated timestamp format
crumb = &event->breadcrumbs[0];
crumb->type = BSG_CRUMB_NAVIGATION;
strcpy(crumb->name, "MainActivity");
strcpy(crumb->timestamp, "2018-10-08T12:07:15Z");
strcpy(crumb->timestamp, "t1539000435563");

// metadata
data = &crumb->metadata;
Expand Down
10 changes: 10 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,17 @@ services:
environment:
DEBUG:
BUILDKITE:
BUILDKITE_BRANCH:
BUILDKITE_BUILD_CREATOR:
BUILDKITE_BUILD_NUMBER:
BUILDKITE_BUILD_URL:
BUILDKITE_LABEL:
BUILDKITE_MESSAGE:
BUILDKITE_PIPELINE_NAME:
BUILDKITE_REPO:
BUILDKITE_RETRY_COUNT:
BUILDKITE_STEP_KEY:
MAZE_BUGSNAG_API_KEY:
BROWSER_STACK_USERNAME:
BROWSER_STACK_ACCESS_KEY:
SAUCE_LABS_USERNAME:
Expand Down