|
@@ -3,11 +3,25 @@ import { readFileSync } from 'node:fs';
|
|
|
import { test } from 'node:test';
|
|
import { test } from 'node:test';
|
|
|
|
|
|
|
|
const compose = readFileSync(new URL('../docker-compose.yml', import.meta.url), 'utf8');
|
|
const compose = readFileSync(new URL('../docker-compose.yml', import.meta.url), 'utf8');
|
|
|
|
|
+const appService = compose.match(/^ app:\n[\s\S]*?(?=^ dovecot:)/m)?.[0] || '';
|
|
|
|
|
+const dovecotService = compose.match(/^ dovecot:\n[\s\S]*?(?=^ postfix:)/m)?.[0] || '';
|
|
|
|
|
+const envExample = readFileSync(new URL('../.env.example', import.meta.url), 'utf8');
|
|
|
|
|
+const readme = readFileSync(new URL('../README.md', import.meta.url), 'utf8');
|
|
|
|
|
+const maildirSyncSource = readFileSync(new URL('../src/maildir-sync.js', import.meta.url), 'utf8');
|
|
|
|
|
+const serverSource = readFileSync(new URL('../src/server.js', import.meta.url), 'utf8');
|
|
|
const authConfig = readFileSync(new URL('../docker/dovecot/auth.conf', import.meta.url), 'utf8');
|
|
const authConfig = readFileSync(new URL('../docker/dovecot/auth.conf', import.meta.url), 'utf8');
|
|
|
const mailConfig = readFileSync(new URL('../docker/dovecot/mailhub.conf', import.meta.url), 'utf8');
|
|
const mailConfig = readFileSync(new URL('../docker/dovecot/mailhub.conf', import.meta.url), 'utf8');
|
|
|
const sslConfig = readFileSync(new URL('../docker/dovecot/ssl.conf', import.meta.url), 'utf8');
|
|
const sslConfig = readFileSync(new URL('../docker/dovecot/ssl.conf', import.meta.url), 'utf8');
|
|
|
const authLua = readFileSync(new URL('../docker/dovecot/auth.lua', import.meta.url), 'utf8');
|
|
const authLua = readFileSync(new URL('../docker/dovecot/auth.lua', import.meta.url), 'utf8');
|
|
|
|
|
|
|
|
|
|
+test('Maildir reconciliation defaults to a five-minute polling interval', () => {
|
|
|
|
|
+ assert.match(serverSource, /MAILDIR_SYNC_INTERVAL_MS \|\| 300000/);
|
|
|
|
|
+ assert.match(maildirSyncSource, /intervalMs = 300_000/);
|
|
|
|
|
+ assert.match(maildirSyncSource, /Number\(intervalMs\) \|\| 300_000/);
|
|
|
|
|
+ assert.match(envExample, /^MAILDIR_SYNC_INTERVAL_MS=300000$/m);
|
|
|
|
|
+ assert.match(readme, /MAILDIR_SYNC_INTERVAL_MS[^\n]*`300000` 毫秒(5 分钟)/);
|
|
|
|
|
+});
|
|
|
|
|
+
|
|
|
test('Compose delegates public IMAP and POP3 ports to rootless Dovecot', () => {
|
|
test('Compose delegates public IMAP and POP3 ports to rootless Dovecot', () => {
|
|
|
assert.match(compose, /image: dovecot\/dovecot:2\.4\.4/);
|
|
assert.match(compose, /image: dovecot\/dovecot:2\.4\.4/);
|
|
|
for (const mapping of ['143:31143', '993:31993', '110:31110', '995:31995']) {
|
|
for (const mapping of ['143:31143', '993:31993', '110:31110', '995:31995']) {
|
|
@@ -17,6 +31,11 @@ test('Compose delegates public IMAP and POP3 ports to rootless Dovecot', () => {
|
|
|
assert.equal(compose.includes(oldMapping), false, `app still owns ${oldMapping}`);
|
|
assert.equal(compose.includes(oldMapping), false, `app still owns ${oldMapping}`);
|
|
|
}
|
|
}
|
|
|
assert.match(compose, /dovecot_internal:\n\s+internal: true/);
|
|
assert.match(compose, /dovecot_internal:\n\s+internal: true/);
|
|
|
|
|
+ assert.match(dovecotService, /networks:\n\s+- dovecot_internal\n\s+- dovecot_public/);
|
|
|
|
|
+ assert.match(compose, /^ dovecot_public:\s*$/m);
|
|
|
|
|
+ assert.doesNotMatch(compose, /dovecot_public:\n\s+internal: true/);
|
|
|
|
|
+ assert.match(appService, /networks:\n\s+- mailhub\n\s+- dovecot_internal/);
|
|
|
|
|
+ assert.doesNotMatch(appService, /dovecot_public/);
|
|
|
assert.match(compose, /file: \.\/data\/secrets\/dovecot_auth_secret/);
|
|
assert.match(compose, /file: \.\/data\/secrets\/dovecot_auth_secret/);
|
|
|
assert.match(compose, /MAIL_ACCESS_BACKEND: dovecot/);
|
|
assert.match(compose, /MAIL_ACCESS_BACKEND: dovecot/);
|
|
|
assert.match(compose, /MAILDIR_ROOT: \/data\/maildir/);
|
|
assert.match(compose, /MAILDIR_ROOT: \/data\/maildir/);
|