2026-04-16 07:40:34 +02:00
|
|
|
// Integration tests — requires a running Stalwart instance.
|
|
|
|
|
// Run via: stalwart-dev/test.sh (sets the env vars below)
|
|
|
|
|
//
|
|
|
|
|
// STALWART_IMAP_HOST, STALWART_IMAP_PORT, STALWART_SMTP_HOST, STALWART_SMTP_PORT
|
2026-04-23 17:43:20 +02:00
|
|
|
// STALWART_USER_B / STALWART_PASS_B (alice@example.com)
|
|
|
|
|
// STALWART_USER_C / STALWART_PASS_C (bob@example.com)
|
2026-04-16 07:40:34 +02:00
|
|
|
|
|
|
|
|
import 'dart:io';
|
|
|
|
|
|
|
|
|
|
import 'package:enough_mail/enough_mail.dart';
|
|
|
|
|
import 'package:test/test.dart';
|
|
|
|
|
|
|
|
|
|
String _env(String key) {
|
|
|
|
|
final v = Platform.environment[key];
|
|
|
|
|
if (v == null || v.isEmpty) throw StateError('$key is not set');
|
|
|
|
|
return v;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Future<ImapClient> _connect(
|
|
|
|
|
String user,
|
|
|
|
|
String pass, {
|
2026-04-16 08:21:14 +02:00
|
|
|
required String host,
|
|
|
|
|
required int port,
|
2026-04-16 07:40:34 +02:00
|
|
|
}) async {
|
2026-04-16 08:21:14 +02:00
|
|
|
final client = ImapClient();
|
|
|
|
|
await client.connectToServer(host, port, isSecure: false);
|
2026-04-16 07:40:34 +02:00
|
|
|
await client.login(user, pass);
|
|
|
|
|
return client;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void main() {
|
2026-04-16 08:21:14 +02:00
|
|
|
late String imapHost;
|
2026-04-16 07:40:34 +02:00
|
|
|
late int imapPort;
|
|
|
|
|
late int smtpPort;
|
|
|
|
|
late String userA, passA, userB, passB;
|
|
|
|
|
|
|
|
|
|
setUpAll(() {
|
2026-04-16 08:21:14 +02:00
|
|
|
imapHost = Platform.environment['STALWART_IMAP_HOST'] ?? '127.0.0.1';
|
2026-04-16 07:40:34 +02:00
|
|
|
imapPort = int.parse(_env('STALWART_IMAP_PORT'));
|
|
|
|
|
smtpPort = int.parse(_env('STALWART_SMTP_PORT'));
|
|
|
|
|
userA = _env('STALWART_USER_B'); // alice
|
|
|
|
|
passA = _env('STALWART_PASS_B');
|
|
|
|
|
userB = _env('STALWART_USER_C'); // bob
|
|
|
|
|
passB = _env('STALWART_PASS_C');
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('login and list mailboxes', () async {
|
2026-05-12 21:55:06 +02:00
|
|
|
final client = await _connect(userA, passA, host: imapHost, port: imapPort);
|
2026-04-16 07:40:34 +02:00
|
|
|
addTearDown(() => client.logout().ignore());
|
|
|
|
|
|
2026-04-16 08:21:14 +02:00
|
|
|
// listMailboxes() returns List<Mailbox> directly
|
|
|
|
|
final mailboxes = await client.listMailboxes();
|
|
|
|
|
expect(mailboxes, isNotEmpty);
|
|
|
|
|
expect(mailboxes.map((m) => m.name), contains('INBOX'));
|
2026-04-16 07:40:34 +02:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
test('send via SMTP and receive via IMAP', () async {
|
2026-04-16 08:21:14 +02:00
|
|
|
final smtpClient = SmtpClient('test');
|
2026-04-16 07:40:34 +02:00
|
|
|
await smtpClient.connectToServer(imapHost, smtpPort, isSecure: false);
|
|
|
|
|
await smtpClient.ehlo();
|
2026-04-16 10:08:05 +02:00
|
|
|
await smtpClient.authenticate(userA, passA);
|
2026-04-16 07:40:34 +02:00
|
|
|
|
|
|
|
|
final builder = MessageBuilder()
|
2026-04-18 12:05:20 +02:00
|
|
|
..from = [MailAddress('Alice', userA)]
|
|
|
|
|
..to = [MailAddress('Bob', userB)]
|
2026-04-16 07:40:34 +02:00
|
|
|
..subject = 'Integration test ${DateTime.now().millisecondsSinceEpoch}'
|
|
|
|
|
..text = 'Hello from SharedInbox integration test.';
|
|
|
|
|
await smtpClient.sendMessage(builder.buildMimeMessage());
|
2026-04-16 08:21:14 +02:00
|
|
|
await smtpClient.quit();
|
2026-04-16 07:40:34 +02:00
|
|
|
|
|
|
|
|
// Give Stalwart a moment to deliver the message.
|
2026-04-16 08:21:14 +02:00
|
|
|
await Future<void>.delayed(const Duration(milliseconds: 500));
|
2026-04-16 07:40:34 +02:00
|
|
|
|
2026-04-16 08:21:14 +02:00
|
|
|
final imapClient = await _connect(
|
|
|
|
|
userB,
|
|
|
|
|
passB,
|
|
|
|
|
host: imapHost,
|
|
|
|
|
port: imapPort,
|
|
|
|
|
);
|
2026-04-16 07:40:34 +02:00
|
|
|
addTearDown(() => imapClient.logout().ignore());
|
|
|
|
|
|
2026-04-16 08:21:14 +02:00
|
|
|
final inbox = await imapClient.selectMailboxByPath('INBOX');
|
|
|
|
|
expect(inbox.messagesExists, greaterThan(0));
|
2026-04-16 07:40:34 +02:00
|
|
|
});
|
|
|
|
|
}
|