Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
## 4.0.0-alpha.3 (Next)

- Development.
- add loadContextsIntegration tests

## 4.0.0-alpha.2

Expand Down
20 changes: 16 additions & 4 deletions flutter/lib/src/sentry_flutter.dart
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,15 @@ mixin SentryFlutter {
OptionsConfiguration optionsConfiguration,
Function callback, {
PackageLoader packageLoader = _loadPackageInfo,
iOSPlatformChecker iOSPlatformChecker = _iOSPlatformChecker,
}) async {
await Sentry.init((options) async {
await _initDefaultValues(options, callback, packageLoader);
await _initDefaultValues(
options,
callback,
packageLoader,
iOSPlatformChecker,
);

await optionsConfiguration(options);
});
Expand All @@ -30,6 +36,7 @@ mixin SentryFlutter {
SentryOptions options,
Function callback,
PackageLoader packageLoader,
iOSPlatformChecker iOSPlatformChecker,
) async {
// it is necessary to initialize Flutter method channels so that
// our plugin can call into the native code.
Expand Down Expand Up @@ -58,7 +65,7 @@ mixin SentryFlutter {

// first step is to install the native integration and set default values,
// so we are able to capture future errors.
_addDefaultIntegrations(options, callback);
_addDefaultIntegrations(options, callback, iOSPlatformChecker);

await _setReleaseAndDist(options, packageLoader);

Expand Down Expand Up @@ -103,6 +110,7 @@ mixin SentryFlutter {
static void _addDefaultIntegrations(
SentryOptions options,
Function callback,
iOSPlatformChecker isIOS,
) {
// the ordering here matters, as we'd like to first start the native integration
// that allow us to send events to the network and then the Flutter integrations.
Expand All @@ -121,8 +129,7 @@ mixin SentryFlutter {
options.addIntegration(isolateErrorIntegration);
}

// TODO: make it testable/mockable
if (Platform.isIOS) {
if (isIOS()) {
options.addIntegration(loadContextsIntegration(options, _channel));
}
// finally the runZonedGuarded, catch any errors in Dart code running
Expand All @@ -145,7 +152,12 @@ mixin SentryFlutter {

typedef PackageLoader = Future<PackageInfo> Function();

typedef iOSPlatformChecker = bool Function();

/// Package info loader.
Future<PackageInfo> _loadPackageInfo() async {
return await PackageInfo.fromPlatform();
}

/// verify if the platform is iOS
bool _iOSPlatformChecker() => Platform.isIOS;
15 changes: 1 addition & 14 deletions flutter/test/default_integrations_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ void main() {
fixture.options.sdk.integrations.contains('nativeSdkIntegration'));
});

test('loadContextsIntegration adds integration on ios', () async {
test('loadContextsIntegration adds integration', () async {
_channel.setMockMethodCallHandler((MethodCall methodCall) async {});

final integration = loadContextsIntegration(fixture.options, _channel);
Expand All @@ -186,19 +186,6 @@ void main() {
expect(true,
fixture.options.sdk.integrations.contains('loadContextsIntegration'));
});

test('loadContextsIntegration do not throw', () async {
_channel.setMockMethodCallHandler((MethodCall methodCall) async {
throw null;
});

final integration = loadContextsIntegration(fixture.options, _channel);

await integration(fixture.hub, fixture.options);

expect(true,
fixture.options.sdk.integrations.contains('loadContextsIntegration'));
});
}

class Fixture {
Expand Down
146 changes: 146 additions & 0 deletions flutter/test/load_contexts_integrations_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/mockito.dart';
import 'package:sentry/sentry.dart';
import 'package:sentry_flutter/sentry_flutter.dart';

import 'mocks.dart';

class MockTransport extends Mock implements Transport {}

void main() {
const MethodChannel _channel = MethodChannel('sentry_flutter');

TestWidgetsFlutterBinding.ensureInitialized();

bool called = false;

setUp(() {
_channel.setMockMethodCallHandler((MethodCall methodCall) async {
called = true;
return {
'integrations': ['NativeIntegration'],
'package': {'sdk_name': 'native-package', 'version': '1.0'},
'contexts': {
'device': {'name': 'Device1'},
'app': {'app_name': 'test-app'},
'os': {'name': 'os1'},
'gpu': {'name': 'gpu1'},
'browser': {'name': 'browser1'},
'runtime': {'name': 'RT1'},
'theme': 'material',
}
};
});
});

tearDown(() {
_channel.setMockMethodCallHandler(null);
});

test('should apply the loadContextsIntegration eventProcessor', () async {
final options = SentryOptions()..dsn = fakeDsn;
final hub = Hub(options);

loadContextsIntegration(options, _channel)(hub, options);

expect(options.eventProcessors.length, 1);

final e = SentryEvent();
final event = await options.eventProcessors.first(e, null);

expect(called, true);
expect(event.contexts.device.name, 'Device1');
expect(event.contexts.app.name, 'test-app');
expect(event.contexts.operatingSystem.name, 'os1');
expect(event.contexts.gpu.name, 'gpu1');
expect(event.contexts.browser.name, 'browser1');
expect(
event.contexts.runtimes.any((element) => element.name == 'RT1'), true);
expect(event.contexts['theme'], 'material');
expect(
event.sdk.packages.any((element) => element.name == 'native-package'),
true,
);
expect(event.sdk.integrations.contains('NativeIntegration'), true);
});

test(
'should not override event contexts with the loadContextsIntegration infos',
() async {
final options = SentryOptions()..dsn = fakeDsn;
final hub = Hub(options);

loadContextsIntegration(options, _channel)(hub, options);

expect(options.eventProcessors.length, 1);

final eventContexts = Contexts(
device: const Device(name: 'eDevice'),
app: const App(name: 'eApp'),
operatingSystem: const OperatingSystem(name: 'eOS'),
gpu: const Gpu(name: 'eGpu'),
browser: const Browser(name: 'eBrowser'),
runtimes: [const SentryRuntime(name: 'eRT')])
..['theme'] = 'cuppertino';
final e = SentryEvent(contexts: eventContexts);
final event = await options.eventProcessors.first(e, null);

expect(called, true);
expect(event.contexts.device.name, 'eDevice');
expect(event.contexts.app.name, 'eApp');
expect(event.contexts.operatingSystem.name, 'eOS');
expect(event.contexts.gpu.name, 'eGpu');
expect(event.contexts.browser.name, 'eBrowser');
expect(
event.contexts.runtimes.any((element) => element.name == 'RT1'), true);
expect(
event.contexts.runtimes.any((element) => element.name == 'eRT'), true);
expect(event.contexts['theme'], 'cuppertino');
});

test(
'should merge event and loadContextsIntegration sdk packages and integration',
() async {
final options = SentryOptions()..dsn = fakeDsn;
final hub = Hub(options);

loadContextsIntegration(options, _channel)(hub, options);

final eventSdk = SdkVersion(
name: 'sdk1',
version: '1.0',
integrations: ['EventIntegration'],
packages: [const SentryPackage('event-package', '2.0')],
);
final e = SentryEvent(sdk: eventSdk);
final event = await options.eventProcessors.first(e, null);

expect(
event.sdk.packages.any((element) => element.name == 'native-package'),
true,
);
expect(
event.sdk.packages.any((element) => element.name == 'event-package'),
true,
);
expect(event.sdk.integrations.contains('NativeIntegration'), true);
expect(event.sdk.integrations.contains('EventIntegration'), true);
},
);

test('should not throw on loadContextsIntegration exception', () async {
_channel.setMockMethodCallHandler((MethodCall methodCall) async {
throw null;
});
final options = SentryOptions()..dsn = fakeDsn;
final hub = Hub(options);

loadContextsIntegration(options, _channel)(hub, options);

final e = SentryEvent();
final event = await options.eventProcessors.first(e, null);

expect(event, isNotNull);
});
}
13 changes: 12 additions & 1 deletion flutter/test/sentry_flutter_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,20 @@ void main() {

test('Flutter init for mobile will run default configurations', () async {
await SentryFlutter.init(
configurationTester,
getConfigurationTester(false),
callback,
packageLoader: loadTestPackage,
iOSPlatformChecker: () => false,
);
});

test('Flutter init for mobile will run default configurations on ios',
() async {
await SentryFlutter.init(
getConfigurationTester(true),
callback,
packageLoader: loadTestPackage,
iOSPlatformChecker: () => true,
);
});
}
Expand Down
47 changes: 23 additions & 24 deletions flutter/test/sentry_flutter_util.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,36 +6,35 @@ import 'package:sentry/sentry.dart';
import 'package:sentry_flutter/sentry_flutter.dart';
import 'package:sentry_flutter/src/file_system_transport.dart';
import 'package:sentry_flutter/src/version.dart';

import 'mocks.dart';

FutureOr<void> configurationTester(
SentryOptions options, {
bool isWeb = false,
}) async {
options.dsn = fakeDsn;
FutureOr<void> Function(SentryOptions) getConfigurationTester(bool onIOS) =>
(SentryOptions options) async {
options.dsn = fakeDsn;

expect(kDebugMode, options.debug);
expect('debug', options.environment);
expect(kDebugMode, options.debug);
expect('debug', options.environment);

expect(true, options.transport is FileSystemTransport);
expect(true, options.transport is FileSystemTransport);

expect(
options.integrations
.where((element) => element == flutterErrorIntegration),
isNotEmpty);
expect(
options.integrations
.where((element) => element == flutterErrorIntegration),
isNotEmpty);

expect(
options.integrations
.where((element) => element == isolateErrorIntegration),
isNotEmpty);
expect(
options.integrations
.where((element) => element == isolateErrorIntegration),
isNotEmpty);

expect(4, options.integrations.length);
expect(onIOS ? 5 : 4, options.integrations.length);

expect(sdkName, options.sdk.name);
expect(sdkVersion, options.sdk.version);
expect('pub:sentry_flutter', options.sdk.packages.last.name);
expect(sdkVersion, options.sdk.packages.last.version);
expect(sdkName, options.sdk.name);
expect(sdkVersion, options.sdk.version);
expect('pub:sentry_flutter', options.sdk.packages.last.name);
expect(sdkVersion, options.sdk.packages.last.version);

expect('packageName@version+buildNumber', options.release);
expect('buildNumber', options.dist);
}
expect('packageName@version+buildNumber', options.release);
expect('buildNumber', options.dist);
};