Mailspring/packages/isomorphic-core/spec/imap-connection-pool-spec.es6
Mark Hahnenberg 4ef8e7614e [client-sync] Don't handle IMAP timeouts in the connection pool
Summary:
Different clients can have different policies for retrying after
timeouts.

Test Plan: Run locally, run tests

Reviewers: evan, spang, juan

Reviewed By: juan

Differential Revision: https://phab.nylas.com/D4247
2017-03-23 11:33:53 -07:00

205 lines
6.8 KiB
JavaScript

import IMAPConnectionPool from '../src/imap-connection-pool';
import IMAPConnection from '../src/imap-connection';
import IMAPErrors from '../src/imap-errors';
describe('IMAPConnectionPool', function describeBlock() {
beforeEach(() => {
this.account = {
id: 'test-account',
decryptedCredentials: () => { return {}; },
connectionSettings: {
imap_host: 'imap.foobar.com',
},
};
IMAPConnectionPool._poolMap = {};
this.logger = {};
spyOn(IMAPConnection.prototype, 'connect').andCallFake(function connectFake() {
return this;
});
spyOn(IMAPConnection.prototype, 'end').andCallFake(() => {});
});
it('opens IMAP connection and properly returns to pool at end of scope', async () => {
let invokedCallback = false;
await IMAPConnectionPool.withConnectionsForAccount(this.account, {
desiredCount: 1,
logger: this.logger,
socketTimeout: 5 * 1000,
onConnected: ([conn]) => {
expect(conn instanceof IMAPConnection).toBe(true);
invokedCallback = true;
return false;
},
});
expect(invokedCallback).toBe(true);
expect(IMAPConnection.prototype.connect.calls.length).toBe(1);
expect(IMAPConnection.prototype.end.calls.length).toBe(0);
});
it('opens multiple IMAP connections and properly returns to pool at end of scope', async () => {
let invokedCallback = false;
await IMAPConnectionPool.withConnectionsForAccount(this.account, {
desiredCount: 2,
logger: this.logger,
socketTimeout: 5 * 1000,
onConnected: ([conn, otherConn]) => {
expect(conn instanceof IMAPConnection).toBe(true);
expect(otherConn instanceof IMAPConnection).toBe(true);
invokedCallback = true;
return false;
},
});
expect(invokedCallback).toBe(true);
expect(IMAPConnection.prototype.connect.calls.length).toBe(2);
expect(IMAPConnection.prototype.end.calls.length).toBe(0);
});
it('opens an IMAP connection properly and only returns to pool on done', async () => {
let invokedCallback = false;
let doneCallback = null;
await IMAPConnectionPool.withConnectionsForAccount(this.account, {
desiredCount: 1,
logger: this.logger,
socketTimeout: 5 * 1000,
onConnected: ([conn], done) => {
expect(conn instanceof IMAPConnection).toBe(true);
invokedCallback = true;
doneCallback = done;
return true;
},
});
expect(invokedCallback).toBe(true);
expect(IMAPConnection.prototype.connect.calls.length).toBe(1);
expect(IMAPConnection.prototype.end.calls.length).toBe(0);
expect(IMAPConnectionPool._poolMap[this.account.id]._availableConns.length === 2);
doneCallback();
expect(IMAPConnectionPool._poolMap[this.account.id]._availableConns.length === 3);
});
it('does not call connect if already connected', async () => {
let invokedCallback = false;
await IMAPConnectionPool.withConnectionsForAccount(this.account, {
desiredCount: 1,
logger: this.logger,
socketTimeout: 5 * 1000,
onConnected: ([conn]) => {
expect(conn instanceof IMAPConnection).toBe(true);
invokedCallback = true;
return false;
},
});
expect(invokedCallback).toBe(true);
expect(IMAPConnection.prototype.connect.calls.length).toBe(1);
expect(IMAPConnection.prototype.end.calls.length).toBe(0);
invokedCallback = false;
await IMAPConnectionPool.withConnectionsForAccount(this.account, {
desiredCount: 1,
logger: this.logger,
socketTimeout: 5 * 1000,
onConnected: ([conn]) => {
expect(conn instanceof IMAPConnection).toBe(true);
invokedCallback = true;
return false;
},
});
expect(invokedCallback).toBe(true);
expect(IMAPConnection.prototype.connect.calls.length).toBe(1);
expect(IMAPConnection.prototype.end.calls.length).toBe(0);
});
it('waits for an available IMAP connection', async () => {
let invokedCallback = false;
let doneCallback = null;
await IMAPConnectionPool.withConnectionsForAccount(this.account, {
desiredCount: 3,
logger: this.logger,
socketTimeout: 5 * 1000,
onConnected: ([conn], done) => {
expect(conn instanceof IMAPConnection).toBe(true);
invokedCallback = true;
doneCallback = done;
return true;
},
});
expect(invokedCallback).toBe(true);
expect(IMAPConnection.prototype.connect.calls.length).toBe(3);
expect(IMAPConnection.prototype.end.calls.length).toBe(0);
invokedCallback = false;
const promise = IMAPConnectionPool.withConnectionsForAccount(this.account, {
desiredCount: 1,
logger: this.logger,
socketTimeout: 5 * 1000,
onConnected: ([conn]) => {
expect(conn instanceof IMAPConnection).toBe(true);
invokedCallback = true;
return false;
},
});
expect(IMAPConnectionPool._poolMap[this.account.id]._queue.length).toBe(1)
doneCallback();
await promise;
expect(invokedCallback).toBe(true);
expect(IMAPConnection.prototype.connect.calls.length).toBe(3);
expect(IMAPConnection.prototype.end.calls.length).toBe(0);
});
it('does not retry on IMAP connection timeout', async () => {
let invokeCount = 0;
try {
await IMAPConnectionPool.withConnectionsForAccount(this.account, {
desiredCount: 1,
logger: this.logger,
socketTimeout: 5 * 1000,
onConnected: ([conn]) => {
expect(conn instanceof IMAPConnection).toBe(true);
if (invokeCount === 0) {
invokeCount += 1;
throw new IMAPErrors.IMAPConnectionTimeoutError();
}
invokeCount += 1;
return false;
},
});
} catch (err) {
expect(err instanceof IMAPErrors.IMAPConnectionTimeoutError).toBe(true);
}
expect(invokeCount).toBe(1);
expect(IMAPConnection.prototype.connect.calls.length).toBe(1);
expect(IMAPConnection.prototype.end.calls.length).toBe(1);
});
it('does not retry on other IMAP error', async () => {
let invokeCount = 0;
let errorCount = 0;
try {
await IMAPConnectionPool.withConnectionsForAccount(this.account, {
desiredCount: 1,
logger: this.logger,
socketTimeout: 5 * 1000,
onConnected: ([conn]) => {
expect(conn instanceof IMAPConnection).toBe(true);
if (invokeCount === 0) {
invokeCount += 1;
throw new IMAPErrors.IMAPSocketError();
}
invokeCount += 1;
return false;
},
});
} catch (err) {
errorCount += 1;
}
expect(invokeCount).toBe(1);
expect(errorCount).toBe(1);
expect(IMAPConnection.prototype.connect.calls.length).toBe(1);
expect(IMAPConnection.prototype.end.calls.length).toBe(1);
});
});