Merge branch 'main' into krille/better-syncloop-error
This commit is contained in:
commit
e03826b1bb
12
CHANGELOG.md
12
CHANGELOG.md
|
|
@ -1,3 +1,15 @@
|
||||||
|
## [0.22.7] - 16 November 2023
|
||||||
|
- chore: incrementally add left rooms to archive (The one with the braid)
|
||||||
|
- chore: remove archived room on forget (#2) (Clemens-Toegel)
|
||||||
|
- chore: store states to archived rooms (#1) (Clemens-Toegel)
|
||||||
|
- chore: upgrade lints (Nicolas Werner)
|
||||||
|
- chore: use our custom reusable workflow to avoid manually configuring each publish job (td)
|
||||||
|
- fix: Code style (The one with the braid)
|
||||||
|
- fix: call hangup on timeout race condition (Karthikeyan S)
|
||||||
|
- fix: clear local database on logout even if server timesout (td)
|
||||||
|
- fix: hangup on call crash (Mohammad Reza Moradi)
|
||||||
|
- fix: stale call checker leaks memory (Nicolas Werner)
|
||||||
|
|
||||||
## [0.22.6] - 23 October 2023
|
## [0.22.6] - 23 October 2023
|
||||||
- fix: Do not convert linebreaks in pre blocks on markdown parsing (Krille)
|
- fix: Do not convert linebreaks in pre blocks on markdown parsing (Krille)
|
||||||
- refactor: Wait for room in sync until sync process and trigger cleanup call not before actually start clean up. (Krille)
|
- refactor: Wait for room in sync until sync process and trigger cleanup call not before actually start clean up. (Krille)
|
||||||
|
|
|
||||||
|
|
@ -554,10 +554,9 @@ class Client extends MatrixApi {
|
||||||
/// including all persistent data from the store.
|
/// including all persistent data from the store.
|
||||||
@override
|
@override
|
||||||
Future<void> logout() async {
|
Future<void> logout() async {
|
||||||
// Upload keys to make sure all are cached on the next login.
|
|
||||||
await encryption?.keyManager.uploadInboundGroupSessions();
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
// Upload keys to make sure all are cached on the next login.
|
||||||
|
await encryption?.keyManager.uploadInboundGroupSessions();
|
||||||
await super.logout();
|
await super.logout();
|
||||||
} catch (e, s) {
|
} catch (e, s) {
|
||||||
Logs().e('Logout failed', e, s);
|
Logs().e('Logout failed', e, s);
|
||||||
|
|
@ -934,6 +933,7 @@ class Client extends MatrixApi {
|
||||||
final syncResp = await sync(
|
final syncResp = await sync(
|
||||||
filter: '{"room":{"include_leave":true,"timeline":{"limit":10}}}',
|
filter: '{"room":{"include_leave":true,"timeline":{"limit":10}}}',
|
||||||
timeout: _archiveCacheBusterTimeout,
|
timeout: _archiveCacheBusterTimeout,
|
||||||
|
setPresence: syncPresence,
|
||||||
);
|
);
|
||||||
// wrap around and hope there are not more than 30 leaves in 2 minutes :)
|
// wrap around and hope there are not more than 30 leaves in 2 minutes :)
|
||||||
_archiveCacheBusterTimeout = (_archiveCacheBusterTimeout + 1) % 30;
|
_archiveCacheBusterTimeout = (_archiveCacheBusterTimeout + 1) % 30;
|
||||||
|
|
@ -1742,6 +1742,8 @@ class Client extends MatrixApi {
|
||||||
await processToDeviceQueue();
|
await processToDeviceQueue();
|
||||||
} catch (_) {} // we want to dispose any errors this throws
|
} catch (_) {} // we want to dispose any errors this throws
|
||||||
|
|
||||||
|
await singleShotStaleCallChecker();
|
||||||
|
|
||||||
_retryDelay = Future.value();
|
_retryDelay = Future.value();
|
||||||
onSyncStatus.add(SyncStatusUpdate(SyncStatus.finished));
|
onSyncStatus.add(SyncStatusUpdate(SyncStatus.finished));
|
||||||
} on MatrixException catch (e, s) {
|
} on MatrixException catch (e, s) {
|
||||||
|
|
@ -1791,12 +1793,13 @@ class Client extends MatrixApi {
|
||||||
await _handleRooms(leave, direction: direction);
|
await _handleRooms(leave, direction: direction);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (final newPresence in sync.presence ?? []) {
|
for (final newPresence in sync.presence ?? <Presence>[]) {
|
||||||
final cachedPresence = CachedPresence.fromMatrixEvent(newPresence);
|
final cachedPresence = CachedPresence.fromMatrixEvent(newPresence);
|
||||||
presences[newPresence.senderId] = cachedPresence;
|
presences[newPresence.senderId] = cachedPresence;
|
||||||
// ignore: deprecated_member_use_from_same_package
|
// ignore: deprecated_member_use_from_same_package
|
||||||
onPresence.add(newPresence);
|
onPresence.add(newPresence);
|
||||||
onPresenceChanged.add(cachedPresence);
|
onPresenceChanged.add(cachedPresence);
|
||||||
|
await database?.storePresence(newPresence.senderId, cachedPresence);
|
||||||
}
|
}
|
||||||
for (final newAccountData in sync.accountData ?? []) {
|
for (final newAccountData in sync.accountData ?? []) {
|
||||||
await database?.storeAccountData(
|
await database?.storeAccountData(
|
||||||
|
|
@ -2149,6 +2152,9 @@ class Client extends MatrixApi {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// stores when we last checked for stale calls
|
||||||
|
DateTime lastStaleCallRun = DateTime(0);
|
||||||
|
|
||||||
Future<Room> _updateRoomsByRoomUpdate(
|
Future<Room> _updateRoomsByRoomUpdate(
|
||||||
String roomId, SyncRoomUpdate chatUpdate) async {
|
String roomId, SyncRoomUpdate chatUpdate) async {
|
||||||
// Update the chat list item.
|
// Update the chat list item.
|
||||||
|
|
@ -2189,9 +2195,6 @@ class Client extends MatrixApi {
|
||||||
}
|
}
|
||||||
// If the membership is "leave" then remove the item and stop here
|
// If the membership is "leave" then remove the item and stop here
|
||||||
else if (found && membership == Membership.leave) {
|
else if (found && membership == Membership.leave) {
|
||||||
// stop stale group call checker for left room.
|
|
||||||
room.stopStaleCallsChecker(room.id);
|
|
||||||
|
|
||||||
rooms.removeAt(roomIndex);
|
rooms.removeAt(roomIndex);
|
||||||
|
|
||||||
// in order to keep the archive in sync, add left room to archive
|
// in order to keep the archive in sync, add left room to archive
|
||||||
|
|
@ -2924,6 +2927,25 @@ class Client extends MatrixApi {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The newest presence of this user if there is any. Fetches it from the
|
||||||
|
/// database first and then from the server if necessary or returns offline.
|
||||||
|
Future<CachedPresence> fetchCurrentPresence(String userId) async {
|
||||||
|
final cachedPresence = presences[userId];
|
||||||
|
if (cachedPresence != null) {
|
||||||
|
return cachedPresence;
|
||||||
|
}
|
||||||
|
|
||||||
|
final dbPresence = await database?.getPresence(userId);
|
||||||
|
if (dbPresence != null) return presences[userId] = dbPresence;
|
||||||
|
|
||||||
|
try {
|
||||||
|
final newPresence = await getPresence(userId);
|
||||||
|
return CachedPresence.fromPresenceResponse(newPresence, userId);
|
||||||
|
} catch (e) {
|
||||||
|
return CachedPresence.neverSeen(userId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool _disposed = false;
|
bool _disposed = false;
|
||||||
bool _aborted = false;
|
bool _aborted = false;
|
||||||
Future _currentTransaction = Future.sync(() => {});
|
Future _currentTransaction = Future.sync(() => {});
|
||||||
|
|
|
||||||
|
|
@ -312,4 +312,8 @@ abstract class DatabaseApi {
|
||||||
Future<String> exportDump();
|
Future<String> exportDump();
|
||||||
|
|
||||||
Future<bool> importDump(String export);
|
Future<bool> importDump(String export);
|
||||||
|
|
||||||
|
Future<void> storePresence(String userId, CachedPresence presence);
|
||||||
|
|
||||||
|
Future<CachedPresence?> getPresence(String userId);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1478,6 +1478,18 @@ class HiveCollectionsDatabase extends DatabaseApi {
|
||||||
return raw;
|
return raw;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> storePresence(String userId, CachedPresence presence) =>
|
||||||
|
_presencesBox.put(userId, presence.toJson());
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<CachedPresence?> getPresence(String userId) async {
|
||||||
|
final rawPresence = await _presencesBox.get(userId);
|
||||||
|
if (rawPresence == null) return null;
|
||||||
|
|
||||||
|
return CachedPresence.fromJson(copyMap(rawPresence));
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<String> exportDump() async {
|
Future<String> exportDump() async {
|
||||||
final dataMap = {
|
final dataMap = {
|
||||||
|
|
|
||||||
|
|
@ -1450,6 +1450,18 @@ class FamedlySdkHiveDatabase extends DatabaseApi {
|
||||||
return raw as String;
|
return raw as String;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> storePresence(String userId, CachedPresence presence) =>
|
||||||
|
_presencesBox.put(userId, presence.toJson());
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<CachedPresence?> getPresence(String userId) async {
|
||||||
|
final rawPresence = await _presencesBox.get(userId);
|
||||||
|
if (rawPresence == null) return null;
|
||||||
|
|
||||||
|
return CachedPresence.fromJson(copyMap(rawPresence));
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<String> exportDump() {
|
Future<String> exportDump() {
|
||||||
// see no need to implement this in a deprecated part
|
// see no need to implement this in a deprecated part
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,36 @@ class CachedPresence {
|
||||||
bool? currentlyActive;
|
bool? currentlyActive;
|
||||||
String userid;
|
String userid;
|
||||||
|
|
||||||
|
factory CachedPresence.fromJson(Map<String, Object?> json) =>
|
||||||
|
CachedPresence._(
|
||||||
|
presence: PresenceType.values
|
||||||
|
.singleWhere((type) => type.name == json['presence']),
|
||||||
|
lastActiveTimestamp: json['last_active_timestamp'] != null
|
||||||
|
? DateTime.fromMillisecondsSinceEpoch(
|
||||||
|
json['last_active_timestamp'] as int)
|
||||||
|
: null,
|
||||||
|
statusMsg: json['status_msg'] as String?,
|
||||||
|
currentlyActive: json['currently_active'] as bool?,
|
||||||
|
userid: json['user_id'] as String,
|
||||||
|
);
|
||||||
|
|
||||||
|
Map<String, Object?> toJson() => {
|
||||||
|
'user_id': userid,
|
||||||
|
'presence': presence.name,
|
||||||
|
if (lastActiveTimestamp != null)
|
||||||
|
'last_active_timestamp': lastActiveTimestamp?.millisecondsSinceEpoch,
|
||||||
|
if (statusMsg != null) 'status_msg': statusMsg,
|
||||||
|
if (currentlyActive != null) 'currently_active': currentlyActive,
|
||||||
|
};
|
||||||
|
|
||||||
|
CachedPresence._({
|
||||||
|
required this.userid,
|
||||||
|
required this.presence,
|
||||||
|
this.lastActiveTimestamp,
|
||||||
|
this.statusMsg,
|
||||||
|
this.currentlyActive,
|
||||||
|
});
|
||||||
|
|
||||||
CachedPresence(this.presence, int? lastActiveAgo, this.statusMsg,
|
CachedPresence(this.presence, int? lastActiveAgo, this.statusMsg,
|
||||||
this.currentlyActive, this.userid) {
|
this.currentlyActive, this.userid) {
|
||||||
if (lastActiveAgo != null) {
|
if (lastActiveAgo != null) {
|
||||||
|
|
@ -49,7 +79,7 @@ class CachedPresence {
|
||||||
|
|
||||||
Presence toPresence() {
|
Presence toPresence() {
|
||||||
final content = <String, dynamic>{
|
final content = <String, dynamic>{
|
||||||
'presence': presence.toString(),
|
'presence': presence.name.toString(),
|
||||||
};
|
};
|
||||||
if (currentlyActive != null) content['currently_active'] = currentlyActive!;
|
if (currentlyActive != null) content['currently_active'] = currentlyActive!;
|
||||||
if (lastActiveTimestamp != null) {
|
if (lastActiveTimestamp != null) {
|
||||||
|
|
|
||||||
|
|
@ -90,9 +90,6 @@ class Room {
|
||||||
/// Key-Value store for private account data only visible for this user.
|
/// Key-Value store for private account data only visible for this user.
|
||||||
Map<String, BasicRoomEvent> roomAccountData = {};
|
Map<String, BasicRoomEvent> roomAccountData = {};
|
||||||
|
|
||||||
/// stores stale group call checking timers for rooms.
|
|
||||||
Map<String, Timer> staleGroupCallsTimer = {};
|
|
||||||
|
|
||||||
final _sendingQueue = <Completer>[];
|
final _sendingQueue = <Completer>[];
|
||||||
|
|
||||||
Map<String, dynamic> toJson() => {
|
Map<String, dynamic> toJson() => {
|
||||||
|
|
@ -137,9 +134,6 @@ class Room {
|
||||||
setState(state);
|
setState(state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!isArchived) {
|
|
||||||
startStaleCallsChecker(id);
|
|
||||||
}
|
|
||||||
partial = false;
|
partial = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -155,20 +155,10 @@ class User extends Event {
|
||||||
@Deprecated('Use fetchCurrentPresence() instead')
|
@Deprecated('Use fetchCurrentPresence() instead')
|
||||||
Future<CachedPresence> get currentPresence => fetchCurrentPresence();
|
Future<CachedPresence> get currentPresence => fetchCurrentPresence();
|
||||||
|
|
||||||
/// The newest presence of this user if there is any. Fetches it from the server if necessary or returns offline.
|
/// The newest presence of this user if there is any. Fetches it from the
|
||||||
Future<CachedPresence> fetchCurrentPresence() async {
|
/// database first and then from the server if necessary or returns offline.
|
||||||
final cachedPresence = room.client.presences[id];
|
Future<CachedPresence> fetchCurrentPresence() =>
|
||||||
if (cachedPresence != null) {
|
room.client.fetchCurrentPresence(id);
|
||||||
return cachedPresence;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
final newPresence = await room.client.getPresence(id);
|
|
||||||
return CachedPresence.fromPresenceResponse(newPresence, id);
|
|
||||||
} catch (e) {
|
|
||||||
return CachedPresence.neverSeen(id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Whether the client is able to ban/unban this user.
|
/// Whether the client is able to ban/unban this user.
|
||||||
bool get canBan => room.canBan && powerLevel < room.ownPowerLevel;
|
bool get canBan => room.canBan && powerLevel < room.ownPowerLevel;
|
||||||
|
|
|
||||||
|
|
@ -1200,7 +1200,9 @@ class CallSession {
|
||||||
setCallState(CallState.kEnded);
|
setCallState(CallState.kEnded);
|
||||||
|
|
||||||
if (!isGroupCall) {
|
if (!isGroupCall) {
|
||||||
if (callId != voip.currentCID) return;
|
// when a call crash and this call is already terminated the currentCId is null.
|
||||||
|
// So don't return bc the hangup or reject will not proceed anymore.
|
||||||
|
if (callId != voip.currentCID && voip.currentCID != null) return;
|
||||||
voip.currentCID = null;
|
voip.currentCID = null;
|
||||||
voip.incomingCallRoomId.removeWhere((key, value) => value == callId);
|
voip.incomingCallRoomId.removeWhere((key, value) => value == callId);
|
||||||
}
|
}
|
||||||
|
|
@ -1286,7 +1288,7 @@ class CallSession {
|
||||||
|
|
||||||
inviteTimer = Timer(Duration(seconds: Timeouts.callTimeoutSec), () {
|
inviteTimer = Timer(Duration(seconds: Timeouts.callTimeoutSec), () {
|
||||||
if (state == CallState.kInviteSent) {
|
if (state == CallState.kInviteSent) {
|
||||||
hangup(CallErrorCode.InviteTimeout, false);
|
hangup(CallErrorCode.InviteTimeout);
|
||||||
}
|
}
|
||||||
inviteTimer?.cancel();
|
inviteTimer?.cancel();
|
||||||
inviteTimer = null;
|
inviteTimer = null;
|
||||||
|
|
|
||||||
|
|
@ -43,17 +43,6 @@ extension GroupCallUtils on Room {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
/// stops the stale call checker timer
|
|
||||||
void stopStaleCallsChecker(String roomId) {
|
|
||||||
if (staleGroupCallsTimer.tryGet(roomId) != null) {
|
|
||||||
staleGroupCallsTimer[roomId]!.cancel();
|
|
||||||
staleGroupCallsTimer.remove(roomId);
|
|
||||||
Logs().d('[VOIP] stopped stale group calls checker for room $id');
|
|
||||||
} else {
|
|
||||||
Logs().d('[VOIP] no stale call checker for room found');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static const staleCallCheckerDuration = Duration(seconds: 30);
|
static const staleCallCheckerDuration = Duration(seconds: 30);
|
||||||
|
|
||||||
bool callMemberStateIsExpired(
|
bool callMemberStateIsExpired(
|
||||||
|
|
@ -89,23 +78,16 @@ extension GroupCallUtils on Room {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// checks for stale calls in a room and sends `m.terminated` if all the
|
/// checks for stale calls in a room and sends `m.terminated` if all the
|
||||||
/// expires_ts are expired. Call when opening a room
|
/// expires_ts are expired. Called regularly on sync.
|
||||||
void startStaleCallsChecker(String roomId) async {
|
|
||||||
stopStaleCallsChecker(roomId);
|
|
||||||
await singleShotStaleCallCheckerOnRoom();
|
|
||||||
staleGroupCallsTimer[roomId] = Timer.periodic(
|
|
||||||
staleCallCheckerDuration,
|
|
||||||
(timer) async => await singleShotStaleCallCheckerOnRoom(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> singleShotStaleCallCheckerOnRoom() async {
|
Future<void> singleShotStaleCallCheckerOnRoom() async {
|
||||||
Logs().d('[VOIP] checking for stale group calls in room $id');
|
if (partial) return;
|
||||||
// make sure we have all the to-device messages we are supposed to have
|
|
||||||
await client.oneShotSync();
|
|
||||||
final copyGroupCallIds =
|
final copyGroupCallIds =
|
||||||
states.tryGetMap<String, Event>(EventTypes.GroupCallPrefix);
|
states.tryGetMap<String, Event>(EventTypes.GroupCallPrefix);
|
||||||
if (copyGroupCallIds == null) return;
|
if (copyGroupCallIds == null) return;
|
||||||
|
|
||||||
|
Logs().d('[VOIP] checking for stale group calls in room $id');
|
||||||
|
|
||||||
for (final groupCall in copyGroupCallIds.entries) {
|
for (final groupCall in copyGroupCallIds.entries) {
|
||||||
final groupCallId = groupCall.key;
|
final groupCallId = groupCall.key;
|
||||||
final groupCallEvent = groupCall.value;
|
final groupCallEvent = groupCall.value;
|
||||||
|
|
@ -165,3 +147,16 @@ extension GroupCallUtils on Room {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension GroupCallClientUtils on Client {
|
||||||
|
// call after sync
|
||||||
|
Future<void> singleShotStaleCallChecker() async {
|
||||||
|
if (lastStaleCallRun
|
||||||
|
.add(GroupCallUtils.staleCallCheckerDuration)
|
||||||
|
.isBefore(DateTime.now())) {
|
||||||
|
await Future.wait(rooms
|
||||||
|
.where((r) => r.membership == Membership.join)
|
||||||
|
.map((r) => r.singleShotStaleCallCheckerOnRoom()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
name: matrix
|
name: matrix
|
||||||
description: Matrix Dart SDK
|
description: Matrix Dart SDK
|
||||||
version: 0.22.6
|
version: 0.22.7
|
||||||
homepage: https://famedly.com
|
homepage: https://famedly.com
|
||||||
repository: https://github.com/famedly/matrix-dart-sdk.git
|
repository: https://github.com/famedly/matrix-dart-sdk.git
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -335,6 +335,94 @@ void main() {
|
||||||
expect(loginState, LoginState.loggedOut);
|
expect(loginState, LoginState.loggedOut);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('Login again but break server when trying to logout', () async {
|
||||||
|
matrix = Client(
|
||||||
|
'testclient',
|
||||||
|
httpClient: FakeMatrixApi(),
|
||||||
|
databaseBuilder: getDatabase,
|
||||||
|
);
|
||||||
|
|
||||||
|
try {
|
||||||
|
await olm.init();
|
||||||
|
olm.get_library_version();
|
||||||
|
} catch (e) {
|
||||||
|
olmEnabled = false;
|
||||||
|
Logs().w('[LibOlm] Failed to load LibOlm', e);
|
||||||
|
}
|
||||||
|
Logs().w('[LibOlm] Enabled: $olmEnabled');
|
||||||
|
|
||||||
|
expect(matrix.homeserver, null);
|
||||||
|
|
||||||
|
try {
|
||||||
|
await matrix
|
||||||
|
.checkHomeserver(Uri.parse('https://fakeserver.wrongaddress'));
|
||||||
|
} catch (exception) {
|
||||||
|
expect(exception.toString().isNotEmpty, true);
|
||||||
|
}
|
||||||
|
await matrix.checkHomeserver(Uri.parse('https://fakeserver.notexisting'),
|
||||||
|
checkWellKnown: false);
|
||||||
|
expect(matrix.homeserver.toString(), 'https://fakeserver.notexisting');
|
||||||
|
|
||||||
|
final available = await matrix.checkUsernameAvailability('testuser');
|
||||||
|
expect(available, true);
|
||||||
|
|
||||||
|
final loginStateFuture = matrix.onLoginStateChanged.stream.first;
|
||||||
|
final syncFuture = matrix.onSync.stream.first;
|
||||||
|
|
||||||
|
await matrix.init(
|
||||||
|
newToken: 'abcd',
|
||||||
|
newUserID: '@test:fakeServer.notExisting',
|
||||||
|
newHomeserver: matrix.homeserver,
|
||||||
|
newDeviceName: 'Text Matrix Client',
|
||||||
|
newDeviceID: 'GHTYAJCE',
|
||||||
|
newOlmAccount: pickledOlmAccount,
|
||||||
|
);
|
||||||
|
|
||||||
|
await Future.delayed(Duration(milliseconds: 50));
|
||||||
|
|
||||||
|
final loginState = await loginStateFuture;
|
||||||
|
final sync = await syncFuture;
|
||||||
|
|
||||||
|
expect(loginState, LoginState.loggedIn);
|
||||||
|
expect(matrix.onSync.value != null, true);
|
||||||
|
expect(matrix.encryptionEnabled, olmEnabled);
|
||||||
|
if (olmEnabled) {
|
||||||
|
expect(matrix.identityKey, identityKey);
|
||||||
|
expect(matrix.fingerprintKey, fingerprintKey);
|
||||||
|
}
|
||||||
|
expect(sync.nextBatch == matrix.prevBatch, true);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Logout but this time server is dead', () async {
|
||||||
|
final oldapi = FakeMatrixApi.currentApi?.api;
|
||||||
|
expect(
|
||||||
|
(FakeMatrixApi.currentApi?.api['PUT']?.keys.where((element) =>
|
||||||
|
element.startsWith('/client/v3/room_keys/keys?version')))?.length,
|
||||||
|
1);
|
||||||
|
// not a huge fan, open to ideas
|
||||||
|
FakeMatrixApi.currentApi?.api = {};
|
||||||
|
// random sanity test to test if the test to test the breaking server hack works.
|
||||||
|
expect(
|
||||||
|
(FakeMatrixApi.currentApi?.api['PUT']?.keys.where((element) =>
|
||||||
|
element.startsWith('/client/v3/room_keys/keys?version')))?.length,
|
||||||
|
null);
|
||||||
|
try {
|
||||||
|
await matrix.logout();
|
||||||
|
} catch (e) {
|
||||||
|
Logs().w(
|
||||||
|
'Ignore red warnings for this test, test is to check if database is cleared even if server breaks ');
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(matrix.accessToken == null, true);
|
||||||
|
expect(matrix.homeserver == null, true);
|
||||||
|
expect(matrix.userID == null, true);
|
||||||
|
expect(matrix.deviceID == null, true);
|
||||||
|
expect(matrix.deviceName == null, true);
|
||||||
|
expect(matrix.prevBatch == null, true);
|
||||||
|
|
||||||
|
FakeMatrixApi.currentApi?.api = oldapi!;
|
||||||
|
});
|
||||||
|
|
||||||
test('Login', () async {
|
test('Login', () async {
|
||||||
matrix = Client(
|
matrix = Client(
|
||||||
'testclient',
|
'testclient',
|
||||||
|
|
|
||||||
|
|
@ -457,6 +457,25 @@ void testDatabase(
|
||||||
'deviceId',
|
'deviceId',
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
test('getStorePresences', () async {
|
||||||
|
const userId = '@alice:example.com';
|
||||||
|
final presence = CachedPresence(
|
||||||
|
PresenceType.online,
|
||||||
|
100,
|
||||||
|
'test message',
|
||||||
|
true,
|
||||||
|
'@alice:example.com',
|
||||||
|
);
|
||||||
|
await database.storePresence(
|
||||||
|
userId,
|
||||||
|
presence,
|
||||||
|
);
|
||||||
|
final storedPresence = await database.getPresence(userId);
|
||||||
|
expect(
|
||||||
|
presence.toJson(),
|
||||||
|
storedPresence?.toJson(),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
// Clearing up from here
|
// Clearing up from here
|
||||||
test('clearSSSSCache', () async {
|
test('clearSSSSCache', () async {
|
||||||
|
|
|
||||||
|
|
@ -1051,7 +1051,7 @@ class FakeMatrixApi extends BaseClient {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
final Map<String, Map<String, dynamic>> api = {
|
Map<String, Map<String, dynamic>> api = {
|
||||||
'GET': {
|
'GET': {
|
||||||
'/path/to/auth/error': (var req) => {
|
'/path/to/auth/error': (var req) => {
|
||||||
'errcode': 'M_FORBIDDEN',
|
'errcode': 'M_FORBIDDEN',
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue