-
Notifications
You must be signed in to change notification settings - Fork 54
[flutter_webrtc] Add regression integration tests and fix close() double-call error #1067
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
Open
seungsoo47
wants to merge
3
commits into
flutter-tizen:master
Choose a base branch
from
seungsoo47:flutter_webrtc-add-integration-tests
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
224 changes: 224 additions & 0 deletions
224
...s/flutter_webrtc/example/flutter_webrtc_example/integration_test/flutter_webrtc_test.dart
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,224 @@ | ||
| // Copyright 2024 Samsung Electronics Co., Ltd. All rights reserved. | ||
| // Use of this source code is governed by a BSD-style license that can be | ||
| // found in the LICENSE file. | ||
|
|
||
| import 'dart:async'; | ||
| import 'dart:typed_data'; | ||
|
|
||
| import 'package:flutter_test/flutter_test.dart'; | ||
| import 'package:flutter_webrtc/flutter_webrtc.dart'; | ||
| import 'package:integration_test/integration_test.dart'; | ||
|
|
||
| const Map<String, dynamic> _kConfig = { | ||
| 'iceServers': <Map<String, dynamic>>[], | ||
| }; | ||
|
|
||
| Future<void> _negotiate( | ||
| RTCPeerConnection pc1, | ||
| RTCPeerConnection pc2, | ||
| ) async { | ||
| pc1.onIceCandidate = (c) => pc2.addCandidate(c); | ||
| pc2.onIceCandidate = (c) => pc1.addCandidate(c); | ||
|
|
||
| final offer = await pc1.createOffer(); | ||
| await pc1.setLocalDescription(offer); | ||
| await pc2.setRemoteDescription(offer); | ||
| final answer = await pc2.createAnswer(); | ||
| await pc2.setLocalDescription(answer); | ||
| await pc1.setRemoteDescription(answer); | ||
| } | ||
|
|
||
| void main() { | ||
| IntegrationTestWidgetsFlutterBinding.ensureInitialized(); | ||
|
|
||
| group('RTCPeerConnection', () { | ||
| testWidgets('creates with empty ice servers', (WidgetTester tester) async { | ||
| final pc = await createPeerConnection(_kConfig); | ||
| expect(pc, isNotNull); | ||
| await pc.close(); | ||
| }, timeout: const Timeout(Duration(seconds: 10))); | ||
|
|
||
| testWidgets('createOffer returns valid SDP', (WidgetTester tester) async { | ||
| final pc = await createPeerConnection(_kConfig); | ||
| final offer = await pc.createOffer(); | ||
| expect(offer.type, equals('offer')); | ||
| expect(offer.sdp, isNotEmpty); | ||
| await pc.close(); | ||
| }, timeout: const Timeout(Duration(seconds: 10))); | ||
|
|
||
| testWidgets('setLocalDescription succeeds', (WidgetTester tester) async { | ||
| final pc = await createPeerConnection(_kConfig); | ||
| final offer = await pc.createOffer(); | ||
| await expectLater(pc.setLocalDescription(offer), completes); | ||
| await pc.close(); | ||
| }, timeout: const Timeout(Duration(seconds: 10))); | ||
|
|
||
| testWidgets('createAnswer returns valid SDP', (WidgetTester tester) async { | ||
| final pc1 = await createPeerConnection(_kConfig); | ||
| final pc2 = await createPeerConnection(_kConfig); | ||
| final offer = await pc1.createOffer(); | ||
| await pc2.setRemoteDescription(offer); | ||
| final answer = await pc2.createAnswer(); | ||
| expect(answer.type, equals('answer')); | ||
| expect(answer.sdp, isNotEmpty); | ||
| await pc1.close(); | ||
| await pc2.close(); | ||
| }, timeout: const Timeout(Duration(seconds: 10))); | ||
|
|
||
| testWidgets('close is idempotent', (WidgetTester tester) async { | ||
| final pc = await createPeerConnection(_kConfig); | ||
| await pc.close(); | ||
| await expectLater(pc.close(), completes); | ||
| }, timeout: const Timeout(Duration(seconds: 10))); | ||
| }); | ||
|
|
||
| group('RTCDataChannel', () { | ||
| testWidgets('createDataChannel returns channel with correct label', | ||
| (WidgetTester tester) async { | ||
| final pc = await createPeerConnection(_kConfig); | ||
| final dc = await pc.createDataChannel('test-label', RTCDataChannelInit()); | ||
| expect(dc.label, equals('test-label')); | ||
| await dc.close(); | ||
| await pc.close(); | ||
| }, timeout: const Timeout(Duration(seconds: 10))); | ||
|
|
||
| testWidgets('loopback text message exchange', (WidgetTester tester) async { | ||
| final pc1 = await createPeerConnection(_kConfig); | ||
| final pc2 = await createPeerConnection(_kConfig); | ||
|
|
||
| final dc2Completer = Completer<RTCDataChannel>(); | ||
| pc2.onDataChannel = (channel) { | ||
| if (!dc2Completer.isCompleted) dc2Completer.complete(channel); | ||
| }; | ||
|
|
||
| final dc1 = await pc1.createDataChannel( | ||
| 'loopback', | ||
| RTCDataChannelInit()..ordered = true, | ||
| ); | ||
|
|
||
| await _negotiate(pc1, pc2); | ||
|
|
||
| final dc2 = | ||
| await dc2Completer.future.timeout(const Duration(seconds: 10)); | ||
|
|
||
| final dc1Open = Completer<void>(); | ||
| final dc2Open = Completer<void>(); | ||
| if (dc1.state == RTCDataChannelState.RTCDataChannelOpen) { | ||
| dc1Open.complete(); | ||
| } else { | ||
| dc1.onDataChannelState = (s) { | ||
| if (s == RTCDataChannelState.RTCDataChannelOpen && | ||
| !dc1Open.isCompleted) { | ||
| dc1Open.complete(); | ||
| } | ||
| }; | ||
| } | ||
| if (dc2.state == RTCDataChannelState.RTCDataChannelOpen) { | ||
| dc2Open.complete(); | ||
| } else { | ||
| dc2.onDataChannelState = (s) { | ||
| if (s == RTCDataChannelState.RTCDataChannelOpen && | ||
| !dc2Open.isCompleted) { | ||
| dc2Open.complete(); | ||
| } | ||
| }; | ||
| } | ||
|
|
||
| await Future.wait([ | ||
| dc1Open.future.timeout(const Duration(seconds: 10)), | ||
| dc2Open.future.timeout(const Duration(seconds: 10)), | ||
| ]); | ||
|
|
||
| final dc2Received = Completer<String>(); | ||
| dc2.onMessage = (msg) { | ||
| if (!dc2Received.isCompleted) dc2Received.complete(msg.text); | ||
| }; | ||
| await dc1.send(RTCDataChannelMessage('hello from dc1')); | ||
| expect( | ||
| await dc2Received.future.timeout(const Duration(seconds: 5)), | ||
| equals('hello from dc1'), | ||
| ); | ||
|
|
||
| final dc1Received = Completer<String>(); | ||
| dc1.onMessage = (msg) { | ||
| if (!dc1Received.isCompleted) dc1Received.complete(msg.text); | ||
| }; | ||
| await dc2.send(RTCDataChannelMessage('hello from dc2')); | ||
| expect( | ||
| await dc1Received.future.timeout(const Duration(seconds: 5)), | ||
| equals('hello from dc2'), | ||
| ); | ||
|
|
||
| await dc1.close(); | ||
| await dc2.close(); | ||
| await pc1.close(); | ||
| await pc2.close(); | ||
| }, timeout: const Timeout(Duration(seconds: 60))); | ||
|
|
||
| testWidgets('loopback binary message exchange', | ||
| (WidgetTester tester) async { | ||
| final pc1 = await createPeerConnection(_kConfig); | ||
| final pc2 = await createPeerConnection(_kConfig); | ||
|
|
||
| final dc2Completer = Completer<RTCDataChannel>(); | ||
| pc2.onDataChannel = (channel) { | ||
| if (!dc2Completer.isCompleted) dc2Completer.complete(channel); | ||
| }; | ||
|
|
||
| final dc1 = await pc1.createDataChannel( | ||
| 'binary', | ||
| RTCDataChannelInit()..ordered = true, | ||
| ); | ||
|
|
||
| await _negotiate(pc1, pc2); | ||
|
|
||
| final dc2 = | ||
| await dc2Completer.future.timeout(const Duration(seconds: 10)); | ||
|
|
||
| final dc1Open = Completer<void>(); | ||
| final dc2Open = Completer<void>(); | ||
| if (dc1.state == RTCDataChannelState.RTCDataChannelOpen) { | ||
| dc1Open.complete(); | ||
| } else { | ||
| dc1.onDataChannelState = (s) { | ||
| if (s == RTCDataChannelState.RTCDataChannelOpen && | ||
| !dc1Open.isCompleted) { | ||
| dc1Open.complete(); | ||
| } | ||
| }; | ||
| } | ||
| if (dc2.state == RTCDataChannelState.RTCDataChannelOpen) { | ||
| dc2Open.complete(); | ||
| } else { | ||
| dc2.onDataChannelState = (s) { | ||
| if (s == RTCDataChannelState.RTCDataChannelOpen && | ||
| !dc2Open.isCompleted) { | ||
| dc2Open.complete(); | ||
| } | ||
| }; | ||
| } | ||
|
|
||
| await Future.wait([ | ||
| dc1Open.future.timeout(const Duration(seconds: 10)), | ||
| dc2Open.future.timeout(const Duration(seconds: 10)), | ||
| ]); | ||
|
seungsoo47 marked this conversation as resolved.
|
||
|
|
||
| final payload = Uint8List.fromList([1, 2, 3, 4, 5]); | ||
|
|
||
| final dc2Received = Completer<Uint8List>(); | ||
| dc2.onMessage = (msg) { | ||
| if (!dc2Received.isCompleted) dc2Received.complete(msg.binary); | ||
| }; | ||
| await dc1.send(RTCDataChannelMessage.fromBinary(payload)); | ||
| expect( | ||
| await dc2Received.future.timeout(const Duration(seconds: 5)), | ||
| equals(payload), | ||
| ); | ||
|
|
||
| await dc1.close(); | ||
| await dc2.close(); | ||
| await pc1.close(); | ||
| await pc2.close(); | ||
| }, timeout: const Timeout(Duration(seconds: 60))); | ||
| }); | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
3 changes: 3 additions & 0 deletions
3
packages/flutter_webrtc/example/flutter_webrtc_example/test_driver/integration_test.dart
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| import 'package:integration_test/integration_test_driver.dart'; | ||
|
|
||
| Future<void> main() => integrationDriver(); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.