/* * 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 . */ import 'dart:convert'; import 'dart:typed_data'; import 'dart:async'; import 'package:matrix/matrix.dart'; import 'package:test/test.dart'; import 'package:olm/olm.dart' as olm; import 'fake_database.dart'; void main() { group('FluffyBox Database Test', () { testDatabase( getFluffyBoxDatabase(null), ); }); group('Hive Database Test', () { testDatabase( getHiveDatabase(null), ); }); } Future olmEnabled() async { var olmEnabled = true; try { await olm.init(); olm.get_library_version(); } catch (e) { olmEnabled = false; } return olmEnabled; } void testDatabase( Future futureDatabase, ) { late DatabaseApi database; late int toDeviceQueueIndex; test('Open', () async { database = await futureDatabase; }); 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); }); // we can't use Zone.root.run inside of tests so we abuse timers instead Timer(Duration(milliseconds: 50), () async { await database.transaction(() async { expect(counter++, 6); }); }); await database.transaction(() async { expect(counter++, 4); await Future.delayed(Duration(milliseconds: 100)); expect(counter++, 5); }); }); 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', () 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); }); 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, client); final rooms = await database.getRoomList(client); expect(rooms.single.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 { await database.insertClient( 'name', 'homeserverUrl', 'token', 'userId', 'deviceId', 'deviceName', 'prevBatch', 'olmAccount', ); final client = await database.getClient('name'); expect(client?['token'], 'token'); }); test('updateClient', () async { await database.updateClient( 'homeserverUrl', 'token_different', '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('storeEventUpdate', () async { await database.storeEventUpdate( EventUpdate( roomID: '!testroom:example.com', type: EventUpdateType.timeline, content: { '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, }, }, 'event_id': '\$event:example.com', 'sender': '@bob:example.org', }, ), Client('testclient')); }); 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 { if (!(await olmEnabled())) return; 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 { if (!(await olmEnabled())) return; 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', ); }); // 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(); }); return; }