722 lines
22 KiB
Dart
722 lines
22 KiB
Dart
/*
|
|
* Famedly Matrix SDK
|
|
* Copyright (C) 2019, 2020 Famedly GmbH
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU Affero General Public License as
|
|
* published by the Free Software Foundation, either version 3 of the
|
|
* License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU Affero General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Affero General Public License
|
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
import 'dart:async';
|
|
import 'dart:convert';
|
|
import 'dart:typed_data';
|
|
|
|
import 'package:test/test.dart';
|
|
|
|
import 'package:matrix/matrix.dart';
|
|
import 'fake_database.dart';
|
|
|
|
String createLargeString(String character, int desiredSize) {
|
|
final buffer = StringBuffer();
|
|
|
|
while (buffer.length < desiredSize) {
|
|
buffer.write(character);
|
|
}
|
|
|
|
return buffer.toString();
|
|
}
|
|
|
|
void main() {
|
|
final databaseBuilders = {
|
|
'Matrix SDK Database': getMatrixSdkDatabase,
|
|
'Hive Collections Database': getHiveCollectionsDatabase,
|
|
};
|
|
|
|
for (final databaseBuilder in databaseBuilders.entries) {
|
|
group('Test ${databaseBuilder.key}', tags: 'olm', () {
|
|
late DatabaseApi database;
|
|
late int toDeviceQueueIndex;
|
|
|
|
test('Setup', () async {
|
|
database = await databaseBuilder.value(null);
|
|
});
|
|
test('transaction', () async {
|
|
var counter = 0;
|
|
await database.transaction(() async {
|
|
expect(counter++, 0);
|
|
await database.transaction(() async {
|
|
expect(counter++, 1);
|
|
await Future.delayed(Duration(milliseconds: 50));
|
|
expect(counter++, 2);
|
|
});
|
|
expect(counter++, 3);
|
|
});
|
|
});
|
|
test('insertIntoToDeviceQueue', () async {
|
|
toDeviceQueueIndex = await database.insertIntoToDeviceQueue(
|
|
'm.test',
|
|
'txnId',
|
|
'{"foo":"bar"}',
|
|
);
|
|
});
|
|
test('getToDeviceEventQueue', () async {
|
|
final toDeviceQueue = await database.getToDeviceEventQueue();
|
|
expect(toDeviceQueue.first.type, 'm.test');
|
|
});
|
|
test('deleteFromToDeviceQueue', () async {
|
|
await database.deleteFromToDeviceQueue(toDeviceQueueIndex);
|
|
final toDeviceQueue = await database.getToDeviceEventQueue();
|
|
expect(toDeviceQueue.isEmpty, true);
|
|
});
|
|
test('storeFile and deleteFile', () async {
|
|
await database.storeFile(
|
|
Uri.parse('mxc://test'),
|
|
Uint8List.fromList([0]),
|
|
0,
|
|
);
|
|
final file = await database.getFile(Uri.parse('mxc://test'));
|
|
expect(file != null, database.supportsFileStoring);
|
|
|
|
final result = await database.deleteFile(Uri.parse('mxc://test'));
|
|
expect(result, database.supportsFileStoring);
|
|
if (result) {
|
|
final file = await database.getFile(Uri.parse('mxc://test'));
|
|
expect(file, null);
|
|
}
|
|
});
|
|
test('getFile', () async {
|
|
await database.getFile(Uri.parse('mxc://test'));
|
|
});
|
|
test('deleteOldFiles', () async {
|
|
await database.deleteOldFiles(1);
|
|
final file = await database.getFile(Uri.parse('mxc://test'));
|
|
expect(file == null, true);
|
|
});
|
|
test('storeRoomUpdate', () async {
|
|
final roomUpdate = JoinedRoomUpdate.fromJson({
|
|
'highlight_count': 0,
|
|
'notification_count': 0,
|
|
'limited_timeline': false,
|
|
'membership': Membership.join,
|
|
});
|
|
final client = Client('testclient');
|
|
await database.storeRoomUpdate('!testroom', roomUpdate, null, client);
|
|
final rooms = await database.getRoomList(client);
|
|
expect(rooms.single.id, '!testroom');
|
|
});
|
|
test('getRoomList', () async {
|
|
final room =
|
|
await database.getSingleRoom(Client('testclient'), '!testroom');
|
|
expect(room?.id, '!testroom');
|
|
});
|
|
test('getRoomList', () async {
|
|
final list = await database.getRoomList(Client('testclient'));
|
|
expect(list.single.id, '!testroom');
|
|
});
|
|
test('setRoomPrevBatch', () async {
|
|
final client = Client('testclient');
|
|
await database.setRoomPrevBatch('1234', '!testroom', client);
|
|
final rooms = await database.getRoomList(client);
|
|
expect(rooms.single.prev_batch, '1234');
|
|
});
|
|
test('forgetRoom', () async {
|
|
await database.forgetRoom('!testroom');
|
|
final rooms = await database.getRoomList(Client('testclient'));
|
|
expect(rooms.isEmpty, true);
|
|
});
|
|
test('getClient', () async {
|
|
await database.getClient('name');
|
|
});
|
|
test('insertClient', () async {
|
|
final now = DateTime.now();
|
|
await database.insertClient(
|
|
'name',
|
|
'homeserverUrl',
|
|
'token',
|
|
now,
|
|
'refresh_token',
|
|
'userId',
|
|
'deviceId',
|
|
'deviceName',
|
|
'prevBatch',
|
|
'olmAccount',
|
|
);
|
|
|
|
final client = await database.getClient('name');
|
|
expect(client?['token'], 'token');
|
|
expect(
|
|
client?['token_expires_at'],
|
|
now.millisecondsSinceEpoch.toString(),
|
|
);
|
|
});
|
|
test('updateClient', () async {
|
|
await database.updateClient(
|
|
'homeserverUrl',
|
|
'token_different',
|
|
DateTime.now(),
|
|
'refresh_token',
|
|
'userId',
|
|
'deviceId',
|
|
'deviceName',
|
|
'prevBatch',
|
|
'olmAccount',
|
|
);
|
|
final client = await database.getClient('name');
|
|
expect(client?['token'], 'token_different');
|
|
});
|
|
test('updateClientKeys', () async {
|
|
await database.updateClientKeys(
|
|
'olmAccount2',
|
|
);
|
|
final client = await database.getClient('name');
|
|
expect(client?['olm_account'], 'olmAccount2');
|
|
});
|
|
test('storeSyncFilterId', () async {
|
|
await database.storeSyncFilterId(
|
|
'1234',
|
|
);
|
|
final client = await database.getClient('name');
|
|
expect(client?['sync_filter_id'], '1234');
|
|
});
|
|
test('getAccountData', () async {
|
|
await database.getAccountData();
|
|
});
|
|
test('storeAccountData', () async {
|
|
await database.storeAccountData('m.test', {'foo': 'bar'});
|
|
final events = await database.getAccountData();
|
|
expect(events.values.single.type, 'm.test');
|
|
|
|
await database.storeAccountData('m.abc+de', {'foo': 'bar'});
|
|
final events2 = await database.getAccountData();
|
|
expect(
|
|
events2.values.any((element) => element.type == 'm.abc+de'),
|
|
true,
|
|
);
|
|
});
|
|
test('Database can write and read 5MB data', () async {
|
|
final hugeDataObject = {'foo': createLargeString('A', 5 * 1000 * 1000)};
|
|
|
|
await database.storeAccountData(
|
|
'm.huge_data_test',
|
|
hugeDataObject,
|
|
);
|
|
|
|
final events = await database.getAccountData();
|
|
|
|
expect(
|
|
events.values.any((data) => data.type == 'm.huge_data_test'),
|
|
true,
|
|
);
|
|
});
|
|
test('storeEventUpdate', () async {
|
|
await database.storeEventUpdate(
|
|
'!testroom:example.com',
|
|
MatrixEvent.fromJson(
|
|
{
|
|
'type': EventTypes.Message,
|
|
'content': {
|
|
'body': '* edit 3',
|
|
'msgtype': 'm.text',
|
|
'm.new_content': {
|
|
'body': 'edit 3',
|
|
'msgtype': 'm.text',
|
|
},
|
|
'm.relates_to': {
|
|
'event_id': '\$source',
|
|
'rel_type': RelationshipTypes.edit,
|
|
},
|
|
},
|
|
'origin_server_ts': DateTime.now().millisecondsSinceEpoch,
|
|
'event_id': '\$event:example.com',
|
|
'sender': '@bob:example.org',
|
|
},
|
|
),
|
|
EventUpdateType.timeline,
|
|
Client('testclient'),
|
|
);
|
|
});
|
|
test('storeEventUpdate (state)', () async {
|
|
final roomid = '!testrooma:example.com';
|
|
final client = Client('testclient');
|
|
|
|
await database.storeRoomUpdate(
|
|
roomid,
|
|
JoinedRoomUpdate(),
|
|
null,
|
|
client,
|
|
);
|
|
|
|
await database.storeRoomAccountData(
|
|
roomid,
|
|
BasicRoomEvent(
|
|
content: {'foo': 'bar'},
|
|
type: 'm.test',
|
|
roomId: roomid,
|
|
),
|
|
);
|
|
|
|
await database.storeEventUpdate(
|
|
roomid,
|
|
MatrixEvent.fromJson(
|
|
{
|
|
'type': EventTypes.RoomName,
|
|
'content': {
|
|
'name': 'start',
|
|
},
|
|
'event_id': '\$eventstart:example.com',
|
|
'sender': '@bob:example.org',
|
|
'state_key': '',
|
|
'origin_server_ts': DateTime.now().millisecondsSinceEpoch,
|
|
},
|
|
),
|
|
EventUpdateType.timeline,
|
|
client,
|
|
);
|
|
|
|
var room = await database.getSingleRoom(client, roomid);
|
|
|
|
expect(room, isNotNull);
|
|
|
|
expect(room?.name, 'start');
|
|
|
|
expect(room?.roomAccountData['m.test']?.content, {'foo': 'bar'});
|
|
|
|
await database.storeEventUpdate(
|
|
roomid,
|
|
MatrixEvent.fromJson(
|
|
{
|
|
'type': EventTypes.RoomName,
|
|
'content': {
|
|
'name': 'update',
|
|
},
|
|
'event_id': '\$eventupdate:example.com',
|
|
'sender': '@bob:example.org',
|
|
'state_key': '',
|
|
'origin_server_ts': DateTime.now().millisecondsSinceEpoch,
|
|
},
|
|
),
|
|
EventUpdateType.timeline,
|
|
client,
|
|
);
|
|
|
|
room = await database.getSingleRoom(client, roomid);
|
|
|
|
expect(room?.name, 'update');
|
|
|
|
await database.storeEventUpdate(
|
|
roomid,
|
|
MatrixEvent.fromJson(
|
|
{
|
|
'type': EventTypes.RoomName,
|
|
'content': {
|
|
'name': 'update2',
|
|
},
|
|
'event_id': '\$eventupdate2:example.com',
|
|
'sender': '@bob:example.org',
|
|
'state_key': '',
|
|
'origin_server_ts': DateTime.now().millisecondsSinceEpoch,
|
|
},
|
|
),
|
|
EventUpdateType.state,
|
|
client,
|
|
);
|
|
|
|
room = await database.getSingleRoom(client, roomid);
|
|
|
|
expect(room?.name, 'update2');
|
|
|
|
await database.storeEventUpdate(
|
|
roomid,
|
|
StrippedStateEvent.fromJson(
|
|
{
|
|
'type': EventTypes.RoomName,
|
|
'content': {
|
|
'name': 'update3',
|
|
},
|
|
'event_id': '\$eventupdate3:example.com',
|
|
'sender': '@bob:example.org',
|
|
'state_key': '',
|
|
},
|
|
),
|
|
EventUpdateType.inviteState,
|
|
client,
|
|
);
|
|
|
|
room = await database.getSingleRoom(client, roomid);
|
|
|
|
expect(room?.name, 'update3');
|
|
|
|
await database.storeEventUpdate(
|
|
roomid,
|
|
MatrixEvent.fromJson(
|
|
{
|
|
'type': EventTypes.RoomName,
|
|
'content': {
|
|
'name': 'notupdate',
|
|
},
|
|
'event_id': '\$eventnotupdate:example.com',
|
|
'sender': '@bob:example.org',
|
|
'state_key': '',
|
|
'origin_server_ts': DateTime.now().millisecondsSinceEpoch,
|
|
},
|
|
),
|
|
EventUpdateType.history,
|
|
client,
|
|
);
|
|
|
|
room = await database.getSingleRoom(client, roomid);
|
|
|
|
expect(room?.name, 'update3');
|
|
});
|
|
test('getEventById', () async {
|
|
final event = await database.getEventById(
|
|
'\$event:example.com',
|
|
Room(id: '!testroom:example.com', client: Client('testclient')),
|
|
);
|
|
expect(event?.type, EventTypes.Message);
|
|
});
|
|
test('getEventList', () async {
|
|
final events = await database.getEventList(
|
|
Room(id: '!testroom:example.com', client: Client('testclient')),
|
|
);
|
|
expect(events.single.type, EventTypes.Message);
|
|
});
|
|
test('getUser', () async {
|
|
final user = await database.getUser(
|
|
'@bob:example.org',
|
|
Room(id: '!testroom:example.com', client: Client('testclient')),
|
|
);
|
|
expect(user, null);
|
|
});
|
|
test('getUsers', () async {
|
|
final users = await database.getUsers(
|
|
Room(id: '!testroom:example.com', client: Client('testclient')),
|
|
);
|
|
expect(users.isEmpty, true);
|
|
});
|
|
test('removeEvent', () async {
|
|
await database.removeEvent(
|
|
'\$event:example.com',
|
|
'!testroom:example.com',
|
|
);
|
|
final event = await database.getEventById(
|
|
'\$event:example.com',
|
|
Room(id: '!testroom:example.com', client: Client('testclient')),
|
|
);
|
|
expect(event, null);
|
|
});
|
|
test('getAllInboundGroupSessions', () async {
|
|
final result = await database.getAllInboundGroupSessions();
|
|
expect(result.isEmpty, true);
|
|
});
|
|
test('getInboundGroupSession', () async {
|
|
await database.getInboundGroupSession(
|
|
'!testroom:example.com',
|
|
'sessionId',
|
|
);
|
|
});
|
|
test('getInboundGroupSessionsToUpload', () async {
|
|
await database.getInboundGroupSessionsToUpload();
|
|
});
|
|
test('storeInboundGroupSession', () async {
|
|
await database.storeInboundGroupSession(
|
|
'!testroom:example.com',
|
|
'sessionId',
|
|
'pickle',
|
|
'{"foo":"bar"}',
|
|
'{}',
|
|
'{}',
|
|
'senderKey',
|
|
'{}',
|
|
);
|
|
final session = await database.getInboundGroupSession(
|
|
'!testroom:example.com',
|
|
'sessionId',
|
|
);
|
|
expect(jsonDecode(session!.content)['foo'], 'bar');
|
|
});
|
|
test('markInboundGroupSessionAsUploaded', () async {
|
|
await database.markInboundGroupSessionAsUploaded(
|
|
'!testroom:example.com',
|
|
'sessionId',
|
|
);
|
|
});
|
|
test('markInboundGroupSessionsAsNeedingUpload', () async {
|
|
await database.markInboundGroupSessionsAsNeedingUpload();
|
|
});
|
|
test('updateInboundGroupSessionAllowedAtIndex', () async {
|
|
await database.updateInboundGroupSessionAllowedAtIndex(
|
|
'{}',
|
|
'!testroom:example.com',
|
|
'sessionId',
|
|
);
|
|
});
|
|
test('updateInboundGroupSessionIndexes', () async {
|
|
await database.updateInboundGroupSessionIndexes(
|
|
'{}',
|
|
'!testroom:example.com',
|
|
'sessionId',
|
|
);
|
|
});
|
|
test('getSSSSCache', () async {
|
|
final cache = await database.getSSSSCache('type');
|
|
expect(cache, null);
|
|
});
|
|
test('storeSSSSCache', () async {
|
|
await database.storeSSSSCache('type', 'keyId', 'ciphertext', '{}');
|
|
final cache = (await database.getSSSSCache('type'))!;
|
|
expect(cache.type, 'type');
|
|
expect(cache.keyId, 'keyId');
|
|
expect(cache.ciphertext, 'ciphertext');
|
|
expect(cache.content, '{}');
|
|
});
|
|
test('getOlmSessions', () async {
|
|
final olm = await database.getOlmSessions(
|
|
'identityKey',
|
|
'userId',
|
|
);
|
|
expect(olm.isEmpty, true);
|
|
});
|
|
test('getAllOlmSessions', () async {
|
|
var sessions = await database.getAllOlmSessions();
|
|
expect(sessions.isEmpty, true);
|
|
await database.storeOlmSession(
|
|
'identityKey',
|
|
'sessionId',
|
|
'pickle',
|
|
0,
|
|
);
|
|
await database.storeOlmSession(
|
|
'identityKey',
|
|
'sessionId2',
|
|
'pickle',
|
|
0,
|
|
);
|
|
sessions = await database.getAllOlmSessions();
|
|
expect(
|
|
sessions,
|
|
{
|
|
'identityKey': {
|
|
'sessionId': {
|
|
'identity_key': 'identityKey',
|
|
'pickle': 'pickle',
|
|
'session_id': 'sessionId',
|
|
'last_received': 0,
|
|
},
|
|
'sessionId2': {
|
|
'identity_key': 'identityKey',
|
|
'pickle': 'pickle',
|
|
'session_id': 'sessionId2',
|
|
'last_received': 0,
|
|
},
|
|
},
|
|
},
|
|
);
|
|
});
|
|
test('getOlmSessionsForDevices', () async {
|
|
final olm = await database.getOlmSessionsForDevices(
|
|
['identityKeys'],
|
|
'userId',
|
|
);
|
|
expect(olm.isEmpty, true);
|
|
});
|
|
test('storeOlmSession', () async {
|
|
await database.storeOlmSession(
|
|
'identityKey',
|
|
'sessionId',
|
|
'pickle',
|
|
0,
|
|
);
|
|
final olm = await database.getOlmSessions(
|
|
'identityKey',
|
|
'userId',
|
|
);
|
|
expect(olm.isNotEmpty, true);
|
|
});
|
|
test('getOutboundGroupSession', () async {
|
|
final session = await database.getOutboundGroupSession(
|
|
'!testroom:example.com',
|
|
'@alice:example.com',
|
|
);
|
|
expect(session, null);
|
|
});
|
|
test('storeOutboundGroupSession', () async {
|
|
await database.storeOutboundGroupSession(
|
|
'!testroom:example.com',
|
|
'pickle',
|
|
'{}',
|
|
0,
|
|
);
|
|
final session = await database.getOutboundGroupSession(
|
|
'!testroom:example.com',
|
|
'@alice:example.com',
|
|
);
|
|
expect(session?.devices.isEmpty, true);
|
|
});
|
|
test('getLastSentMessageUserDeviceKey', () async {
|
|
final list = await database.getLastSentMessageUserDeviceKey(
|
|
'userId',
|
|
'deviceId',
|
|
);
|
|
expect(list.isEmpty, true);
|
|
});
|
|
test('getUnimportantRoomEventStatesForRoom', () async {
|
|
final events = await database.getUnimportantRoomEventStatesForRoom(
|
|
['events'],
|
|
Room(id: '!mep', client: Client('testclient')),
|
|
);
|
|
expect(events.isEmpty, true);
|
|
});
|
|
test('getUserDeviceKeys', () async {
|
|
await database.getUserDeviceKeys(Client('testclient'));
|
|
});
|
|
test('storeUserCrossSigningKey', () async {
|
|
await database.storeUserCrossSigningKey(
|
|
'@alice:example.com',
|
|
'publicKey',
|
|
'{}',
|
|
false,
|
|
false,
|
|
);
|
|
});
|
|
test('setVerifiedUserCrossSigningKey', () async {
|
|
await database.setVerifiedUserCrossSigningKey(
|
|
true,
|
|
'@alice:example.com',
|
|
'publicKey',
|
|
);
|
|
});
|
|
test('setBlockedUserCrossSigningKey', () async {
|
|
await database.setBlockedUserCrossSigningKey(
|
|
true,
|
|
'@alice:example.com',
|
|
'publicKey',
|
|
);
|
|
});
|
|
test('removeUserCrossSigningKey', () async {
|
|
await database.removeUserCrossSigningKey(
|
|
'@alice:example.com',
|
|
'publicKey',
|
|
);
|
|
});
|
|
test('storeUserDeviceKeysInfo', () async {
|
|
await database.storeUserDeviceKeysInfo(
|
|
'@alice:example.com',
|
|
true,
|
|
);
|
|
});
|
|
test('storeUserDeviceKey', () async {
|
|
await database.storeUserDeviceKey(
|
|
'@alice:example.com',
|
|
'deviceId',
|
|
'{}',
|
|
false,
|
|
false,
|
|
0,
|
|
);
|
|
});
|
|
test('setVerifiedUserDeviceKey', () async {
|
|
await database.setVerifiedUserDeviceKey(
|
|
true,
|
|
'@alice:example.com',
|
|
'deviceId',
|
|
);
|
|
});
|
|
test('setBlockedUserDeviceKey', () async {
|
|
await database.setBlockedUserDeviceKey(
|
|
true,
|
|
'@alice:example.com',
|
|
'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(),
|
|
);
|
|
});
|
|
test(
|
|
'storeUserProfile',
|
|
() async {
|
|
final profile1 = await database.getUserProfile('@alice:example.com');
|
|
expect(profile1, null);
|
|
|
|
await database.storeUserProfile(
|
|
'@alice:example.com',
|
|
CachedProfileInformation.fromProfile(
|
|
ProfileInformation(
|
|
avatarUrl: Uri.parse('mxc://test'),
|
|
displayname: 'Alice M',
|
|
),
|
|
outdated: false,
|
|
updated: DateTime.now(),
|
|
),
|
|
);
|
|
// ignore: deprecated_member_use_from_same_package
|
|
if (database is! HiveCollectionsDatabase) {
|
|
final profile2 =
|
|
await database.getUserProfile('@alice:example.com');
|
|
expect(profile2?.displayname, 'Alice M');
|
|
expect(profile2?.outdated, false);
|
|
await database.markUserProfileAsOutdated('@alice:example.com');
|
|
|
|
final profile3 =
|
|
await database.getUserProfile('@alice:example.com');
|
|
expect(profile3?.displayname, 'Alice M');
|
|
expect(profile3?.outdated, true);
|
|
}
|
|
},
|
|
);
|
|
|
|
// Clearing up from here
|
|
test('clearSSSSCache', () async {
|
|
await database.clearSSSSCache();
|
|
});
|
|
test('clearCache', () async {
|
|
await database.clearCache();
|
|
});
|
|
test('clear', () async {
|
|
await database.clear();
|
|
});
|
|
test('Close', () async {
|
|
await database.close();
|
|
});
|
|
test('Delete', () async {
|
|
final database = await getMatrixSdkDatabase(null);
|
|
await database.storeAccountData(
|
|
'm.test.data',
|
|
{'foo': 'bar'},
|
|
);
|
|
await database.delete();
|
|
|
|
// Check if previously stored data is gone:
|
|
final reopenedDatabase = await getMatrixSdkDatabase(null);
|
|
final dump = await reopenedDatabase.getAccountData();
|
|
expect(dump.isEmpty, true);
|
|
});
|
|
});
|
|
}
|
|
}
|