Skip to content

Commit b16ca72

Browse files
committed
Merge branch 'main' into ci/dart-only-metrics
2 parents 7f8b13f + 45d0706 commit b16ca72

34 files changed

+460
-182
lines changed

.github/CODEOWNERS

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
* @krystofwoldrich @stefanosiano @buenaflor @martinhaintz
1+
* @krystofwoldrich @stefanosiano @buenaflor

.github/workflows/flutter.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,13 +84,13 @@ jobs:
8484
if: matrix.target == 'web'
8585
run: |
8686
flutter test --platform chrome --test-randomize-ordering-seed=random --exclude-tags canvasKit
87-
flutter test --platform chrome --test-randomize-ordering-seed=random --tags canvasKit --web-renderer canvaskit
87+
flutter test --platform chrome --test-randomize-ordering-seed=random --tags canvasKit
8888
8989
- name: Test web (WASM)
9090
if: matrix.target == 'web'
9191
run: |
9292
flutter test --platform chrome --wasm --test-randomize-ordering-seed=random --exclude-tags canvasKit
93-
flutter test --platform chrome --wasm --test-randomize-ordering-seed=random --tags canvasKit --web-renderer canvaskit
93+
flutter test --platform chrome --wasm --test-randomize-ordering-seed=random --tags canvasKit
9494
9595
- name: Test VM with coverage
9696
if: matrix.target == 'linux' || matrix.target == 'macos' || matrix.target == 'windows'

.github/workflows/flutter_test.yml

Lines changed: 30 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ on:
1313
- "flutter/**"
1414

1515
env:
16-
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
16+
SENTRY_AUTH_TOKEN_E2E: ${{ secrets.SENTRY_AUTH_TOKEN_E2E }}
1717

1818
jobs:
1919
cancel-previous-workflow:
@@ -25,7 +25,7 @@ jobs:
2525
access_token: ${{ github.token }}
2626

2727
test-android:
28-
runs-on: macos-13
28+
runs-on: ubuntu-latest
2929
timeout-minutes: 30
3030
defaults:
3131
run:
@@ -38,6 +38,12 @@ jobs:
3838
- name: checkout
3939
uses: actions/checkout@v4
4040

41+
- name: Enable KVM group perms
42+
run: |
43+
echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
44+
sudo udevadm control --reload-rules
45+
sudo udevadm trigger --name-match=kvm
46+
4147
- uses: actions/setup-java@v4
4248
with:
4349
distribution: "adopt"
@@ -56,28 +62,7 @@ jobs:
5662
- name: Gradle cache
5763
uses: gradle/gradle-build-action@ac2d340dc04d9e1113182899e983b5400c17cda1 # [email protected]
5864

