From 083ca282837e495054790bf058f356562e373337 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Mon, 15 Mar 2021 16:48:56 +0530 Subject: [PATCH] test(persistence): Add test for channel query dao Signed-off-by: Sahil Kumar --- packages/stream_chat/lib/src/client.dart | 3 +- .../lib/src/db/chat_persistence_client.dart | 7 +- .../lib/src/dao/channel_query_dao.dart | 17 +- .../test/src/dao/channel_query_dao_test.dart | 270 ++++++++++++++++++ 4 files changed, 285 insertions(+), 12 deletions(-) create mode 100644 packages/stream_chat_persistence/test/src/dao/channel_query_dao_test.dart diff --git a/packages/stream_chat/lib/src/client.dart b/packages/stream_chat/lib/src/client.dart index 11619b35..8b9d3a75 100644 --- a/packages/stream_chat/lib/src/client.dart +++ b/packages/stream_chat/lib/src/client.dart @@ -738,7 +738,8 @@ class StreamChatClient { await _chatPersistenceClient?.updateChannelQueries( filter, channels.map((c) => c.channel.cid).toList(), - paginationParams?.offset == null || paginationParams.offset == 0, + clearQueryCache: + paginationParams?.offset == null || paginationParams.offset == 0, ); state.channels = updateData.key; diff --git a/packages/stream_chat/lib/src/db/chat_persistence_client.dart b/packages/stream_chat/lib/src/db/chat_persistence_client.dart index d90872a2..d15772df 100644 --- a/packages/stream_chat/lib/src/db/chat_persistence_client.dart +++ b/packages/stream_chat/lib/src/db/chat_persistence_client.dart @@ -100,10 +100,9 @@ abstract class ChatPersistenceClient { /// the list of matching rows will be deleted Future updateChannelQueries( Map filter, - List cids, - // ignore: avoid_positional_boolean_parameters - bool clearQueryCache, - ); + List cids, { + bool clearQueryCache = false, + }); /// Remove a message by [messageId] Future deleteMessageById(String messageId) => diff --git a/packages/stream_chat_persistence/lib/src/dao/channel_query_dao.dart b/packages/stream_chat_persistence/lib/src/dao/channel_query_dao.dart index 785b5946..233fd4ef 100644 --- a/packages/stream_chat_persistence/lib/src/dao/channel_query_dao.dart +++ b/packages/stream_chat_persistence/lib/src/dao/channel_query_dao.dart @@ -32,7 +32,7 @@ class ChannelQueryDao extends DatabaseAccessor Future updateChannelQueries( Map filter, List cids, { - bool clearQueryCache, + bool clearQueryCache = false, }) async => transaction(() async { final hash = _computeHash(filter); @@ -57,6 +57,14 @@ class ChannelQueryDao extends DatabaseAccessor }); }); + /// + Future> getCachedChannelCids(Map filter) { + final hash = _computeHash(filter); + return (select(channelQueries)..where((c) => c.queryHash.equals(hash))) + .map((c) => c.channelCid) + .get(); + } + /// Get list of channels by filter, sort and paginationParams Future> getChannels({ Map filter, @@ -72,12 +80,7 @@ class ChannelQueryDao extends DatabaseAccessor return true; }(), ''); - final hash = _computeHash(filter); - final cachedChannelCids = await (select(channelQueries) - ..where((c) => c.queryHash.equals(hash))) - .map((c) => c.channelCid) - .get(); - + final cachedChannelCids = await getCachedChannelCids(filter); final query = select(channels)..where((c) => c.cid.isIn(cachedChannelCids)); final cachedChannels = await (query.join([ diff --git a/packages/stream_chat_persistence/test/src/dao/channel_query_dao_test.dart b/packages/stream_chat_persistence/test/src/dao/channel_query_dao_test.dart new file mode 100644 index 00000000..1a437dfc --- /dev/null +++ b/packages/stream_chat_persistence/test/src/dao/channel_query_dao_test.dart @@ -0,0 +1,270 @@ +import 'dart:math' as math; + +import 'package:stream_chat/stream_chat.dart'; +import 'package:stream_chat_persistence/src/dao/channel_query_dao.dart'; +import 'package:stream_chat_persistence/src/db/moor_chat_database.dart'; +import 'package:test/test.dart'; + +void main() { + MoorChatDatabase database; + ChannelQueryDao channelQueryDao; + + setUp(() { + database = MoorChatDatabase.testable('testUserId'); + channelQueryDao = database.channelQueryDao; + }); + + test('updateChannelQueries', () async { + const filter = { + 'members': { + r'$in': ['testUserId'], + }, + }; + + const cids = ['testCid1', 'testCid2', 'testCid3']; + + final cachedCids = await channelQueryDao.getCachedChannelCids(filter); + expect(cachedCids, []); + + // Updating channel queries + await channelQueryDao.updateChannelQueries(filter, cids); + + final updatedCids = await channelQueryDao.getCachedChannelCids(filter); + expect(updatedCids, cids); + }); + + test('getCachedChannelCids', () async { + const filter = { + 'members': { + r'$in': ['testUserId'], + }, + }; + + const cids = ['testCid1', 'testCid2', 'testCid3']; + + final cachedCids = await channelQueryDao.getCachedChannelCids(filter); + expect(cachedCids, []); + + // Updating channel queries + await channelQueryDao.updateChannelQueries(filter, cids); + + final updatedCids = await channelQueryDao.getCachedChannelCids(filter); + expect(updatedCids, cids); + }); + + Future> _insertTestDataForGetChannel( + Map filter) async { + final now = DateTime.now(); + final userDao = database.userDao; + final channelDao = database.channelDao; + + const cids = ['testCid0', 'testCid1', 'testCid2']; + final users = List.generate(3, (index) => User(id: 'testId$index')); + final channels = List.generate( + 3, + (index) => ChannelModel( + id: 'testId$index', + type: 'testType$index', + cid: cids[index], + createdBy: users[index], + config: ChannelConfig(), + extraData: {'test_custom_field': math.Random().nextInt(100)}, + createdAt: now, + memberCount: math.Random().nextInt(100), + lastMessageAt: now.add(Duration(hours: index)), + ), + ).reversed.toList(growable: false); + + await userDao.updateUsers(users); + await channelDao.updateChannels(channels); + await channelQueryDao.updateChannelQueries(filter, cids); + + return channels; + } + + group('getChannels', () { + const filter = { + 'members': { + r'$in': ['testUserId'], + }, + }; + + test('should return empty list of channels', () async { + final channels = await channelQueryDao.getChannels(filter: filter); + expect(channels, []); + }); + + test('should return all the inserted channels', () async { + // Inserting test data for get channels + final insertedChannels = await _insertTestDataForGetChannel(filter); + + // Should match with the inserted channels + final updatedChannels = await channelQueryDao.getChannels(filter: filter); + expect(updatedChannels.length, insertedChannels.length); + for (var i = 0; i < updatedChannels.length; i++) { + final updatedChannel = updatedChannels[i]; + final insertedChannel = insertedChannels[i]; + + // Should match all the basic details + expect(updatedChannel.id, insertedChannel.id); + expect(updatedChannel.type, insertedChannel.type); + expect(updatedChannel.cid, insertedChannel.cid); + expect(updatedChannel.memberCount, insertedChannel.memberCount); + + // Should match createdAt date + expect( + updatedChannel.createdAt.hour, + insertedChannel.createdAt.hour, + ); + expect( + updatedChannel.createdAt.minute, + insertedChannel.createdAt.minute, + ); + expect( + updatedChannel.createdAt.second, + insertedChannel.createdAt.second, + ); + + // Should match lastMessageAt date + expect( + updatedChannel.lastMessageAt.hour, + insertedChannel.lastMessageAt.hour, + ); + expect( + updatedChannel.lastMessageAt.minute, + insertedChannel.lastMessageAt.minute, + ); + expect( + updatedChannel.lastMessageAt.second, + insertedChannel.lastMessageAt.second, + ); + } + }); + + test('should return sorted channels using member count', () async { + int sortComparator(ChannelModel a, ChannelModel b) => + b.memberCount.compareTo(a.memberCount); + + // Inserting test data for get channels + final insertedChannels = await _insertTestDataForGetChannel(filter); + insertedChannels.sort(sortComparator); + + // Should match with the inserted channels + final updatedChannels = await channelQueryDao.getChannels( + filter: filter, + sort: [SortOption('member_count', comparator: sortComparator)], + ); + + expect(updatedChannels.length, insertedChannels.length); + for (var i = 0; i < updatedChannels.length; i++) { + final updatedChannel = updatedChannels[i]; + final insertedChannel = insertedChannels[i]; + + // Should match all the basic details + expect(updatedChannel.id, insertedChannel.id); + expect(updatedChannel.type, insertedChannel.type); + expect(updatedChannel.cid, insertedChannel.cid); + expect(updatedChannel.memberCount, insertedChannel.memberCount); + + // Should match createdAt date + expect( + updatedChannel.createdAt.hour, + insertedChannel.createdAt.hour, + ); + expect( + updatedChannel.createdAt.minute, + insertedChannel.createdAt.minute, + ); + expect( + updatedChannel.createdAt.second, + insertedChannel.createdAt.second, + ); + + // Should match lastMessageAt date + expect( + updatedChannel.lastMessageAt.hour, + insertedChannel.lastMessageAt.hour, + ); + expect( + updatedChannel.lastMessageAt.minute, + insertedChannel.lastMessageAt.minute, + ); + expect( + updatedChannel.lastMessageAt.second, + insertedChannel.lastMessageAt.second, + ); + } + }); + + test('should throw if comparator is not provided in sort list', () { + expect( + () => channelQueryDao.getChannels( + sort: [const SortOption('test_custom_field')], + ), + throwsArgumentError, + ); + }); + + test('should return sorted channels using custom field', () async { + int sortComparator(ChannelModel a, ChannelModel b) { + final aData = a.extraData['test_custom_field'] as int; + final bData = b.extraData['test_custom_field'] as int; + return bData.compareTo(aData); + } + + // Inserting test data for get channels + final insertedChannels = await _insertTestDataForGetChannel(filter); + insertedChannels.sort(sortComparator); + + // Should match with the inserted channels + final updatedChannels = await channelQueryDao.getChannels( + filter: filter, + sort: [SortOption('test_custom_field', comparator: sortComparator)], + ); + + expect(updatedChannels.length, insertedChannels.length); + for (var i = 0; i < updatedChannels.length; i++) { + final updatedChannel = updatedChannels[i]; + final insertedChannel = insertedChannels[i]; + + // Should match all the basic details + expect(updatedChannel.id, insertedChannel.id); + expect(updatedChannel.type, insertedChannel.type); + expect(updatedChannel.cid, insertedChannel.cid); + expect(updatedChannel.memberCount, insertedChannel.memberCount); + + // Should match createdAt date + expect( + updatedChannel.createdAt.hour, + insertedChannel.createdAt.hour, + ); + expect( + updatedChannel.createdAt.minute, + insertedChannel.createdAt.minute, + ); + expect( + updatedChannel.createdAt.second, + insertedChannel.createdAt.second, + ); + + // Should match lastMessageAt date + expect( + updatedChannel.lastMessageAt.hour, + insertedChannel.lastMessageAt.hour, + ); + expect( + updatedChannel.lastMessageAt.minute, + insertedChannel.lastMessageAt.minute, + ); + expect( + updatedChannel.lastMessageAt.second, + insertedChannel.lastMessageAt.second, + ); + } + }); + }); + + tearDown(() async { + await database.disconnect(); + }); +}