Files
sharedinbox/test/integration/account_sync_manager_test.dart
T

236 lines
6.0 KiB
Dart

import 'dart:async';
import 'package:flutter_test/flutter_test.dart';
import 'package:sharedinbox/core/models/account.dart';
import 'package:sharedinbox/core/models/email.dart';
import 'package:sharedinbox/core/models/mailbox.dart';
import 'package:sharedinbox/core/repositories/account_repository.dart';
import 'package:sharedinbox/core/repositories/email_repository.dart';
import 'package:sharedinbox/core/repositories/mailbox_repository.dart';
import 'package:sharedinbox/core/repositories/sync_log_repository.dart';
import 'package:sharedinbox/core/sync/account_sync_manager.dart';
void main() {
test('AccountSyncManager schedules sync for multiple accounts', () async {
final accounts = _FakeAccounts('pw');
final mailboxes = _FakeMailboxes();
final emails = _FakeEmails();
final logs = _FakeLogs();
final manager = AccountSyncManager(
accounts,
mailboxes,
emails,
syncLog: logs,
);
final a1 = _account('1');
final a2 = _account('2');
manager.start();
accounts.push([a1, a2]);
// Allow some time for listeners to fire.
await Future<void>.delayed(const Duration(milliseconds: 100));
expect(emails.syncCounts['1'], greaterThanOrEqualTo(1));
expect(emails.syncCounts['2'], greaterThanOrEqualTo(1));
manager.dispose();
});
}
Account _account(String id) => Account(
id: id,
displayName: 'Account $id',
email: '$id@example.com',
imapHost: 'localhost',
imapPort: 143,
imapSsl: false,
smtpHost: 'localhost',
smtpPort: 25,
smtpSsl: false,
);
class _FakeAccounts implements AccountRepository {
_FakeAccounts(this.password);
final String password;
final _ctrl = StreamController<List<Account>>.broadcast();
@override
Stream<List<Account>> observeAccounts() => _ctrl.stream;
@override
Future<Account?> getAccount(String id) async => null;
@override
Future<String> getPassword(String accountId) async => password;
@override
Future<void> addAccount(Account a, String p) async {}
@override
Future<void> removeAccount(String id) async {}
@override
Future<void> updateAccount(Account a, {String? password}) async {}
void push(List<Account> accounts) => _ctrl.add(accounts);
}
class _FakeMailboxes implements MailboxRepository {
@override
Stream<List<Mailbox>> observeMailboxes(String? accountId) => Stream.value([
Mailbox(
id: '$accountId:INBOX',
accountId: accountId ?? '',
path: 'INBOX',
name: 'INBOX',
unreadCount: 0,
totalCount: 0,
role: 'inbox',
),
]);
@override
Future<int> syncMailboxes(String accountId) async => 0;
@override
Future<Mailbox?> findMailboxByRole(String accountId, String role) async =>
null;
@override
Future<void> clearForResync(String accountId) async {}
}
class _FakeEmails implements EmailRepository {
final syncCounts = <String, int>{};
@override
Stream<List<Email>> observeEmails(
String a,
String m, {
int limit = 50,
}) =>
Stream.value([]);
@override
Stream<List<EmailThread>> observeThreads(
String a,
String m, {
int limit = 50,
}) =>
Stream.value([]);
@override
Stream<List<Email>> observeEmailsInThread(String a, String m, String t) =>
Stream.value([]);
@override
Future<Email?> getEmail(String id) async => null;
@override
Future<EmailBody> getEmailBody(String id) async =>
const EmailBody(emailId: '', attachments: []);
@override
Future<SyncEmailsResult> syncEmails(String a, String m) async {
syncCounts[a] = (syncCounts[a] ?? 0) + 1;
return SyncEmailsResult.zero;
}
@override
Future<void> setFlag(String id, {bool? seen, bool? flagged}) async {}
@override
Future<void> moveEmail(String id, String dest) async {}
@override
Future<bool> cancelPendingChange(String id, String type) async => false;
@override
Future<void> snoozeEmail(String emailId, DateTime until) async {}
@override
Future<int> wakeUpEmails(String accountId) async => 0;
@override
Future<void> restoreEmails(List<Email> emails) async {}
@override
Future<String?> deleteEmail(String id) async => null;
@override
Stream<String> get onChangesQueued => const Stream.empty();
@override
Future<int> flushPendingChanges(String accountId, String password) async => 0;
@override
Future<void> sendEmail(String a, EmailDraft d) async {}
@override
Future<String> downloadAttachment(
String emailId,
EmailAttachment attachment,
) async =>
'/tmp/${attachment.filename}';
@override
Future<List<Email>> searchEmails(String a, String m, String q) async => [];
@override
Future<List<Email>> searchEmailsGlobal(String? a, String q) async => [];
@override
Future<List<Email>> getEmailsByAddress(String? a, String address) async => [];
@override
Stream<void> watchJmapPush(String accountId, String password) =>
const Stream.empty();
@override
Future<ReliabilityResult> verifySyncReliability(
String accountId,
String mailboxPath,
) async =>
ReliabilityResult.healthy;
@override
Stream<List<FailedMutation>> observeFailedMutations(String accountId) =>
Stream.value([]);
@override
Future<void> discardMutation(int id) async {}
@override
Future<void> retryMutation(int id) async {}
@override
Future<void> clearForResync(String accountId) async {}
}
class _FakeLogs implements SyncLogRepository {
@override
Future<void> log({
required String accountId,
required bool success,
String? errorMessage,
required String protocol,
required int emailsFetched,
required int emailsSkipped,
required int mailboxesSynced,
required int pendingFlushed,
required int bytesTransferred,
required DateTime startedAt,
required DateTime finishedAt,
List<MailboxSyncStats> mailboxStats = const [],
String? protocolLog,
}) async {}
@override
Stream<List<SyncLogEntry>> observeSyncLogs(String accountId) =>
Stream.value([]);
@override
Stream<String?> observeLastError(String accountId) => Stream.value(null);
}