From b6d5ce02c48de228ee22cec7a9ff8a9fcc0ff039 Mon Sep 17 00:00:00 2001 From: td Date: Tue, 19 Dec 2023 21:55:30 +0530 Subject: [PATCH] feat: add tests for calls --- lib/src/voip/call.dart | 17 +- lib/src/voip/voip.dart | 3 + test/calls_test.dart | 356 ++++++++++++++++++++++++++++++++--- test/client_test.dart | 42 ++--- test/fake_matrix_api.dart | 56 ++++-- test/room_archived_test.dart | 2 +- test/webrtc_stub.dart | 8 +- 7 files changed, 408 insertions(+), 76 deletions(-) diff --git a/lib/src/voip/call.dart b/lib/src/voip/call.dart index 9b42884c..5b88a87c 100644 --- a/lib/src/voip/call.dart +++ b/lib/src/voip/call.dart @@ -461,6 +461,7 @@ class CallSession { Logs().d( '[glare] new call $callId needs to be canceled because the older one ${prevCall.callId} has a smaller lex'); await hangup(); + voip.currentCID = prevCall.callId; return; } else { Logs().d( @@ -1690,8 +1691,6 @@ class CallSession { String? txid, CallCapabilities? capabilities, SDPStreamMetadata? metadata}) async { - txid ??= 'txid${DateTime.now().millisecondsSinceEpoch}'; - final content = { 'call_id': callId, 'party_id': party_id, @@ -1723,8 +1722,6 @@ class CallSession { Future sendSelectCallAnswer( Room room, String callId, String party_id, String selected_party_id, {String version = voipProtoVersion, String? txid}) async { - txid ??= 'txid${DateTime.now().millisecondsSinceEpoch}'; - final content = { 'call_id': callId, 'party_id': party_id, @@ -1748,8 +1745,6 @@ class CallSession { Future sendCallReject( Room room, String callId, String party_id, String? reason, {String version = voipProtoVersion, String? txid}) async { - txid ??= 'txid${DateTime.now().millisecondsSinceEpoch}'; - final content = { 'call_id': callId, 'party_id': party_id, @@ -1778,7 +1773,6 @@ class CallSession { String? txid, CallCapabilities? capabilities, SDPStreamMetadata? metadata}) async { - txid ??= 'txid${DateTime.now().millisecondsSinceEpoch}'; final content = { 'call_id': callId, 'party_id': party_id, @@ -1825,7 +1819,6 @@ class CallSession { String version = voipProtoVersion, String? txid, }) async { - txid ??= 'txid${DateTime.now().millisecondsSinceEpoch}'; final content = { 'call_id': callId, 'party_id': party_id, @@ -1854,7 +1847,6 @@ class CallSession { String? txid, CallCapabilities? capabilities, SDPStreamMetadata? metadata}) async { - txid ??= 'txid${DateTime.now().millisecondsSinceEpoch}'; final content = { 'call_id': callId, 'party_id': party_id, @@ -1879,8 +1871,6 @@ class CallSession { Future sendHangupCall( Room room, String callId, String party_id, String? hangupCause, {String version = voipProtoVersion, String? txid}) async { - txid ??= 'txid${DateTime.now().millisecondsSinceEpoch}'; - final content = { 'call_id': callId, 'party_id': party_id, @@ -1913,7 +1903,6 @@ class CallSession { Future sendSDPStreamMetadataChanged( Room room, String callId, String party_id, SDPStreamMetadata metadata, {String version = voipProtoVersion, String? txid}) async { - txid ??= 'txid${DateTime.now().millisecondsSinceEpoch}'; final content = { 'call_id': callId, 'party_id': party_id, @@ -1938,7 +1927,6 @@ class CallSession { Future sendCallReplaces( Room room, String callId, String party_id, CallReplaces callReplaces, {String version = voipProtoVersion, String? txid}) async { - txid ??= 'txid${DateTime.now().millisecondsSinceEpoch}'; final content = { 'call_id': callId, 'party_id': party_id, @@ -1963,7 +1951,6 @@ class CallSession { Future sendAssertedIdentity(Room room, String callId, String party_id, AssertedIdentity assertedIdentity, {String version = voipProtoVersion, String? txid}) async { - txid ??= 'txid${DateTime.now().millisecondsSinceEpoch}'; final content = { 'call_id': callId, 'party_id': party_id, @@ -1985,7 +1972,7 @@ class CallSession { Map content, { String? txid, }) async { - txid ??= client.generateUniqueTransactionId(); + txid ??= VoIP.customTxid ?? client.generateUniqueTransactionId(); final mustEncrypt = room.encrypted && client.encryptionEnabled; // opponentDeviceId is only set for a few events during group calls, diff --git a/lib/src/voip/voip.dart b/lib/src/voip/voip.dart index d873545b..c099815b 100644 --- a/lib/src/voip/voip.dart +++ b/lib/src/voip/voip.dart @@ -30,6 +30,9 @@ abstract class WebRTCDelegate { } class VoIP { + // used only for internal tests, all txids for call events will be overwritten to this + static String? customTxid; + TurnServerCredentials? _turnServerCredentials; Map calls = {}; Map groupCalls = {}; diff --git a/test/calls_test.dart b/test/calls_test.dart index 25fcf831..7aad93dd 100644 --- a/test/calls_test.dart +++ b/test/calls_test.dart @@ -1,4 +1,5 @@ import 'package:test/test.dart'; +import 'package:webrtc_interface/webrtc_interface.dart'; import 'package:matrix/matrix.dart'; import 'fake_client.dart'; @@ -7,24 +8,16 @@ import 'webrtc_stub.dart'; void main() { late Client matrix; late Room room; - - group('Call Tests', () { + late VoIP voip; + group('Call tests', () { Logs().level = Level.info; - - test('Login', () async { + setUp(() async { matrix = await getClient(); - }); + voip = VoIP(matrix, MockWebRTCDelegate()); + VoIP.customTxid = '1234'; + final id = '!calls:example.com'; - test('Create from json', () async { - final id = '!localpart:server.abc'; - final membership = Membership.join; - - room = Room( - client: matrix, - id: id, - membership: membership, - prev_batch: '', - ); + room = matrix.getRoomById(id)!; }); test('Test call methods', () async { @@ -54,10 +47,9 @@ void main() { room, '1234', '4567', SDPStreamMetadata({}), txid: '1234'); }); - test('Test call lifetime', () async { - final voip = VoIP(matrix, MockWebRTCDelegate()); + + test('Call lifetime and age', () async { expect(voip.currentCID, null); - // persist normal room messages await matrix.handleSync(SyncUpdate( nextBatch: 'something', rooms: RoomsUpdate(join: { @@ -77,12 +69,11 @@ void main() { ) ])) }))); - await Future.delayed(Duration(seconds: 3)); + await Future.delayed(Duration(seconds: 2)); // confirm that no call got created after 3 seconds, which is // expected in this case because the originTs was old asf expect(voip.currentCID, null); - // persist normal room messages await matrix.handleSync(SyncUpdate( nextBatch: 'something', rooms: RoomsUpdate(join: { @@ -103,11 +94,13 @@ void main() { ) ])) }))); - await Future.delayed(Duration(seconds: 3)); + await Future.delayed(Duration(seconds: 2)); // confirm that no call got created after 3 seconds, which is // expected in this case because age was older than lifetime expect(voip.currentCID, null); - // persist normal room messages + }); + test('Call connection and hanging up', () async { + expect(voip.currentCID, null); await matrix.handleSync(SyncUpdate( nextBatch: 'something', rooms: RoomsUpdate(join: { @@ -118,11 +111,43 @@ void main() { content: { 'lifetime': 60000, 'call_id': 'originTsValidCall', - 'party_id': 'DPCIPPBGPO', + 'party_id': 'GHTYAJCE_caller', + 'version': '1', 'offer': {'type': 'offer', 'sdp': 'sdp'} }, senderId: '@alice:testing.com', - eventId: 'newevent', + eventId: 'callerInviteEvent', + originServerTs: DateTime.now(), + ) + ])) + }))); + await matrix.handleSync(SyncUpdate( + nextBatch: 'something', + rooms: RoomsUpdate(join: { + room.id: JoinedRoomUpdate( + timeline: TimelineUpdate(events: [ + MatrixEvent( + type: 'm.call.candidates', + content: { + 'call_id': 'originTsValidCall', + 'party_id': 'GHTYAJCE_caller', + 'version': '1', + 'candidates': [ + { + 'candidate': 'candidate:01UDP2122252543uwu50184typhost', + 'sdpMid': '0', + 'sdpMLineIndex': 0 + }, + { + 'candidate': + 'candidate:31TCP2105524479uwu9typhosttcptypeactive', + 'sdpMid': '0', + 'sdpMLineIndex': 0 + } + ], + }, + senderId: '@alice:testing.com', + eventId: 'callerCallCandidatesEvent', originServerTs: DateTime.now(), ) ])) @@ -134,8 +159,291 @@ void main() { } expect(voip.currentCID, 'originTsValidCall'); final call = voip.calls[voip.currentCID]!; + expect(call.state, CallState.kRinging); await call.answer(txid: '1234'); + + call.pc!.onIceGatheringState! + .call(RTCIceGatheringState.RTCIceGatheringStateComplete); + // we send them manually anyway because our stub sends empty list of + // candidates + await call.sendCallCandidates( + room, + 'originTsValidCall', + 'GHTYAJCE', + [ + { + 'candidate': 'candidate:0 1 UDP 2122252543 uwu 50184 typ host', + 'sdpMid': '0', + 'sdpMLineIndex': 0 + }, + { + 'candidate': + 'candidate:3 1 TCP 2105524479 uwu 9 typ host tcptype active', + 'sdpMid': '0', + 'sdpMLineIndex': 0 + } + ], + txid: '1234'); + expect(call.state, CallState.kConnecting); + + // caller sends select answer + await matrix.handleSync(SyncUpdate( + nextBatch: 'something', + rooms: RoomsUpdate(join: { + room.id: JoinedRoomUpdate( + timeline: TimelineUpdate(events: [ + MatrixEvent( + type: 'm.call.select_answer', + content: { + 'call_id': 'originTsValidCall', + 'party_id': 'GHTYAJCE_caller', + 'version': '1', + 'lifetime': 10000, + 'selected_party_id': 'GHTYAJCE' + }, + senderId: '@alice:testing.com', + eventId: 'callerSelectAnswerEvent', + originServerTs: DateTime.now(), + ) + ])) + }))); + + call.pc!.onIceConnectionState! + .call(RTCIceConnectionState.RTCIceConnectionStateChecking); + call.pc!.onIceConnectionState! + .call(RTCIceConnectionState.RTCIceConnectionStateConnected); + // just to make sure there are no errors after running functions + // that are supposed to run once iceConnectionState is connected + await Future.delayed(Duration(seconds: 2)); + + expect(call.state, CallState.kConnected); + + await call.hangup(); + expect(call.state, CallState.kEnded); + expect(voip.currentCID, null); + }); + + test('Call answered elsewhere', () async { + expect(voip.currentCID, null); + await matrix.handleSync(SyncUpdate( + nextBatch: 'something', + rooms: RoomsUpdate(join: { + room.id: JoinedRoomUpdate( + timeline: TimelineUpdate(events: [ + MatrixEvent( + type: 'm.call.invite', + content: { + 'lifetime': 60000, + 'call_id': 'answer_elseWhere', + 'party_id': 'GHTYAJCE_caller', + 'version': '1', + 'offer': {'type': 'offer', 'sdp': 'sdp'} + }, + senderId: '@alice:testing.com', + eventId: 'callerInviteEvent', + originServerTs: DateTime.now(), + ) + ])) + }))); + await matrix.handleSync(SyncUpdate( + nextBatch: 'something', + rooms: RoomsUpdate(join: { + room.id: JoinedRoomUpdate( + timeline: TimelineUpdate(events: [ + MatrixEvent( + type: 'm.call.candidates', + content: { + 'call_id': 'answer_elseWhere', + 'party_id': 'GHTYAJCE_caller', + 'version': '1', + 'candidates': [ + { + 'candidate': 'candidate:01UDP2122252543uwu50184typhost', + 'sdpMid': '0', + 'sdpMLineIndex': 0 + }, + { + 'candidate': + 'candidate:31TCP2105524479uwu9typhosttcptypeactive', + 'sdpMid': '0', + 'sdpMLineIndex': 0 + } + ], + }, + senderId: '@alice:testing.com', + eventId: 'callerCallCandidatesEvent', + originServerTs: DateTime.now(), + ) + ])) + }))); + while (voip.currentCID != 'answer_elseWhere') { + // call invite looks valid, call should be created now :D + await Future.delayed(Duration(milliseconds: 50)); + Logs().d('Waiting for currentCID to update'); + } + expect(voip.currentCID, 'answer_elseWhere'); + final call = voip.calls[voip.currentCID]!; + expect(call.state, CallState.kRinging); + + // caller sends select answer + await matrix.handleSync(SyncUpdate( + nextBatch: 'something', + rooms: RoomsUpdate(join: { + room.id: JoinedRoomUpdate( + timeline: TimelineUpdate(events: [ + MatrixEvent( + type: 'm.call.select_answer', + content: { + 'call_id': 'answer_elseWhere', + 'party_id': 'GHTYAJCE_caller', + 'version': '1', + 'lifetime': 10000, + 'selected_party_id': + 'not_us' // selected some other device for answer + }, + senderId: '@alice:testing.com', + eventId: 'callerSelectAnswerEvent', + originServerTs: DateTime.now(), + ) + ])) + }))); + // wait for select answer to end the call + await Future.delayed(Duration(seconds: 2)); + // call ended because answered elsewhere + expect(call.state, CallState.kEnded); + expect(voip.currentCID, null); + }); + + test('Reject incoming call', () async { + expect(voip.currentCID, null); + await matrix.handleSync(SyncUpdate( + nextBatch: 'something', + rooms: RoomsUpdate(join: { + room.id: JoinedRoomUpdate( + timeline: TimelineUpdate(events: [ + MatrixEvent( + type: 'm.call.invite', + content: { + 'lifetime': 60000, + 'call_id': 'reject_call', + 'party_id': 'GHTYAJCE_caller', + 'version': '1', + 'offer': {'type': 'offer', 'sdp': 'sdp'} + }, + senderId: '@alice:testing.com', + eventId: 'callerInviteEvent', + originServerTs: DateTime.now(), + ) + ])) + }))); + await matrix.handleSync(SyncUpdate( + nextBatch: 'something', + rooms: RoomsUpdate(join: { + room.id: JoinedRoomUpdate( + timeline: TimelineUpdate(events: [ + MatrixEvent( + type: 'm.call.candidates', + content: { + 'call_id': 'reject_call', + 'party_id': 'GHTYAJCE_caller', + 'version': '1', + 'candidates': [ + { + 'candidate': 'candidate:01UDP2122252543uwu50184typhost', + 'sdpMid': '0', + 'sdpMLineIndex': 0 + }, + { + 'candidate': + 'candidate:31TCP2105524479uwu9typhosttcptypeactive', + 'sdpMid': '0', + 'sdpMLineIndex': 0 + } + ], + }, + senderId: '@alice:testing.com', + eventId: 'callerCallCandidatesEvent', + originServerTs: DateTime.now(), + ) + ])) + }))); + while (voip.currentCID != 'reject_call') { + // call invite looks valid, call should be created now :D + await Future.delayed(Duration(milliseconds: 50)); + Logs().d('Waiting for currentCID to update'); + } + expect(voip.currentCID, 'reject_call'); + final call = voip.calls[voip.currentCID]!; + expect(call.state, CallState.kRinging); + + await call.reject(); + + // call ended because answered elsewhere + expect(call.state, CallState.kEnded); + expect(voip.currentCID, null); + }); + + test('Glare after invite was sent', () async { + expect(voip.currentCID, null); + final firstCall = await voip.inviteToCall(room.id, CallType.kVoice); + await firstCall.pc!.onRenegotiationNeeded!.call(); + expect(firstCall.state, CallState.kInviteSent); + // KABOOM YOU JUST GLARED + await Future.delayed(Duration(seconds: 3)); + await matrix.handleSync(SyncUpdate( + nextBatch: 'something', + rooms: RoomsUpdate(join: { + room.id: JoinedRoomUpdate( + timeline: TimelineUpdate(events: [ + MatrixEvent( + type: 'm.call.invite', + content: { + 'lifetime': 60000, + 'call_id': 'zzzz_glare_2nd_call', + 'party_id': 'GHTYAJCE_caller', + 'version': '1', + 'offer': {'type': 'offer', 'sdp': 'sdp'} + }, + senderId: '@alice:testing.com', + eventId: 'callerInviteEvent', + originServerTs: DateTime.now(), + ) + ])) + }))); + await Future.delayed(Duration(seconds: 3)); + expect(voip.currentCID, firstCall.callId); + await firstCall.hangup(); + }); + test('Glare before invite was sent', () async { + expect(voip.currentCID, null); + final firstCall = await voip.inviteToCall(room.id, CallType.kVoice); + expect(firstCall.state, CallState.kCreateOffer); + // KABOOM YOU JUST GLARED, but this tiem you were still preparing your call + // so just cancel that instead + await Future.delayed(Duration(seconds: 3)); + await matrix.handleSync(SyncUpdate( + nextBatch: 'something', + rooms: RoomsUpdate(join: { + room.id: JoinedRoomUpdate( + timeline: TimelineUpdate(events: [ + MatrixEvent( + type: 'm.call.invite', + content: { + 'lifetime': 60000, + 'call_id': 'zzzz_glare_2nd_call', + 'party_id': 'GHTYAJCE_caller', + 'version': '1', + 'offer': {'type': 'offer', 'sdp': 'sdp'} + }, + senderId: '@alice:testing.com', + eventId: 'callerInviteEvent', + originServerTs: DateTime.now(), + ) + ])) + }))); + await Future.delayed(Duration(seconds: 3)); + expect(voip.currentCID, 'zzzz_glare_2nd_call'); }); }); } diff --git a/test/client_test.dart b/test/client_test.dart index 6369d4e4..ef025f07 100644 --- a/test/client_test.dart +++ b/test/client_test.dart @@ -121,23 +121,23 @@ void main() { expect(matrix.accountData.length, 10); expect(matrix.getDirectChatFromUserId('@bob:example.com'), '!726s6s6q:example.com'); - expect(matrix.rooms[1].directChatMatrixID, '@bob:example.com'); + expect(matrix.rooms[2].directChatMatrixID, '@bob:example.com'); expect(matrix.directChats, matrix.accountData['m.direct']?.content); // ignore: deprecated_member_use_from_same_package expect(matrix.presences.length, 1); - expect(matrix.rooms[1].ephemerals.length, 2); - expect(matrix.rooms[1].typingUsers.length, 1); - expect(matrix.rooms[1].typingUsers[0].id, '@alice:example.com'); - expect(matrix.rooms[1].roomAccountData.length, 3); - expect(matrix.rooms[1].encrypted, true); - expect(matrix.rooms[1].encryptionAlgorithm, + expect(matrix.rooms[2].ephemerals.length, 2); + expect(matrix.rooms[2].typingUsers.length, 1); + expect(matrix.rooms[2].typingUsers[0].id, '@alice:example.com'); + expect(matrix.rooms[2].roomAccountData.length, 3); + expect(matrix.rooms[2].encrypted, true); + expect(matrix.rooms[2].encryptionAlgorithm, Client.supportedGroupEncryptionAlgorithms.first); expect( - matrix.rooms[1].receiptState.global.otherUsers['@alice:example.com'] + matrix.rooms[2].receiptState.global.otherUsers['@alice:example.com'] ?.ts, 1436451550453); expect( - matrix.rooms[1].receiptState.global.otherUsers['@alice:example.com'] + matrix.rooms[2].receiptState.global.otherUsers['@alice:example.com'] ?.eventId, '\$7365636s6r6432:example.com'); @@ -145,8 +145,8 @@ void main() { .singleWhere((room) => room.membership == Membership.invite); expect(inviteRoom.name, 'My Room Name'); expect(inviteRoom.states[EventTypes.RoomMember]?.length, 1); - expect(matrix.rooms.length, 2); - expect(matrix.rooms[1].canonicalAlias, + expect(matrix.rooms.length, 3); + expect(matrix.rooms[2].canonicalAlias, "#famedlyContactDiscovery:${matrix.userID!.split(":")[1]}"); // ignore: deprecated_member_use_from_same_package expect(matrix.presences['@alice:example.com']?.presence, @@ -209,7 +209,7 @@ void main() { final eventUpdateList = await eventUpdateListFuture; - expect(eventUpdateList.length, 18); + expect(eventUpdateList.length, 20); expect(eventUpdateList[0].content['type'], 'm.room.member'); expect(eventUpdateList[0].roomID, '!726s6s6q:example.com'); @@ -256,13 +256,13 @@ void main() { expect(eventUpdateList[10].roomID, '!726s6s6q:example.com'); expect(eventUpdateList[10].type, EventUpdateType.accountData); - expect(eventUpdateList[11].content['type'], 'm.room.name'); - expect(eventUpdateList[11].roomID, '!696r7674:example.com'); - expect(eventUpdateList[11].type, EventUpdateType.inviteState); + expect(eventUpdateList[11].content['type'], 'm.room.member'); + expect(eventUpdateList[11].roomID, '!calls:example.com'); + expect(eventUpdateList[11].type, EventUpdateType.state); expect(eventUpdateList[12].content['type'], 'm.room.member'); - expect(eventUpdateList[12].roomID, '!696r7674:example.com'); - expect(eventUpdateList[12].type, EventUpdateType.inviteState); + expect(eventUpdateList[12].roomID, '!calls:example.com'); + expect(eventUpdateList[12].type, EventUpdateType.state); await matrix.onToDeviceEvent.close(); @@ -909,7 +909,7 @@ void main() { await Future.delayed(Duration(milliseconds: 500)); expect(client1.isLogged(), true); - expect(client1.rooms.length, 2); + expect(client1.rooms.length, 3); final client2 = Client( 'testclient', @@ -926,7 +926,7 @@ void main() { expect(client2.homeserver, client1.homeserver); expect(client2.deviceID, client1.deviceID); expect(client2.deviceName, client1.deviceName); - expect(client2.rooms.length, 2); + expect(client2.rooms.length, 3); if (client2.encryptionEnabled) { expect(client2.encryption?.fingerprintKey, client1.encryption?.fingerprintKey); @@ -1111,7 +1111,7 @@ void main() { final client = await getClient(); await Future.delayed(Duration(milliseconds: 50)); - expect(client.rooms.length, 2, + expect(client.rooms.length, 3, reason: 'Count of invited+joined before loadArchive() rooms does not match'); expect(client.archivedRooms.length, 0, @@ -1120,7 +1120,7 @@ void main() { await client.loadArchive(); - expect(client.rooms.length, 2, + expect(client.rooms.length, 3, reason: 'Count of invited+joined rooms does not match'); expect(client.archivedRooms.length, 2, reason: 'Count of archived rooms does not match'); diff --git a/test/fake_matrix_api.dart b/test/fake_matrix_api.dart index 0af46749..b9e46353 100644 --- a/test/fake_matrix_api.dart +++ b/test/fake_matrix_api.dart @@ -572,7 +572,37 @@ class FakeMatrixApi extends BaseClient { } ] } - } + }, + '!calls:example.com': { + 'state': { + 'events': [ + { + 'sender': '@test:fakeServer.notExisting', + 'type': 'm.room.member', + 'state_key': '@test:fakeServer.notExisting', + 'content': { + 'membership': 'join', + 'avatar_url': 'mxc://example.org/SEsfnsuifSDFSSEF', + 'displayname': 'Test User', + }, + 'origin_server_ts': 1417731086795, + 'event_id': 'calls_1:example.com' + }, + { + 'sender': '@alice:example.com', + 'type': 'm.room.member', + 'state_key': '@alice:example.com', + 'content': { + 'membership': 'join', + 'avatar_url': 'mxc://example.org/SEsfnsuifSDFSSEF', + 'displayname': 'Alice Margatroid', + }, + 'origin_server_ts': 1417731086795, + 'event_id': 'calls_2:example.com' + }, + ] + }, + }, }, 'invite': { '!696r7674:example.com': { @@ -2430,29 +2460,29 @@ class FakeMatrixApi extends BaseClient { (var req) => {'event_id': '1234'}, '/client/v3/rooms/!localpart%3Aserver.abc/state/m.room.guest_access': (var req) => {'event_id': '1234'}, - '/client/v3/rooms/!localpart%3Aserver.abc/send/m.call.invite/1234': + '/client/v3/rooms/!calls%3Aexample.com/send/m.call.invite/1234': (var req) => {'event_id': '1234'}, - '/client/v3/rooms/!localpart%3Aserver.abc/send/m.call.answer/1234': + '/client/v3/rooms/!calls%3Aexample.com/send/m.call.answer/1234': (var req) => {'event_id': '1234'}, - '/client/v3/rooms/!localpart%3Aserver.abc/send/m.call.select_answer/1234': + '/client/v3/rooms/!calls%3Aexample.com/send/m.call.select_answer/1234': (var req) => {'event_id': '1234'}, - '/client/v3/rooms/!localpart%3Aserver.abc/send/m.call.reject/1234': + '/client/v3/rooms/!calls%3Aexample.com/send/m.call.reject/1234': (var req) => {'event_id': '1234'}, - '/client/v3/rooms/!localpart%3Aserver.abc/send/m.call.negotiate/1234': + '/client/v3/rooms/!calls%3Aexample.com/send/m.call.negotiate/1234': (var req) => {'event_id': '1234'}, - '/client/v3/rooms/!localpart%3Aserver.abc/send/m.call.candidates/1234': + '/client/v3/rooms/!calls%3Aexample.com/send/m.call.candidates/1234': (var req) => {'event_id': '1234'}, - '/client/v3/rooms/!localpart%3Aserver.abc/send/m.call.hangup/1234': + '/client/v3/rooms/!calls%3Aexample.com/send/m.call.hangup/1234': (var req) => {'event_id': '1234'}, - '/client/v3/rooms/!localpart%3Aserver.abc/send/m.call.replaces/1234': + '/client/v3/rooms/!calls%3Aexample.com/send/m.call.replaces/1234': (var req) => {'event_id': '1234'}, - '/client/v3/rooms/!localpart%3Aserver.abc/send/m.call.asserted_identity/1234': + '/client/v3/rooms/!calls%3Aexample.com/send/m.call.asserted_identity/1234': (var req) => {'event_id': '1234'}, - '/client/v3/rooms/!localpart%3Aserver.abc/send/m.call.sdp_stream_metadata_changed/1234': + '/client/v3/rooms/!calls%3Aexample.com/send/m.call.sdp_stream_metadata_changed/1234': (var req) => {'event_id': '1234'}, - '/client/v3/rooms/!localpart%3Aserver.abc/send/org.matrix.call.sdp_stream_metadata_changed/1234': + '/client/v3/rooms/!calls%3Aexample.com/send/org.matrix.call.sdp_stream_metadata_changed/1234': (var req) => {'event_id': '1234'}, - '/client/v3/rooms/!localpart%3Aserver.abc/send/org.matrix.call.asserted_identity/1234': + '/client/v3/rooms/!calls%3Aexample.com/send/org.matrix.call.asserted_identity/1234': (var req) => {'event_id': '1234'}, '/client/v3/rooms/!1234%3Aexample.com/redact/1143273582443PhrSn%3Aexample.org/1234': (var req) => {'event_id': '1234'}, diff --git a/test/room_archived_test.dart b/test/room_archived_test.dart index 6cfa5bd9..3c23d8d6 100644 --- a/test/room_archived_test.dart +++ b/test/room_archived_test.dart @@ -62,7 +62,7 @@ void main() { final archive = await client.loadArchiveWithTimeline(); expect(archive.length, 2); - expect(client.rooms.length, 2); + expect(client.rooms.length, 3); expect(archive[0].room.id, '!5345234234:example.com'); expect(archive[0].room.membership, Membership.leave); expect(archive[0].room.name, 'The room name'); diff --git a/test/webrtc_stub.dart b/test/webrtc_stub.dart index dee2449a..9c61a072 100644 --- a/test/webrtc_stub.dart +++ b/test/webrtc_stub.dart @@ -150,7 +150,9 @@ class MockRTCPeerConnection implements RTCPeerConnection { } @override - RTCIceGatheringState? get iceGatheringState => throw UnimplementedError(); + // value doesn't matter we do onIceConnectionState.call manually + RTCIceGatheringState? get iceGatheringState => + RTCIceGatheringState.RTCIceGatheringStateComplete; @override Future getIceGatheringState() async { @@ -158,7 +160,9 @@ class MockRTCPeerConnection implements RTCPeerConnection { } @override - RTCIceConnectionState? get iceConnectionState => throw UnimplementedError(); + // value doesn't matter we do onIceConnectionState.call manually + RTCIceConnectionState? get iceConnectionState => + RTCIceConnectionState.RTCIceConnectionStateNew; @override Future getIceConnectionState() async {