feat: codecov (#327)

* [llc] add codecov in gh action

* update flag

* update path

* fix codevcov script

* fix codevcov script

* [persistence]: add basic test

* [persistence] add codecov

* [persistence] vgv action

* update threashold

* fix ci

* add coverage for ui packages

* fix ci

* test gh action

* test gh action

* update threashold

* fix(persistence): fix tests

Signed-off-by: Sahil Kumar <[email protected]>

Co-authored-by: Sahil Kumar <[email protected]>
This commit is contained in:
Salvatore Giordano
2021-03-11 16:36:22 +01:00
committed by GitHub
co-authored by Sahil Kumar
parent 4b6f1f54b6
commit 39c2106497
9 changed files with 120 additions and 84 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
#!/bin/bash #!/bin/bash
flutter pub global activate melos 0.4.0+1 flutter pub global activate melos
echo "::add-path::$HOME/.pub-cache/bin" echo "::add-path::$HOME/.pub-cache/bin"
echo "::add-path::$GITHUB_WORKSPACE/_flutter/.pub-cache/bin" echo "::add-path::$GITHUB_WORKSPACE/_flutter/.pub-cache/bin"
echo "::add-path::$GITHUB_WORKSPACE/_flutter/bin/cache/dart-sdk/bin" echo "::add-path::$GITHUB_WORKSPACE/_flutter/bin/cache/dart-sdk/bin"
+28 -32
View File
@@ -48,7 +48,6 @@ jobs:
- name: 'Install Tools' - name: 'Install Tools'
run: | run: |
./.github/workflows/scripts/install-tools.sh ./.github/workflows/scripts/install-tools.sh
curl -sL https://github.com/google/google-java-format/releases/download/google-java-format-1.3/google-java-format-1.3-all-deps.jar -o $HOME/google-java-format.jar
- name: 'Bootstrap Workspace' - name: 'Bootstrap Workspace'
run: melos bootstrap run: melos bootstrap
- name: 'Dart' - name: 'Dart'
@@ -56,20 +55,8 @@ jobs:
melos exec -c 1 -- \ melos exec -c 1 -- \
flutter format . flutter format .
./.github/workflows/scripts/validate-formatting.sh ./.github/workflows/scripts/validate-formatting.sh
- name: 'Objective-C'
if: ${{ success() || failure() }}
run: |
melos exec -c 4 --ignore="*platform_interface*" --ignore="*web*" -- \
find . -maxdepth 3 -name "*.h" -o -name "*.m" -print0 \| xargs -0 clang-format -i --style=Google --verbose
./.github/workflows/scripts/validate-formatting.sh
- name: 'Java'
if: ${{ success() || failure() }}
run: |
melos exec -c 4 --ignore="*platform_interface*" --ignore="*web*" -- \
find . -maxdepth 12 -name "*.java" -print0 \| xargs -0 java -jar $HOME/google-java-format.jar --replace
./.github/workflows/scripts/validate-formatting.sh
test_dart: test:
runs-on: ubuntu-latest runs-on: ubuntu-latest
timeout-minutes: 5 timeout-minutes: 5
steps: steps:
@@ -79,26 +66,35 @@ jobs:
- name: 'Install Flutter' - name: 'Install Flutter'
run: ./.github/workflows/scripts/install-flutter.sh stable run: ./.github/workflows/scripts/install-flutter.sh stable
- name: 'Install Tools' - name: 'Install Tools'
run: ./.github/workflows/scripts/install-tools.sh run: |
- name: 'Bootstrap Workspace' ./.github/workflows/scripts/install-tools.sh
run: melos bootstrap flutter pub global activate coverage
- name: 'Flutter Test'
run: cd packages/stream_chat && flutter pub run test
test_flutter:
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@v2
with:
fetch-depth: 0
- name: 'Install Flutter'
run: ./.github/workflows/scripts/install-flutter.sh stable
- name: 'Install Tools'
run: ./.github/workflows/scripts/install-tools.sh
- name: 'Bootstrap Workspace' - name: 'Bootstrap Workspace'
run: melos bootstrap run: melos bootstrap
- name: 'Dart Test'
run: |
cd packages/stream_chat
flutter pub run test --coverage coverage/
format_coverage --lcov --in=coverage/ --out=lcov.info --packages=.packages --report-on=lib
- name: 'Flutter Test' - name: 'Flutter Test'
run: | run: |
melos exec -c 3 --flutter --dir-exists=test --ignore="*example*" --ignore="*web*" -- \ melos exec -c 3 --flutter --dir-exists=test --ignore="*example*" --ignore="*web*" -- \
flutter test flutter test --coverage
- name: CodeCov
run: bash <(curl -s https://codecov.io/bash) -t ${{ secrets.CODECOV_TOKEN }}
- uses: VeryGoodOpenSource/[email protected]
with:
path: packages/stream_chat/lcov.info
min_coverage: 50
- uses: VeryGoodOpenSource/[email protected]
with:
path: packages/stream_chat_persistence/coverage/lcov.info
min_coverage: 0.2
- uses: VeryGoodOpenSource/[email protected]
with:
path: packages/stream_chat_flutter_core/coverage/lcov.info
min_coverage: 4.5
- uses: VeryGoodOpenSource/[email protected]
with:
path: packages/stream_chat_flutter/coverage/lcov.info
min_coverage: 16
+2 -1
View File
@@ -2,7 +2,8 @@
.atom/ .atom/
.idea/ .idea/
.vscode/ .vscode/
**/lcov.info
coverage
.packages .packages
.pub/ .pub/
.dart_tool/ .dart_tool/
@@ -2,21 +2,23 @@ import 'package:moor/isolate.dart';
import 'package:moor/moor.dart'; import 'package:moor/moor.dart';
import 'package:stream_chat/stream_chat.dart'; import 'package:stream_chat/stream_chat.dart';
import '../entity/entity.dart';
import '../dao/dao.dart';
import '../converter/converter.dart'; import '../converter/converter.dart';
import '../dao/dao.dart';
import '../entity/entity.dart';
import 'shared/shared_db.dart'; import 'shared/shared_db.dart';
part 'moor_chat_database.g.dart'; part 'moor_chat_database.g.dart';
LazyDatabase _openConnection( LazyDatabase _openConnection(
String userId, { String userId, {
logStatements = false, bool logStatements = false,
bool persistOnDisk = true,
}) { }) {
return LazyDatabase(() async { return LazyDatabase(() async {
return await SharedDB.constructDatabase( return await SharedDB.constructDatabase(
userId, userId,
logStatements: logStatements, logStatements: logStatements,
persistOnDisk: persistOnDisk,
); );
}); });
} }
@@ -48,9 +50,11 @@ class MoorChatDatabase extends _$MoorChatDatabase {
MoorChatDatabase( MoorChatDatabase(
this._userId, { this._userId, {
logStatements = false, logStatements = false,
bool persistOnDisk = true,
}) : super(_openConnection( }) : super(_openConnection(
_userId, _userId,
logStatements: logStatements, logStatements: logStatements,
persistOnDisk: persistOnDisk,
)); ));
/// Instantiate a new database instance /// Instantiate a new database instance
@@ -1,5 +1,6 @@
import 'dart:io'; import 'dart:io';
import 'dart:isolate'; import 'dart:isolate';
import 'package:moor/ffi.dart'; import 'package:moor/ffi.dart';
import 'package:moor/isolate.dart'; import 'package:moor/isolate.dart';
import 'package:moor/moor.dart'; import 'package:moor/moor.dart';
@@ -20,17 +21,20 @@ class SharedDB {
static Future<VmDatabase> constructDatabase( static Future<VmDatabase> constructDatabase(
String userId, { String userId, {
bool logStatements = false, bool logStatements = false,
bool persistOnDisk = true,
}) async { }) async {
final dbName = 'db_$userId'; final dbName = 'db_$userId';
if (Platform.isIOS || Platform.isAndroid) { if (persistOnDisk) {
final dir = await getApplicationDocumentsDirectory(); if (Platform.isIOS || Platform.isAndroid) {
final path = join(dir.path, '$dbName.sqlite'); final dir = await getApplicationDocumentsDirectory();
final file = File(path); final path = join(dir.path, '$dbName.sqlite');
return VmDatabase(file, logStatements: logStatements); final file = File(path);
} return VmDatabase(file, logStatements: logStatements);
if (Platform.isMacOS || Platform.isLinux) { }
final file = File('$dbName.sqlite'); if (Platform.isMacOS || Platform.isLinux) {
return VmDatabase(file, logStatements: logStatements); final file = File('$dbName.sqlite');
return VmDatabase(file, logStatements: logStatements);
}
} }
return VmDatabase.memory(logStatements: logStatements); return VmDatabase.memory(logStatements: logStatements);
} }
@@ -8,6 +8,7 @@ class SharedDB {
static dynamic constructDatabase( static dynamic constructDatabase(
String userId, { String userId, {
bool logStatements = false, bool logStatements = false,
bool persistOnDisk = true,
}) { }) {
throw 'Unsupported Platform'; throw 'Unsupported Platform';
} }
@@ -12,6 +12,7 @@ class SharedDB {
static Future<WebDatabase> constructDatabase( static Future<WebDatabase> constructDatabase(
String userId, { String userId, {
bool logStatements = false, bool logStatements = false,
bool persistOnDisk = true, // ignored on web
}) async { }) async {
final dbName = 'db_$userId'; final dbName = 'db_$userId';
return WebDatabase(dbName, logStatements: logStatements); return WebDatabase(dbName, logStatements: logStatements);
@@ -1,3 +1,4 @@
import 'package:meta/meta.dart';
import 'package:stream_chat/stream_chat.dart'; import 'package:stream_chat/stream_chat.dart';
import 'db/moor_chat_database.dart'; import 'db/moor_chat_database.dart';
@@ -24,13 +25,14 @@ class StreamChatPersistenceClient extends ChatPersistenceClient {
_connectionMode = connectionMode, _connectionMode = connectionMode,
_logger = Logger.detached('💽')..level = logLevel; _logger = Logger.detached('💽')..level = logLevel;
MoorChatDatabase _db; @visibleForTesting
MoorChatDatabase db;
final Logger _logger; final Logger _logger;
final ConnectionMode _connectionMode; final ConnectionMode _connectionMode;
@override @override
Future<void> connect(String userId) async { Future<void> connect(String userId) async {
if (_db != null) { if (db != null) {
throw Exception( throw Exception(
'An instance of StreamChatDatabase is already connected.\n' 'An instance of StreamChatDatabase is already connected.\n'
'disconnect the previous instance before connecting again.', 'disconnect the previous instance before connecting again.',
@@ -39,71 +41,71 @@ class StreamChatPersistenceClient extends ChatPersistenceClient {
switch (_connectionMode) { switch (_connectionMode) {
case ConnectionMode.regular: case ConnectionMode.regular:
_logger.info('Connecting on a regular isolate'); _logger.info('Connecting on a regular isolate');
_db = MoorChatDatabase(userId); db = MoorChatDatabase(userId);
return; return;
case ConnectionMode.background: case ConnectionMode.background:
_logger.info('Connecting on background isolate'); _logger.info('Connecting on background isolate');
_db = await SharedDB.constructMoorChatDatabase(userId); db = await SharedDB.constructMoorChatDatabase(userId);
return; return;
} }
} }
@override @override
Future<Event> getConnectionInfo() { Future<Event> getConnectionInfo() {
return _db.connectionEventDao.connectionEvent; return db.connectionEventDao.connectionEvent;
} }
@override @override
Future<void> updateConnectionInfo(Event event) { Future<void> updateConnectionInfo(Event event) {
return _db.connectionEventDao.updateConnectionEvent(event); return db.connectionEventDao.updateConnectionEvent(event);
} }
@override @override
Future<void> updateLastSyncAt(DateTime lastSyncAt) { Future<void> updateLastSyncAt(DateTime lastSyncAt) {
return _db.connectionEventDao.updateLastSyncAt(lastSyncAt); return db.connectionEventDao.updateLastSyncAt(lastSyncAt);
} }
@override @override
Future<DateTime> getLastSyncAt() { Future<DateTime> getLastSyncAt() {
return _db.connectionEventDao.lastSyncAt; return db.connectionEventDao.lastSyncAt;
} }
@override @override
Future<void> deleteChannels(List<String> cids) { Future<void> deleteChannels(List<String> cids) {
return _db.channelDao.deleteChannelByCids(cids); return db.channelDao.deleteChannelByCids(cids);
} }
@override @override
Future<List<String>> getChannelCids() => _db.channelDao.cids; Future<List<String>> getChannelCids() => db.channelDao.cids;
@override @override
Future<void> deleteMessageByIds(List<String> messageIds) { Future<void> deleteMessageByIds(List<String> messageIds) {
return _db.messageDao.deleteMessageByIds(messageIds); return db.messageDao.deleteMessageByIds(messageIds);
} }
@override @override
Future<void> deletePinnedMessageByIds(List<String> messageIds) { Future<void> deletePinnedMessageByIds(List<String> messageIds) {
return _db.pinnedMessageDao.deleteMessageByIds(messageIds); return db.pinnedMessageDao.deleteMessageByIds(messageIds);
} }
@override @override
Future<void> deleteMessageByCids(List<String> cids) { Future<void> deleteMessageByCids(List<String> cids) {
return _db.messageDao.deleteMessageByCids(cids); return db.messageDao.deleteMessageByCids(cids);
} }
@override @override
Future<void> deletePinnedMessageByCids(List<String> cids) { Future<void> deletePinnedMessageByCids(List<String> cids) {
return _db.pinnedMessageDao.deleteMessageByCids(cids); return db.pinnedMessageDao.deleteMessageByCids(cids);
} }
@override @override
Future<List<Member>> getMembersByCid(String cid) { Future<List<Member>> getMembersByCid(String cid) {
return _db.memberDao.getMembersByCid(cid); return db.memberDao.getMembersByCid(cid);
} }
@override @override
Future<ChannelModel> getChannelByCid(String cid) { Future<ChannelModel> getChannelByCid(String cid) {
return _db.channelDao.getChannelByCid(cid); return db.channelDao.getChannelByCid(cid);
} }
@override @override
@@ -111,7 +113,7 @@ class StreamChatPersistenceClient extends ChatPersistenceClient {
String cid, { String cid, {
PaginationParams messagePagination, PaginationParams messagePagination,
}) { }) {
return _db.messageDao.getMessagesByCid( return db.messageDao.getMessagesByCid(
cid, cid,
messagePagination: messagePagination, messagePagination: messagePagination,
); );
@@ -122,7 +124,7 @@ class StreamChatPersistenceClient extends ChatPersistenceClient {
String cid, { String cid, {
PaginationParams messagePagination, PaginationParams messagePagination,
}) { }) {
return _db.pinnedMessageDao.getMessagesByCid( return db.pinnedMessageDao.getMessagesByCid(
cid, cid,
messagePagination: messagePagination, messagePagination: messagePagination,
); );
@@ -130,12 +132,12 @@ class StreamChatPersistenceClient extends ChatPersistenceClient {
@override @override
Future<List<Read>> getReadsByCid(String cid) { Future<List<Read>> getReadsByCid(String cid) {
return _db.readDao.getReadsByCid(cid); return db.readDao.getReadsByCid(cid);
} }
@override @override
Future<Map<String, List<Message>>> getChannelThreads(String cid) async { Future<Map<String, List<Message>>> getChannelThreads(String cid) async {
final messages = await _db.messageDao.getThreadMessages(cid); final messages = await db.messageDao.getThreadMessages(cid);
final messageByParentIdDictionary = <String, List<Message>>{}; final messageByParentIdDictionary = <String, List<Message>>{};
for (final message in messages) { for (final message in messages) {
final parentId = message.parentId; final parentId = message.parentId;
@@ -152,7 +154,7 @@ class StreamChatPersistenceClient extends ChatPersistenceClient {
String parentId, { String parentId, {
PaginationParams options, PaginationParams options,
}) { }) {
return _db.messageDao.getThreadMessagesByParentId( return db.messageDao.getThreadMessagesByParentId(
parentId, parentId,
options: options, options: options,
); );
@@ -164,7 +166,7 @@ class StreamChatPersistenceClient extends ChatPersistenceClient {
List<SortOption<ChannelModel>> sort = const [], List<SortOption<ChannelModel>> sort = const [],
PaginationParams paginationParams, PaginationParams paginationParams,
}) async { }) async {
final channels = await _db.channelQueryDao.getChannels( final channels = await db.channelQueryDao.getChannels(
filter: filter, filter: filter,
sort: sort, sort: sort,
paginationParams: paginationParams, paginationParams: paginationParams,
@@ -178,7 +180,7 @@ class StreamChatPersistenceClient extends ChatPersistenceClient {
List<String> cids, List<String> cids,
bool clearQueryCache, bool clearQueryCache,
) { ) {
return _db.channelQueryDao.updateChannelQueries( return db.channelQueryDao.updateChannelQueries(
filter, filter,
cids, cids,
clearQueryCache, clearQueryCache,
@@ -187,63 +189,63 @@ class StreamChatPersistenceClient extends ChatPersistenceClient {
@override @override
Future<void> updateChannels(List<ChannelModel> channels) { Future<void> updateChannels(List<ChannelModel> channels) {
return _db.channelDao.updateChannels(channels); return db.channelDao.updateChannels(channels);
} }
@override @override
Future<void> updateMembers(String cid, List<Member> members) { Future<void> updateMembers(String cid, List<Member> members) {
return _db.memberDao.updateMembers(cid, members); return db.memberDao.updateMembers(cid, members);
} }
@override @override
Future<void> updateMessages(String cid, List<Message> messages) { Future<void> updateMessages(String cid, List<Message> messages) {
return _db.messageDao.updateMessages(cid, messages); return db.messageDao.updateMessages(cid, messages);
} }
@override @override
Future<void> updatePinnedMessages(String cid, List<Message> messages) { Future<void> updatePinnedMessages(String cid, List<Message> messages) {
return _db.pinnedMessageDao.updateMessages(cid, messages); return db.pinnedMessageDao.updateMessages(cid, messages);
} }
@override @override
Future<void> updateReactions(List<Reaction> reactions) { Future<void> updateReactions(List<Reaction> reactions) {
return _db.reactionDao.updateReactions(reactions); return db.reactionDao.updateReactions(reactions);
} }
@override @override
Future<void> updateReads(String cid, List<Read> reads) { Future<void> updateReads(String cid, List<Read> reads) {
return _db.readDao.updateReads(cid, reads); return db.readDao.updateReads(cid, reads);
} }
@override @override
Future<void> updateUsers(List<User> users) { Future<void> updateUsers(List<User> users) {
return _db.userDao.updateUsers(users); return db.userDao.updateUsers(users);
} }
@override @override
Future<void> deleteReactionsByMessageId(List<String> messageIds) { Future<void> deleteReactionsByMessageId(List<String> messageIds) {
return _db.reactionDao.deleteReactionsByMessageIds(messageIds); return db.reactionDao.deleteReactionsByMessageIds(messageIds);
} }
@override @override
Future<void> deleteMembersByCids(List<String> cids) { Future<void> deleteMembersByCids(List<String> cids) {
return _db.memberDao.deleteMemberByCids(cids); return db.memberDao.deleteMemberByCids(cids);
} }
@override @override
Future<void> disconnect({bool flush = false}) async { Future<void> disconnect({bool flush = false}) async {
if (_db != null) { if (db != null) {
_logger.info('Disconnecting'); _logger.info('Disconnecting');
if (flush) { if (flush) {
_logger.info('Flushing'); _logger.info('Flushing');
await _db.batch((batch) { await db.batch((batch) {
_db.allTables.forEach((table) { db.allTables.forEach((table) {
_db.delete(table).go(); db.delete(table).go();
}); });
}); });
} }
await _db.disconnect(); await db.disconnect();
_db = null; db = null;
} }
} }
} }
@@ -0,0 +1,27 @@
import 'package:stream_chat/stream_chat.dart';
import 'package:stream_chat_persistence/src/db/moor_chat_database.dart';
import 'package:stream_chat_persistence/src/stream_chat_persistence_client.dart';
import 'package:test/test.dart';
void main() {
group('connect', () {
test('throws exception because already connected', () {
final streamChatPersistenceClient = StreamChatPersistenceClient(
connectionMode: ConnectionMode.background,
logLevel: Level.INFO,
)..db = MoorChatDatabase(
'test',
persistOnDisk: false,
);
expect(
() => streamChatPersistenceClient.connect('test'),
throwsA(allOf(isException, predicate((e) {
return e.message ==
'An instance of StreamChatDatabase is already connected.\n'
'disconnect the previous instance before connecting again.';
}))),
);
});
});
}