59-
- name: AVD cache
60-
uses: actions/cache@v4
61-
id: avd-cache
62-
with:
63-
path: |
64-
~/.android/avd/*
65-
~/.android/adb*
66-
key: avd-31
67-
68-
- name: create AVD and generate snapshot for caching
69-
if: steps.avd-cache.outputs.cache-hit != 'true'
70-
uses: reactivecircus/android-emulator-runner@62dbb605bba737720e10b196cb4220d374026a6d #[email protected]
71-
with:
72-
working-directory: ./flutter/example
73-
api-level: 31
74-
profile: Nexus 6
75-
arch: x86_64
76-
force-avd-creation: false
77-
avd-name: macOS-avd-x86_64-31
78-
emulator-options: -no-snapshot-save -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none
79-
disable-animations: true
80-
script: echo 'Generated AVD snapshot for caching.'
65+
# TODO: fix emulator caching, in ubuntu-latest emulator won't boot: https://github.com/ReactiveCircus/android-emulator-runner/issues/278
8166

8267
- name: build apk
8368
working-directory: ./flutter/example/android
@@ -91,8 +76,8 @@ jobs:
9176
profile: Nexus 6
9277
arch: x86_64
9378
force-avd-creation: false
94-
avd-name: macOS-avd-x86_64-31
95-
emulator-options: -no-snapshot-save -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none
79+
avd-name: avd-x86_64-31
80+
emulator-options: -no-snapshot-save -no-window -accel on -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none
9681
disable-animations: true
9782
script: ./gradlew testDebugUnitTest
9883

@@ -104,10 +89,23 @@ jobs:
10489
profile: Nexus 6
10590
arch: x86_64
10691
force-avd-creation: false
107-
avd-name: macOS-avd-x86_64-31
108-
emulator-options: -no-snapshot-save -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none
92+
avd-name: avd-x86_64-31
93+
emulator-options: -no-snapshot-save -no-window -accel on -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none
10994
disable-animations: true
110-
script: flutter test integration_test/all.dart --verbose
95+
script: flutter test integration_test/all.dart --dart-define SENTRY_AUTH_TOKEN_E2E=$SENTRY_AUTH_TOKEN_E2E --verbose
96+
97+
- name: launch android emulator & run android integration test in profile mode
98+
uses: reactivecircus/android-emulator-runner@62dbb605bba737720e10b196cb4220d374026a6d #[email protected]
99+
with:
100+
working-directory: ./flutter/example
101+
api-level: 31
102+
profile: Nexus 6
103+
arch: x86_64
104+
force-avd-creation: false
105+
avd-name: avd-x86_64-31
106+
emulator-options: -no-snapshot-save -no-window -accel on -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none
107+
disable-animations: true
108+
script: flutter drive --driver=integration_test/test_driver/driver.dart --target=integration_test/sentry_widgets_flutter_binding_test.dart --profile -d emulator-5554
111109

112110
cocoa:
113111
name: "${{ matrix.target }} | ${{ matrix.sdk }}"
@@ -158,7 +156,9 @@ jobs:
158156
- name: run integration test
159157
# Disable flutter integration tests for iOS for now (https://github.com/getsentry/sentry-dart/issues/1605#issuecomment-1695809346)
160158
if: ${{ matrix.target != 'ios' }}
161-
run: flutter test -d "${{ steps.device.outputs.name }}" integration_test/all.dart --verbose
159+
run: |
160+
flutter test -d "${{ steps.device.outputs.name }}" integration_test/all.dart --dart-define SENTRY_AUTH_TOKEN_E2E=$SENTRY_AUTH_TOKEN_E2E --verbose
161+
flutter drive --driver=integration_test/test_driver/driver.dart --target=integration_test/sentry_widgets_flutter_binding_test.dart --profile -d "${{ steps.device.outputs.name }}"
162162
163163
- name: run native test
164164
# We only have the native unit test package in the iOS xcodeproj at the moment.

.github/workflows/testflight.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ jobs:
1616
- uses: actions/checkout@v4
1717
- uses: subosito/flutter-action@f2c4f6686ca8e8d6e6d0f28410eeef506ed66aff # [email protected]
1818
- run: xcodes select 15.0.1
19-
- uses: ruby/setup-ruby@a2bbe5b1b236842c1cb7dd11e8e3b51e0a616acc # pin@v1.202.0
19+
- uses: ruby/setup-ruby@401c19e14f474b54450cd3905bb8b86e2c8509cf # pin@v1.204.0
2020
with:
2121
ruby-version: '2.7.5'
2222
bundler-cache: true

CHANGELOG.md

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,38 @@
11
# Changelog
22

3+
## Unreleased
4+
5+
### Deprecate
6+
7+
- Manual TTID ([#2477](https://github.com/getsentry/sentry-dart/pull/2477))
8+
9+
### Improvements
10+
11+
- Check `SentryTracer` type in TTFD tracker ([#2508](https://github.com/getsentry/sentry-dart/pull/2508))
12+
13+
### Enhancements
14+
15+
- Warning (in a debug build) if a potentially sensitive widget is not masked or unmasked explicitly ([#2375](https://github.com/getsentry/sentry-dart/pull/2375))
16+
17+
### Dependencies
18+
19+
- Bump Native SDK from v0.7.15 to v0.7.16 ([#2465](https://github.com/getsentry/sentry-dart/pull/2465))
20+
- [changelog](https://github.com/getsentry/sentry-native/blob/master/CHANGELOG.md#0716)
21+
- [diff](https://github.com/getsentry/sentry-native/compare/0.7.15...0.7.16)
22+
- Bump Android SDK from v7.18.1 to v7.19.0 ([#2488](https://github.com/getsentry/sentry-dart/pull/2488))
23+
- [changelog](https://github.com/getsentry/sentry-java/blob/main/CHANGELOG.md#7190)
24+
- [diff](https://github.com/getsentry/sentry-java/compare/7.18.1...7.19.0)
25+
26+
## 8.11.1
27+
28+
### Improvements
29+
30+
- Check for type before casting in TTID ([#2497](https://github.com/getsentry/sentry-dart/pull/2497))
31+
32+
### Fixes
33+
34+
- SentryWidgetsFlutterBinding initializing even if a binding already exists ([#2494](https://github.com/getsentry/sentry-dart/pull/2494))
35+
336
## 8.12.0-beta.1
437

538
### Features

dart/lib/src/sentry_options.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -542,7 +542,7 @@ class SentryOptions {
542542
/// On io platforms without native SDKs (dart, linux, windows), this will use
543543
/// an 'IOClient' with inner 'HTTPClient' for http communication.
544544
/// A http proxy will be set in returned for 'HttpClient.findProxy' in the
545-
/// form 'PROXY <your_host>:<your_port>'.
545+
/// form 'PROXY your_host:your_port'.
546546
/// When setting 'user' and 'pass', the 'HttpClient.addProxyCredentials'
547547
/// method will be called with empty 'realm'.
548548
///

flutter/android/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ android {
6060
}
6161

6262
dependencies {
63-
api 'io.sentry:sentry-android:7.18.1'
63+
api 'io.sentry:sentry-android:7.19.0'
6464
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
6565

6666
// Required -- JUnit 4 framework

flutter/example/integration_test/integration_test.dart

Lines changed: 76 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,19 @@ import 'dart:convert';
77
import 'package:flutter/widgets.dart';
88
import 'package:flutter_test/flutter_test.dart';
99
import 'package:http/http.dart';
10+
import 'package:integration_test/integration_test.dart';
1011
import 'package:sentry_flutter/sentry_flutter.dart';
1112
import 'package:sentry_flutter_example/main.dart';
1213

14+
import 'utils.dart';
15+
1316
void main() {
14-
// const org = 'sentry-sdks';
15-
// const slug = 'sentry-flutter';
16-
// const authToken = String.fromEnvironment('SENTRY_AUTH_TOKEN');
17+
const org = 'sentry-sdks';
18+
const slug = 'sentry-flutter';
19+
const authToken = String.fromEnvironment('SENTRY_AUTH_TOKEN_E2E');
1720
const fakeDsn = 'https://[email protected]/1234567';
1821

19-
TestWidgetsFlutterBinding.ensureInitialized();
22+
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
2023

2124
tearDown(() async {
2225
await Sentry.close();
@@ -98,7 +101,7 @@ void main() {
98101

99102
// ignore: deprecated_member_use_from_same_package
100103
// ignore: deprecated_member_use
101-
final associatedEventId = await Sentry.captureMessage("Associated");
104+
final associatedEventId = await Sentry.captureMessage('Associated');
102105
final feedback = SentryFeedback(
103106
message: 'message',
104107
contactEmail: '[email protected]',
@@ -162,66 +165,76 @@ void main() {
162165
await transaction.finish();
163166
});
164167

165-
// group('e2e', () {
166-
// var output = find.byKey(const Key('output'));
167-
// late Fixture fixture;
168-
//
169-
// setUp(() {
170-
// fixture = Fixture();
171-
// });
172-
//
173-
// testWidgets('captureException', (tester) async {
174-
// await setupSentryAndApp(tester,
175-
// dsn: exampleDsn, beforeSendCallback: fixture.beforeSend);
176-
//
177-
// await tester.tap(find.text('captureException'));
178-
// await tester.pumpAndSettle();
179-
//
180-
// final text = output.evaluate().single.widget as Text;
181-
// final id = text.data!;
182-
//
183-
// final uri = Uri.parse(
184-
// 'https://sentry.io/api/0/projects/$org/$slug/events/$id/',
185-
// );
186-
// expect(authToken, isNotEmpty);
187-
//
188-
// final event = await fixture.poll(uri, authToken);
189-
// expect(event, isNotNull);
190-
//
191-
// final sentEvent = fixture.sentEvent;
192-
// expect(sentEvent, isNotNull);
193-
//
194-
// final tags = event!["tags"] as List<dynamic>;
195-
//
196-
// expect(sentEvent!.eventId.toString(), event["id"]);
197-
// expect("_Exception: Exception: captureException", event["title"]);
198-
// expect(sentEvent.release, event["release"]["version"]);
199-
// expect(
200-
// 2,
201-
// (tags.firstWhere((e) => e["value"] == sentEvent.environment) as Map)
202-
// .length);
203-
// expect(sentEvent.fingerprint, event["fingerprint"] ?? []);
204-
// expect(
205-
// 2,
206-
// (tags.firstWhere((e) => e["value"] == SentryLevel.error.name) as Map)
207-
// .length);
208-
// expect(sentEvent.logger, event["logger"]);
209-
//
210-
// final dist = tags.firstWhere((element) => element['key'] == 'dist');
211-
// expect('1', dist['value']);
212-
//
213-
// final environment =
214-
// tags.firstWhere((element) => element['key'] == 'environment');
215-
// expect('integration', environment['value']);
216-
// });
217-
// });
168+
group('e2e', () {
169+
var output = find.byKey(const Key('output'));
170+
late Fixture fixture;
171+
172+
setUp(() {
173+
fixture = Fixture();
174+
});
175+
176+
testWidgets('captureException', (tester) async {
177+
late Uri uri;
178+
179+
await restoreFlutterOnErrorAfter(() async {
180+
await setupSentryAndApp(tester,
181+
dsn: exampleDsn, beforeSendCallback: fixture.beforeSend);
182+
183+
await tester.tap(find.text('captureException'));
184+
await tester.pumpAndSettle();
185+
186+
final text = output.evaluate().single.widget as Text;
187+
final id = text.data!;
188+
189+
uri = Uri.parse(
190+
'https://sentry.io/api/0/projects/$org/$slug/events/$id/',
191+
);
192+
});
193+
194+
expect(authToken, isNotEmpty);
195+
196+
final event = await fixture.poll(uri, authToken);
197+
expect(event, isNotNull);
198+
199+
final sentEvents = fixture.sentEvents
200+
.where((el) => el!.eventId.toString() == event!['id']);
201+
expect(
202+
sentEvents.length, 1); // one button click should only send one error
203+
final sentEvent = sentEvents.first;
204+
205+
final tags = event!['tags'] as List<dynamic>;
206+
207+
print('event id: ${event['id']}');
208+
print('event title: ${event['title']}');
209+
expect(sentEvent!.eventId.toString(), event['id']);
210+
expect('_Exception: Exception: captureException', event['title']);
211+
expect(sentEvent.release, event['release']['version']);
212+
expect(
213+
2,
214+
(tags.firstWhere((e) => e['value'] == sentEvent.environment) as Map)
215+
.length);
216+
expect(sentEvent.fingerprint, event['fingerprint'] ?? []);
217+
expect(
218+
2,
219+
(tags.firstWhere((e) => e['value'] == SentryLevel.error.name) as Map)
220+
.length);
221+
expect(sentEvent.logger, event['logger']);
222+
223+
final dist = tags.firstWhere((element) => element['key'] == 'dist');
224+
expect('1', dist['value']);
225+
226+
final environment =
227+
tags.firstWhere((element) => element['key'] == 'environment');
228+
expect('integration', environment['value']);
229+
});
230+
});
218231
}
219232

220233
class Fixture {
221-
SentryEvent? sentEvent;
234+
List<SentryEvent?> sentEvents = [];
222235

223236
FutureOr<SentryEvent?> beforeSend(SentryEvent event, Hint hint) async {
224-
sentEvent = event;
237+
sentEvents.add(event);
225238
return event;
226239
}
227240

@@ -237,16 +250,16 @@ class Fixture {
237250

238251
while (retries < maxRetries) {
239252
try {
240-
print("Trying to fetch $url [try $retries/$maxRetries]");
253+
print('Trying to fetch $url [try $retries/$maxRetries]');
241254
final response = await client.get(
242255
url,
243256
headers: <String, String>{'Authorization': 'Bearer $authToken'},
244257
);
245-
print("Response status code: ${response.statusCode}");
258+
print('Response status code: ${response.statusCode}');
246259
if (response.statusCode == 200) {
247260
return jsonDecode(utf8.decode(response.bodyBytes));
248261
} else if (response.statusCode == 401) {
249-
print("Cannot fetch $url - invalid auth token.");
262+
print('Cannot fetch $url - invalid auth token.');
250263
break;
251264
}
252265
} catch (e) {

0 commit comments

Comments
 (0)