From 26394433a8803e54ef276c1fe24a1601e18d4adb Mon Sep 17 00:00:00 2001 From: Manoel Aranda Neto Date: Sun, 20 Feb 2022 12:50:39 +0100 Subject: [PATCH 01/15] Add missing contexts --- .../flutter/generated_plugin_registrant.cc | 14 +++ .../flutter/generated_plugin_registrant.h | 15 +++ .../windows/flutter/generated_plugins.cmake | 16 ++++ .../Classes/SentryFlutterPluginApple.swift | 38 +++++++- flutter/lib/src/default_integrations.dart | 93 +++++++++++++++++-- 5 files changed, 168 insertions(+), 8 deletions(-) create mode 100644 flutter/example/windows/flutter/generated_plugin_registrant.cc create mode 100644 flutter/example/windows/flutter/generated_plugin_registrant.h create mode 100644 flutter/example/windows/flutter/generated_plugins.cmake diff --git a/flutter/example/windows/flutter/generated_plugin_registrant.cc b/flutter/example/windows/flutter/generated_plugin_registrant.cc new file mode 100644 index 0000000000..1d5d43fa78 --- /dev/null +++ b/flutter/example/windows/flutter/generated_plugin_registrant.cc @@ -0,0 +1,14 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#include "generated_plugin_registrant.h" + +#include + +void RegisterPlugins(flutter::PluginRegistry* registry) { + SentryFlutterPluginRegisterWithRegistrar( + registry->GetRegistrarForPlugin("SentryFlutterPlugin")); +} diff --git a/flutter/example/windows/flutter/generated_plugin_registrant.h b/flutter/example/windows/flutter/generated_plugin_registrant.h new file mode 100644 index 0000000000..dc139d85a9 --- /dev/null +++ b/flutter/example/windows/flutter/generated_plugin_registrant.h @@ -0,0 +1,15 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#ifndef GENERATED_PLUGIN_REGISTRANT_ +#define GENERATED_PLUGIN_REGISTRANT_ + +#include + +// Registers Flutter plugins. +void RegisterPlugins(flutter::PluginRegistry* registry); + +#endif // GENERATED_PLUGIN_REGISTRANT_ diff --git a/flutter/example/windows/flutter/generated_plugins.cmake b/flutter/example/windows/flutter/generated_plugins.cmake new file mode 100644 index 0000000000..820bdca520 --- /dev/null +++ b/flutter/example/windows/flutter/generated_plugins.cmake @@ -0,0 +1,16 @@ +# +# Generated file, do not edit. +# + +list(APPEND FLUTTER_PLUGIN_LIST + sentry_flutter +) + +set(PLUGIN_BUNDLED_LIBRARIES) + +foreach(plugin ${FLUTTER_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/windows plugins/${plugin}) + target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) + list(APPEND PLUGIN_BUNDLED_LIBRARIES $) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) +endforeach(plugin) diff --git a/flutter/ios/Classes/SentryFlutterPluginApple.swift b/flutter/ios/Classes/SentryFlutterPluginApple.swift index ee1b9e8967..0188e94713 100644 --- a/flutter/ios/Classes/SentryFlutterPluginApple.swift +++ b/flutter/ios/Classes/SentryFlutterPluginApple.swift @@ -73,17 +73,51 @@ public class SentryFlutterPluginApple: NSObject, FlutterPlugin { private func loadContexts(result: @escaping FlutterResult) { SentrySDK.configureScope { scope in + // scope.setTag(value: "test", key: "test") + // scope.setExtra(value: "test", key: "test") + // scope.setUser(User(userId: "test")) + // scope.setDist("test") + // scope.setFingerprint(["test"]) + // scope.setLevel(SentryLevel.warning) + // scope.add(Breadcrumb(level: SentryLevel.info, category: "test")) + // scope.setEnvironment("test") + let serializedScope = scope.serialize() let context = serializedScope["context"] var infos = ["contexts": context] + if let tags = serializedScope["tags"] as? [String: String] { + infos["tags"] = tags + } + if let extra = serializedScope["extra"] as? [String: Any] { + infos["extra"] = extra + } + if let user = serializedScope["user"] as? [String: Any] { + infos["user"] = user + } + if let dist = serializedScope["dist"] as? String { + infos["dist"] = dist + } + if let environment = serializedScope["environment"] as? String { + infos["environment"] = environment + } + if let fingerprint = serializedScope["fingerprint"] as? [String] { + infos["fingerprint"] = fingerprint + } + if let level = serializedScope["level"] as? String { + infos["level"] = level + } + if let breadcrumbs = serializedScope["breadcrumbs"] as? [[String: Any]] { + infos["breadcrumbs"] = breadcrumbs + } + if let integrations = self.sentryOptions?.integrations { infos["integrations"] = integrations } - if let sentryOptions = self.sentryOptions { - infos["package"] = ["version": sentryOptions.sdkInfo.version, "sdk_name": "cocoapods:sentry-cocoa"] + if let sdkInfo = self.sentryOptions?.sdkInfo { + infos["package"] = ["version": sdkInfo.version, "sdk_name": "cocoapods:sentry-cocoa"] } result(infos) diff --git a/flutter/lib/src/default_integrations.dart b/flutter/lib/src/default_integrations.dart index f9582e5f5e..858eafdabe 100644 --- a/flutter/lib/src/default_integrations.dart +++ b/flutter/lib/src/default_integrations.dart @@ -175,9 +175,10 @@ class _LoadContextsIntegrationEventProcessor extends EventProcessor { final infos = Map.from( await (_channel.invokeMethod('loadContexts')), ); - if (infos['contexts'] != null) { + final contextsMap = infos['contexts']; + if (contextsMap != null) { final contexts = Contexts.fromJson( - Map.from(infos['contexts'] as Map), + Map.from(contextsMap as Map), ); final eventContexts = event.contexts.clone(); @@ -195,15 +196,95 @@ class _LoadContextsIntegrationEventProcessor extends EventProcessor { event = event.copyWith(contexts: eventContexts); } - if (infos['integrations'] != null) { - final integrations = List.from(infos['integrations'] as List); + final tagsMap = infos['tags']; + if (tagsMap != null) { + final tags = event.tags ?? {}; + final newTags = Map.from(tagsMap as Map); + + for (final tag in newTags.entries) { + if (!tags.containsKey(tag.key)) { + tags[tag.key] = tag.value; + } + } + event = event.copyWith(tags: tags); + } + + final extraMap = infos['extra']; + if (extraMap != null) { + final extras = event.extra ?? {}; + final newExtras = Map.from(extraMap as Map); + + for (final extra in newExtras.entries) { + if (!extras.containsKey(extra.key)) { + extras[extra.key] = extra.value; + } + } + event = event.copyWith(extra: extras); + } + + final userMap = infos['user']; + if (event.user == null && userMap != null) { + final user = Map.from(userMap as Map); + event = event.copyWith(user: SentryUser.fromJson(user)); + } + + final distString = infos['dist']; + if (event.dist == null && distString != null) { + event = event.copyWith(dist: distString as String); + } + + final environmentString = infos['environment']; + if (event.environment == null && environmentString != null) { + event = event.copyWith(environment: environmentString as String); + } + + final fingerprintList = infos['fingerprint']; + if (fingerprintList != null) { + final eventFingerprints = event.fingerprint ?? []; + final newFingerprint = List.from(fingerprintList as List); + + for (final fingerprint in newFingerprint) { + if (!eventFingerprints.contains(fingerprint)) { + eventFingerprints.add(fingerprint); + } + } + event = event.copyWith(fingerprint: eventFingerprints); + } + + final levelString = infos['level']; + if (event.level == null && levelString != null) { + event = event.copyWith(level: SentryLevel.fromName(levelString)); + } + + final breadcrumbsList = infos['breadcrumbs']; + if (breadcrumbsList != null) { + final breadcrumbs = event.breadcrumbs ?? []; + // for some reason I can't use Map, it fails. + final newBreadcrumbs = + List>.from(breadcrumbsList as List); + + for (final breadcrumb in newBreadcrumbs) { + final newBreadcrumb = Map.from(breadcrumb); + final crumb = Breadcrumb.fromJson(newBreadcrumb); + breadcrumbs.add(crumb); + } + + // TODO: sort by timestamp + + event = event.copyWith(breadcrumbs: breadcrumbs); + } + + final integrationsList = infos['integrations']; + if (integrationsList != null) { + final integrations = List.from(integrationsList as List); final sdk = event.sdk ?? _options.sdk; integrations.forEach(sdk.addIntegration); event = event.copyWith(sdk: sdk); } - if (infos['package'] != null) { - final package = Map.from(infos['package'] as Map); + final packageMap = infos['package']; + if (packageMap != null) { + final package = Map.from(packageMap as Map); final sdk = event.sdk ?? _options.sdk; sdk.addPackage(package['sdk_name']!, package['version']!); event = event.copyWith(sdk: sdk); From 933979a84c18bc1a37c1f34f3d722756b0891382 Mon Sep 17 00:00:00 2001 From: Manoel Aranda Neto Date: Sun, 20 Feb 2022 12:50:57 +0100 Subject: [PATCH 02/15] remove --- .../flutter/generated_plugin_registrant.cc | 14 -------------- .../flutter/generated_plugin_registrant.h | 15 --------------- .../windows/flutter/generated_plugins.cmake | 16 ---------------- 3 files changed, 45 deletions(-) delete mode 100644 flutter/example/windows/flutter/generated_plugin_registrant.cc delete mode 100644 flutter/example/windows/flutter/generated_plugin_registrant.h delete mode 100644 flutter/example/windows/flutter/generated_plugins.cmake diff --git a/flutter/example/windows/flutter/generated_plugin_registrant.cc b/flutter/example/windows/flutter/generated_plugin_registrant.cc deleted file mode 100644 index 1d5d43fa78..0000000000 --- a/flutter/example/windows/flutter/generated_plugin_registrant.cc +++ /dev/null @@ -1,14 +0,0 @@ -// -// Generated file. Do not edit. -// - -// clang-format off - -#include "generated_plugin_registrant.h" - -#include - -void RegisterPlugins(flutter::PluginRegistry* registry) { - SentryFlutterPluginRegisterWithRegistrar( - registry->GetRegistrarForPlugin("SentryFlutterPlugin")); -} diff --git a/flutter/example/windows/flutter/generated_plugin_registrant.h b/flutter/example/windows/flutter/generated_plugin_registrant.h deleted file mode 100644 index dc139d85a9..0000000000 --- a/flutter/example/windows/flutter/generated_plugin_registrant.h +++ /dev/null @@ -1,15 +0,0 @@ -// -// Generated file. Do not edit. -// - -// clang-format off - -#ifndef GENERATED_PLUGIN_REGISTRANT_ -#define GENERATED_PLUGIN_REGISTRANT_ - -#include - -// Registers Flutter plugins. -void RegisterPlugins(flutter::PluginRegistry* registry); - -#endif // GENERATED_PLUGIN_REGISTRANT_ diff --git a/flutter/example/windows/flutter/generated_plugins.cmake b/flutter/example/windows/flutter/generated_plugins.cmake deleted file mode 100644 index 820bdca520..0000000000 --- a/flutter/example/windows/flutter/generated_plugins.cmake +++ /dev/null @@ -1,16 +0,0 @@ -# -# Generated file, do not edit. -# - -list(APPEND FLUTTER_PLUGIN_LIST - sentry_flutter -) - -set(PLUGIN_BUNDLED_LIBRARIES) - -foreach(plugin ${FLUTTER_PLUGIN_LIST}) - add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/windows plugins/${plugin}) - target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) - list(APPEND PLUGIN_BUNDLED_LIBRARIES $) - list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) -endforeach(plugin) From a1ff197c3a6a336085e0314ad390c00e0d2e4918 Mon Sep 17 00:00:00 2001 From: Manoel Aranda Neto Date: Sun, 20 Feb 2022 18:10:55 +0100 Subject: [PATCH 03/15] fix --- .../flutter/generated_plugin_registrant.cc | 14 ++++++++++++++ .../flutter/generated_plugin_registrant.h | 15 +++++++++++++++ .../windows/flutter/generated_plugins.cmake | 16 ++++++++++++++++ flutter/lib/src/default_integrations.dart | 8 ++++---- 4 files changed, 49 insertions(+), 4 deletions(-) create mode 100644 flutter/example/windows/flutter/generated_plugin_registrant.cc create mode 100644 flutter/example/windows/flutter/generated_plugin_registrant.h create mode 100644 flutter/example/windows/flutter/generated_plugins.cmake diff --git a/flutter/example/windows/flutter/generated_plugin_registrant.cc b/flutter/example/windows/flutter/generated_plugin_registrant.cc new file mode 100644 index 0000000000..1d5d43fa78 --- /dev/null +++ b/flutter/example/windows/flutter/generated_plugin_registrant.cc @@ -0,0 +1,14 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#include "generated_plugin_registrant.h" + +#include + +void RegisterPlugins(flutter::PluginRegistry* registry) { + SentryFlutterPluginRegisterWithRegistrar( + registry->GetRegistrarForPlugin("SentryFlutterPlugin")); +} diff --git a/flutter/example/windows/flutter/generated_plugin_registrant.h b/flutter/example/windows/flutter/generated_plugin_registrant.h new file mode 100644 index 0000000000..dc139d85a9 --- /dev/null +++ b/flutter/example/windows/flutter/generated_plugin_registrant.h @@ -0,0 +1,15 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#ifndef GENERATED_PLUGIN_REGISTRANT_ +#define GENERATED_PLUGIN_REGISTRANT_ + +#include + +// Registers Flutter plugins. +void RegisterPlugins(flutter::PluginRegistry* registry); + +#endif // GENERATED_PLUGIN_REGISTRANT_ diff --git a/flutter/example/windows/flutter/generated_plugins.cmake b/flutter/example/windows/flutter/generated_plugins.cmake new file mode 100644 index 0000000000..820bdca520 --- /dev/null +++ b/flutter/example/windows/flutter/generated_plugins.cmake @@ -0,0 +1,16 @@ +# +# Generated file, do not edit. +# + +list(APPEND FLUTTER_PLUGIN_LIST + sentry_flutter +) + +set(PLUGIN_BUNDLED_LIBRARIES) + +foreach(plugin ${FLUTTER_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/windows plugins/${plugin}) + target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) + list(APPEND PLUGIN_BUNDLED_LIBRARIES $) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) +endforeach(plugin) diff --git a/flutter/lib/src/default_integrations.dart b/flutter/lib/src/default_integrations.dart index 858eafdabe..7daf59c63d 100644 --- a/flutter/lib/src/default_integrations.dart +++ b/flutter/lib/src/default_integrations.dart @@ -259,9 +259,7 @@ class _LoadContextsIntegrationEventProcessor extends EventProcessor { final breadcrumbsList = infos['breadcrumbs']; if (breadcrumbsList != null) { final breadcrumbs = event.breadcrumbs ?? []; - // for some reason I can't use Map, it fails. - final newBreadcrumbs = - List>.from(breadcrumbsList as List); + final newBreadcrumbs = List.from(breadcrumbsList as List); for (final breadcrumb in newBreadcrumbs) { final newBreadcrumb = Map.from(breadcrumb); @@ -269,7 +267,9 @@ class _LoadContextsIntegrationEventProcessor extends EventProcessor { breadcrumbs.add(crumb); } - // TODO: sort by timestamp + breadcrumbs.sort((a, b) { + return a.timestamp.compareTo(b.timestamp); + }); event = event.copyWith(breadcrumbs: breadcrumbs); } From b933e3028ba8622cc484a912a827d82e449eee69 Mon Sep 17 00:00:00 2001 From: Manoel Aranda Neto Date: Sun, 20 Feb 2022 18:11:04 +0100 Subject: [PATCH 04/15] remove --- .../flutter/generated_plugin_registrant.cc | 14 -------------- .../flutter/generated_plugin_registrant.h | 15 --------------- .../windows/flutter/generated_plugins.cmake | 16 ---------------- 3 files changed, 45 deletions(-) delete mode 100644 flutter/example/windows/flutter/generated_plugin_registrant.cc delete mode 100644 flutter/example/windows/flutter/generated_plugin_registrant.h delete mode 100644 flutter/example/windows/flutter/generated_plugins.cmake diff --git a/flutter/example/windows/flutter/generated_plugin_registrant.cc b/flutter/example/windows/flutter/generated_plugin_registrant.cc deleted file mode 100644 index 1d5d43fa78..0000000000 --- a/flutter/example/windows/flutter/generated_plugin_registrant.cc +++ /dev/null @@ -1,14 +0,0 @@ -// -// Generated file. Do not edit. -// - -// clang-format off - -#include "generated_plugin_registrant.h" - -#include - -void RegisterPlugins(flutter::PluginRegistry* registry) { - SentryFlutterPluginRegisterWithRegistrar( - registry->GetRegistrarForPlugin("SentryFlutterPlugin")); -} diff --git a/flutter/example/windows/flutter/generated_plugin_registrant.h b/flutter/example/windows/flutter/generated_plugin_registrant.h deleted file mode 100644 index dc139d85a9..0000000000 --- a/flutter/example/windows/flutter/generated_plugin_registrant.h +++ /dev/null @@ -1,15 +0,0 @@ -// -// Generated file. Do not edit. -// - -// clang-format off - -#ifndef GENERATED_PLUGIN_REGISTRANT_ -#define GENERATED_PLUGIN_REGISTRANT_ - -#include - -// Registers Flutter plugins. -void RegisterPlugins(flutter::PluginRegistry* registry); - -#endif // GENERATED_PLUGIN_REGISTRANT_ diff --git a/flutter/example/windows/flutter/generated_plugins.cmake b/flutter/example/windows/flutter/generated_plugins.cmake deleted file mode 100644 index 820bdca520..0000000000 --- a/flutter/example/windows/flutter/generated_plugins.cmake +++ /dev/null @@ -1,16 +0,0 @@ -# -# Generated file, do not edit. -# - -list(APPEND FLUTTER_PLUGIN_LIST - sentry_flutter -) - -set(PLUGIN_BUNDLED_LIBRARIES) - -foreach(plugin ${FLUTTER_PLUGIN_LIST}) - add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/windows plugins/${plugin}) - target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) - list(APPEND PLUGIN_BUNDLED_LIBRARIES $) - list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) -endforeach(plugin) From 6d936d7fde2094cfbade57f07fbed1a27ecfaeaf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Denis=20Andra=C5=A1ec?= Date: Thu, 21 Apr 2022 10:50:23 +0200 Subject: [PATCH 05/15] add tests for current properties --- dart/lib/src/protocol/sentry_user.dart | 8 +- .../test/load_contexts_integrations_test.dart | 172 +++++++++++++++++- 2 files changed, 178 insertions(+), 2 deletions(-) diff --git a/dart/lib/src/protocol/sentry_user.dart b/dart/lib/src/protocol/sentry_user.dart index efe21e0cdd..5900b0113a 100644 --- a/dart/lib/src/protocol/sentry_user.dart +++ b/dart/lib/src/protocol/sentry_user.dart @@ -63,12 +63,18 @@ class SentryUser { /// Deserializes a [SentryUser] from JSON [Map]. factory SentryUser.fromJson(Map json) { + Map? extras; + if (json['extras'] != null) { + extras = Map.from(json['extras'] as Map); + } else { + extras = null; + } return SentryUser( id: json['id'], username: json['username'], email: json['email'], ipAddress: json['ip_address'], - extras: json['extras'], + extras: extras, ); } diff --git a/flutter/test/load_contexts_integrations_test.dart b/flutter/test/load_contexts_integrations_test.dart index d19cd9bcab..ad2cfff9c0 100644 --- a/flutter/test/load_contexts_integrations_test.dart +++ b/flutter/test/load_contexts_integrations_test.dart @@ -28,6 +28,13 @@ void main() { SentryEvent getEvent( {SdkVersion? sdk, Map? tags, + Map? extra, + SentryUser? user, + String? dist, + String? environment, + List? fingerprint, + SentryLevel? level, + List? breadcrumbs, List integrations = const ['EventIntegration'], List packages = const [ SentryPackage('event-package', '2.0') @@ -39,6 +46,13 @@ void main() { packages: packages, ), tags: tags, + extra: extra, + user: user, + dist: dist, + environment: environment, + fingerprint: fingerprint, + level: level, + breadcrumbs: breadcrumbs, ); } @@ -265,6 +279,144 @@ void main() { expect(event?.tags?.containsKey('event.environment'), false); }, ); + + test('should merge in tags from native without overriding flutter keys', () async { + final integration = fixture.getSut(); + integration(fixture.hub, fixture.options); + + final e = getEvent(tags: {'key': 'flutter', 'key-a': 'flutter'}); + final event = await fixture.options.eventProcessors.first.apply(e); + + expect(event?.tags?['key'], 'flutter'); + expect(event?.tags?['key-a'], 'flutter'); + expect(event?.tags?['key-b'], 'native'); + }); + + test('should merge in extra from native without overriding flutter keys', () async { + final integration = fixture.getSut(); + integration(fixture.hub, fixture.options); + + final e = getEvent(extra: {'key': 'flutter', 'key-a': 'flutter'}); + final event = await fixture.options.eventProcessors.first.apply(e); + + expect(event?.extra?['key'], 'flutter'); + expect(event?.extra?['key-a'], 'flutter'); + expect(event?.extra?['key-b'], 'native'); + }); + + test('should set user from native', () async { + final integration = fixture.getSut(); + integration(fixture.hub, fixture.options); + + final e = getEvent(); + final event = await fixture.options.eventProcessors.first.apply(e); + + expect(event?.user?.id, '196E065A-AAF7-409A-9A6C-A81F40274CB9'); + expect(event?.user?.username, 'fixture-username'); + expect(event?.user?.email, 'fixture-email'); + expect(event?.user?.ipAddress, 'fixture-ip_address'); + expect(event?.user?.extras?['key'], 'value'); + }); + + test('should not override user with native', () async { + final integration = fixture.getSut(); + integration(fixture.hub, fixture.options); + + final e = getEvent(user: SentryUser(id: 'abc')); + final event = await fixture.options.eventProcessors.first.apply(e); + + expect(event?.user?.id, 'abc'); + }); + + test('should set dist from native', () async { + final integration = fixture.getSut(); + integration(fixture.hub, fixture.options); + + final e = getEvent(); + final event = await fixture.options.eventProcessors.first.apply(e); + + expect(event?.dist, 'fixture-dist'); + }); + + test('should not override dist with native', () async { + final integration = fixture.getSut(); + integration(fixture.hub, fixture.options); + + final e = getEvent(dist: 'abc'); + final event = await fixture.options.eventProcessors.first.apply(e); + + expect(event?.dist, 'abc'); + }); + + test('should set environment from native', () async { + final integration = fixture.getSut(); + integration(fixture.hub, fixture.options); + + final e = getEvent(); + final event = await fixture.options.eventProcessors.first.apply(e); + + expect(event?.environment, 'fixture-environment'); + }); + + test('should not override environment with native', () async { + final integration = fixture.getSut(); + integration(fixture.hub, fixture.options); + + final e = getEvent(environment: 'abc'); + final event = await fixture.options.eventProcessors.first.apply(e); + + expect(event?.environment, 'abc'); + }); + + test('should merge in fingerprint from native without duplicating entries', () async { + final integration = fixture.getSut(); + integration(fixture.hub, fixture.options); + + final e = getEvent(fingerprint: ['fingerprint-a', 'fingerprint-b']); + final event = await fixture.options.eventProcessors.first.apply(e); + + expect(event?.fingerprint, ['fingerprint-a', 'fingerprint-b']); + }); + + test('should set level from native', () async { + final integration = fixture.getSut(); + integration(fixture.hub, fixture.options); + + final e = getEvent(); + final event = await fixture.options.eventProcessors.first.apply(e); + + expect(event?.level, SentryLevel.error); + }); + + test('should not override level with native', () async { + final integration = fixture.getSut(); + integration(fixture.hub, fixture.options); + + final e = getEvent(level: SentryLevel.fatal); + final event = await fixture.options.eventProcessors.first.apply(e); + + expect(event?.level, SentryLevel.fatal); + }); + + test('should merge in breadcrumbs sorted by timestamp', () async { + final integration = fixture.getSut(); + integration(fixture.hub, fixture.options); + + final breadcrumb = Breadcrumb( + message: 'flutter-crumb', + timestamp: DateTime.fromMillisecondsSinceEpoch(100), + ); + final e = getEvent(breadcrumbs: [breadcrumb]); + final event = await fixture.options.eventProcessors.first.apply(e); + + expect(event?.breadcrumbs?[0].message, 'native-crumb'); + expect(event?.breadcrumbs?[1].message, 'flutter-crumb'); + }); + + test('other properties', () async { + // TODO Which ones are relevant? + // platform, logger, serverName, release, modules, message, exceptions, threads, transaction, level, culprit, sdk, request, debugMeta, type + }); } class Fixture { @@ -288,7 +440,25 @@ class Fixture { 'runtime': {'name': 'RT1'}, 'theme': 'material', }, - 'user': {'id': '196E065A-AAF7-409A-9A6C-A81F40274CB9'} + 'user': { + 'id': '196E065A-AAF7-409A-9A6C-A81F40274CB9', + 'username': 'fixture-username', + 'email': 'fixture-email', + 'ip_address': 'fixture-ip_address', + 'extras': {'key': 'value'}, + }, + 'tags': {'key-a': 'native', 'key-b': 'native'}, + 'extra': {'key-a': 'native', 'key-b': 'native'}, + 'dist': 'fixture-dist', + 'environment': 'fixture-environment', + 'fingerprint': ['fingerprint-a'], + 'level': 'error', + 'breadcrumbs': [ + { + 'timestamp': '1970-01-01T01:00:00.000', + 'message': 'native-crumb', + } + ] }}) { channel.setMockMethodCallHandler((MethodCall methodCall) async { called = true; From 4b52f2cbdef26d988e829cf28d92d04abe19bbe5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Denis=20Andra=C5=A1ec?= Date: Mon, 25 Apr 2022 11:44:12 +0200 Subject: [PATCH 06/15] only run blocks if maps are not empty --- flutter/lib/src/default_integrations.dart | 58 +++++++++++------------ 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/flutter/lib/src/default_integrations.dart b/flutter/lib/src/default_integrations.dart index a631ee016c..5a155d3e5b 100644 --- a/flutter/lib/src/default_integrations.dart +++ b/flutter/lib/src/default_integrations.dart @@ -175,10 +175,10 @@ class _LoadContextsIntegrationEventProcessor extends EventProcessor { final infos = Map.from( await (_channel.invokeMethod('loadContexts')), ); - final contextsMap = infos['contexts']; - if (contextsMap != null) { + final contextsMap = infos['contexts'] as Map?; + if (contextsMap != null && contextsMap.isNotEmpty) { final contexts = Contexts.fromJson( - Map.from(contextsMap as Map), + Map.from(contextsMap), ); final eventContexts = event.contexts.clone(); @@ -196,10 +196,10 @@ class _LoadContextsIntegrationEventProcessor extends EventProcessor { event = event.copyWith(contexts: eventContexts); } - final tagsMap = infos['tags']; - if (tagsMap != null) { + final tagsMap = infos['tags'] as Map?; + if (tagsMap != null && tagsMap.isNotEmpty) { final tags = event.tags ?? {}; - final newTags = Map.from(tagsMap as Map); + final newTags = Map.from(tagsMap); for (final tag in newTags.entries) { if (!tags.containsKey(tag.key)) { @@ -209,10 +209,10 @@ class _LoadContextsIntegrationEventProcessor extends EventProcessor { event = event.copyWith(tags: tags); } - final extraMap = infos['extra']; - if (extraMap != null) { + final extraMap = infos['extra'] as Map?; + if (extraMap != null && extraMap.isNotEmpty) { final extras = event.extra ?? {}; - final newExtras = Map.from(extraMap as Map); + final newExtras = Map.from(extraMap); for (final extra in newExtras.entries) { if (!extras.containsKey(extra.key)) { @@ -222,26 +222,26 @@ class _LoadContextsIntegrationEventProcessor extends EventProcessor { event = event.copyWith(extra: extras); } - final userMap = infos['user']; - if (event.user == null && userMap != null) { - final user = Map.from(userMap as Map); + final userMap = infos['user'] as Map?; + if (event.user == null && userMap != null && userMap.isNotEmpty) { + final user = Map.from(userMap); event = event.copyWith(user: SentryUser.fromJson(user)); } - final distString = infos['dist']; + final distString = infos['dist'] as String?; if (event.dist == null && distString != null) { - event = event.copyWith(dist: distString as String); + event = event.copyWith(dist: distString); } - final environmentString = infos['environment']; + final environmentString = infos['environment'] as String?; if (event.environment == null && environmentString != null) { - event = event.copyWith(environment: environmentString as String); + event = event.copyWith(environment: environmentString); } - final fingerprintList = infos['fingerprint']; - if (fingerprintList != null) { + final fingerprintList = infos['fingerprint'] as List?; + if (fingerprintList != null && fingerprintList.isNotEmpty) { final eventFingerprints = event.fingerprint ?? []; - final newFingerprint = List.from(fingerprintList as List); + final newFingerprint = List.from(fingerprintList); for (final fingerprint in newFingerprint) { if (!eventFingerprints.contains(fingerprint)) { @@ -251,15 +251,15 @@ class _LoadContextsIntegrationEventProcessor extends EventProcessor { event = event.copyWith(fingerprint: eventFingerprints); } - final levelString = infos['level']; + final levelString = infos['level'] as String?; if (event.level == null && levelString != null) { event = event.copyWith(level: SentryLevel.fromName(levelString)); } - final breadcrumbsList = infos['breadcrumbs']; - if (breadcrumbsList != null) { + final breadcrumbsList = infos['breadcrumbs'] as List?; + if (breadcrumbsList != null && breadcrumbsList.isNotEmpty) { final breadcrumbs = event.breadcrumbs ?? []; - final newBreadcrumbs = List.from(breadcrumbsList as List); + final newBreadcrumbs = List.from(breadcrumbsList); for (final breadcrumb in newBreadcrumbs) { final newBreadcrumb = Map.from(breadcrumb); @@ -274,9 +274,9 @@ class _LoadContextsIntegrationEventProcessor extends EventProcessor { event = event.copyWith(breadcrumbs: breadcrumbs); } - final integrationsList = infos['integrations']; - if (integrationsList != null) { - final integrations = List.from(integrationsList as List); + final integrationsList = infos['integrations'] as List?; + if (integrationsList != null && integrationsList.isNotEmpty) { + final integrations = List.from(integrationsList); final sdk = event.sdk ?? _options.sdk; for (final integration in integrations) { @@ -288,9 +288,9 @@ class _LoadContextsIntegrationEventProcessor extends EventProcessor { event = event.copyWith(sdk: sdk); } - final packageMap = infos['package']; - if (packageMap != null) { - final package = Map.from(packageMap as Map); + final packageMap = infos['package'] as Map?; + if (packageMap != null && packageMap.isNotEmpty) { + final package = Map.from(packageMap); final sdk = event.sdk ?? _options.sdk; final name = package['sdk_name']; From 4be2a7dbcf6a1d7dddb06e9bc2f880d0228fb2d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Denis=20Andra=C5=A1ec?= Date: Mon, 25 Apr 2022 13:39:13 +0200 Subject: [PATCH 07/15] remove else path --- dart/lib/src/protocol/sentry_user.dart | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/dart/lib/src/protocol/sentry_user.dart b/dart/lib/src/protocol/sentry_user.dart index 5900b0113a..812f9e8772 100644 --- a/dart/lib/src/protocol/sentry_user.dart +++ b/dart/lib/src/protocol/sentry_user.dart @@ -63,11 +63,9 @@ class SentryUser { /// Deserializes a [SentryUser] from JSON [Map]. factory SentryUser.fromJson(Map json) { - Map? extras; - if (json['extras'] != null) { - extras = Map.from(json['extras'] as Map); - } else { - extras = null; + var extras = json['extras'] as Map?; + if (extras != null) { + extras = Map.from(extras); } return SentryUser( id: json['id'], From 3063fe97d60e1442ccdb92c10d0c4ac119cf2428 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Denis=20Andra=C5=A1ec?= Date: Mon, 25 Apr 2022 13:40:21 +0200 Subject: [PATCH 08/15] fix compiler issue --- dart/lib/src/protocol/sentry_user.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dart/lib/src/protocol/sentry_user.dart b/dart/lib/src/protocol/sentry_user.dart index 812f9e8772..7b8c3237e8 100644 --- a/dart/lib/src/protocol/sentry_user.dart +++ b/dart/lib/src/protocol/sentry_user.dart @@ -63,9 +63,9 @@ class SentryUser { /// Deserializes a [SentryUser] from JSON [Map]. factory SentryUser.fromJson(Map json) { - var extras = json['extras'] as Map?; + var extras = json['extras']; if (extras != null) { - extras = Map.from(extras); + extras = Map.from(extras as Map); } return SentryUser( id: json['id'], From aeffe8114e2a467f2d3c8a4714781ff992eacebc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Denis=20Andra=C5=A1ec?= Date: Mon, 25 Apr 2022 13:40:43 +0200 Subject: [PATCH 09/15] remove not needed test --- flutter/test/load_contexts_integrations_test.dart | 5 ----- 1 file changed, 5 deletions(-) diff --git a/flutter/test/load_contexts_integrations_test.dart b/flutter/test/load_contexts_integrations_test.dart index ad2cfff9c0..a279f23d3f 100644 --- a/flutter/test/load_contexts_integrations_test.dart +++ b/flutter/test/load_contexts_integrations_test.dart @@ -412,11 +412,6 @@ void main() { expect(event?.breadcrumbs?[0].message, 'native-crumb'); expect(event?.breadcrumbs?[1].message, 'flutter-crumb'); }); - - test('other properties', () async { - // TODO Which ones are relevant? - // platform, logger, serverName, release, modules, message, exceptions, threads, transaction, level, culprit, sdk, request, debugMeta, type - }); } class Fixture { From e535725c4c2714f9e7f5f7af43115cbf3ecd1021 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Denis=20Andra=C5=A1ec?= Date: Mon, 25 Apr 2022 14:02:02 +0200 Subject: [PATCH 10/15] remove debug code --- flutter/ios/Classes/SentryFlutterPluginApple.swift | 9 --------- 1 file changed, 9 deletions(-) diff --git a/flutter/ios/Classes/SentryFlutterPluginApple.swift b/flutter/ios/Classes/SentryFlutterPluginApple.swift index 87e35eb173..191f4df1f8 100644 --- a/flutter/ios/Classes/SentryFlutterPluginApple.swift +++ b/flutter/ios/Classes/SentryFlutterPluginApple.swift @@ -83,15 +83,6 @@ public class SentryFlutterPluginApple: NSObject, FlutterPlugin { private func loadContexts(result: @escaping FlutterResult) { SentrySDK.configureScope { scope in - // scope.setTag(value: "test", key: "test") - // scope.setExtra(value: "test", key: "test") - // scope.setUser(User(userId: "test")) - // scope.setDist("test") - // scope.setFingerprint(["test"]) - // scope.setLevel(SentryLevel.warning) - // scope.add(Breadcrumb(level: SentryLevel.info, category: "test")) - // scope.setEnvironment("test") - let serializedScope = scope.serialize() let context = serializedScope["context"] From 11b012adb52538ef82f628749026933c130752c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Denis=20Andra=C5=A1ec?= Date: Mon, 25 Apr 2022 14:03:01 +0200 Subject: [PATCH 11/15] run format --- flutter/lib/src/default_integrations.dart | 2 +- flutter/test/load_contexts_integrations_test.dart | 9 ++++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/flutter/lib/src/default_integrations.dart b/flutter/lib/src/default_integrations.dart index 5a155d3e5b..3bff9cf850 100644 --- a/flutter/lib/src/default_integrations.dart +++ b/flutter/lib/src/default_integrations.dart @@ -233,7 +233,7 @@ class _LoadContextsIntegrationEventProcessor extends EventProcessor { event = event.copyWith(dist: distString); } - final environmentString = infos['environment'] as String?; + final environmentString = infos['environment'] as String?; if (event.environment == null && environmentString != null) { event = event.copyWith(environment: environmentString); } diff --git a/flutter/test/load_contexts_integrations_test.dart b/flutter/test/load_contexts_integrations_test.dart index a279f23d3f..552c06e1dc 100644 --- a/flutter/test/load_contexts_integrations_test.dart +++ b/flutter/test/load_contexts_integrations_test.dart @@ -280,7 +280,8 @@ void main() { }, ); - test('should merge in tags from native without overriding flutter keys', () async { + test('should merge in tags from native without overriding flutter keys', + () async { final integration = fixture.getSut(); integration(fixture.hub, fixture.options); @@ -292,7 +293,8 @@ void main() { expect(event?.tags?['key-b'], 'native'); }); - test('should merge in extra from native without overriding flutter keys', () async { + test('should merge in extra from native without overriding flutter keys', + () async { final integration = fixture.getSut(); integration(fixture.hub, fixture.options); @@ -368,7 +370,8 @@ void main() { expect(event?.environment, 'abc'); }); - test('should merge in fingerprint from native without duplicating entries', () async { + test('should merge in fingerprint from native without duplicating entries', + () async { final integration = fixture.getSut(); integration(fixture.hub, fixture.options); From 5d64bc69836704b4851eee8605ae4b60f2460fbb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Denis=20Andra=C5=A1ec?= Date: Mon, 25 Apr 2022 14:07:47 +0200 Subject: [PATCH 12/15] add changelog entry --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c339615ac6..06ac70238b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +## Unreleased: + +* Feat: Add missing iOS contexts (#761) + ## 6.5.0-beta.2 * Fix: Do not set the transaction to scope if no op (#828) From 82306b29e4d5dbeccd246148f0e818f5c364f610 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Denis=20Andra=C5=A1ec?= Date: Mon, 25 Apr 2022 14:11:23 +0200 Subject: [PATCH 13/15] Change changelog entry --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 40b8d614af..338f92f7c8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,8 @@ ## Unreleased: -* Feat: Add missing iOS contexts (#761) +* Fix: Add missing iOS contexts (#761) + ## 6.5.1 - Update event contexts (#838) From 739f5c03e5c4d52bfdd0767d5cfea582afd7fa36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Denis=20Andra=C5=A1ec?= Date: Mon, 25 Apr 2022 16:04:34 +0200 Subject: [PATCH 14/15] print timestamps --- flutter/test/load_contexts_integrations_test.dart | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/flutter/test/load_contexts_integrations_test.dart b/flutter/test/load_contexts_integrations_test.dart index 552c06e1dc..9f127ba82f 100644 --- a/flutter/test/load_contexts_integrations_test.dart +++ b/flutter/test/load_contexts_integrations_test.dart @@ -412,7 +412,9 @@ void main() { final e = getEvent(breadcrumbs: [breadcrumb]); final event = await fixture.options.eventProcessors.first.apply(e); - expect(event?.breadcrumbs?[0].message, 'native-crumb'); + expect(event?.breadcrumbs?[0].message, 'native-crumb', + reason: + 'with timestamps of crumb1: ${event?.breadcrumbs?[0].timestamp.millisecondsSinceEpoch} and crumb2: ${event?.breadcrumbs?[1].timestamp.millisecondsSinceEpoch}'); expect(event?.breadcrumbs?[1].message, 'flutter-crumb'); }); } From 2a0a6e04f03cc0141750ab60aee1dbce7fa493ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Denis=20Andra=C5=A1ec?= Date: Mon, 25 Apr 2022 16:14:57 +0200 Subject: [PATCH 15/15] Fix timezone issue in unit test --- flutter/test/load_contexts_integrations_test.dart | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/flutter/test/load_contexts_integrations_test.dart b/flutter/test/load_contexts_integrations_test.dart index 9f127ba82f..d86490420d 100644 --- a/flutter/test/load_contexts_integrations_test.dart +++ b/flutter/test/load_contexts_integrations_test.dart @@ -407,14 +407,13 @@ void main() { final breadcrumb = Breadcrumb( message: 'flutter-crumb', - timestamp: DateTime.fromMillisecondsSinceEpoch(100), + timestamp: DateTime.fromMillisecondsSinceEpoch(1), ); final e = getEvent(breadcrumbs: [breadcrumb]); final event = await fixture.options.eventProcessors.first.apply(e); - expect(event?.breadcrumbs?[0].message, 'native-crumb', - reason: - 'with timestamps of crumb1: ${event?.breadcrumbs?[0].timestamp.millisecondsSinceEpoch} and crumb2: ${event?.breadcrumbs?[1].timestamp.millisecondsSinceEpoch}'); + expect(event?.breadcrumbs?.length, 2); + expect(event?.breadcrumbs?[0].message, 'native-crumb'); expect(event?.breadcrumbs?[1].message, 'flutter-crumb'); }); } @@ -455,7 +454,7 @@ class Fixture { 'level': 'error', 'breadcrumbs': [ { - 'timestamp': '1970-01-01T01:00:00.000', + 'timestamp': '1970-01-01T00:00:00.000Z', 'message': 'native-crumb', } ]