ae15e12ffc
ref https://linear.app/tryghost/issue/ENG-1518 After releasing the analytics job improvements, it appears for large sites we're awfully close to missing some Mailgun events because of an unexpected behavior of the aggregateStats call for just the opened events job. This is taking 2-5x(+) the amount of time that the aggregate queries take for the other jobs, despite not being dependent on the events. To err on the side of caution, we're going to roll this back and look to optimize the aggregation queries before re-implementing. And we may be a bit more cautious in giving _some_ but not _all_ priority to the `opened` events.
160 lines
6.1 KiB
JavaScript
160 lines
6.1 KiB
JavaScript
const sinon = require('sinon');
|
|
|
|
const {EventProcessingResult} = require('@tryghost/email-analytics-service');
|
|
|
|
// module under test
|
|
const EmailAnalyticsProviderMailgun = require('../');
|
|
|
|
const SAMPLE_EVENTS = [
|
|
new EventProcessingResult({
|
|
delivered: 4,
|
|
opened: 2,
|
|
temporaryFailed: 0,
|
|
permanentFailed: 0,
|
|
unsubscribed: 0,
|
|
complained: 0,
|
|
unhandled: 0,
|
|
unprocessable: 0,
|
|
processingFailures: 0,
|
|
emailIds: [
|
|
'62f3aebaaa887b504a40519f',
|
|
'62f3c200e8e74e677ab5e1fa',
|
|
'62f3c606de193a6d00433dfc'
|
|
],
|
|
memberIds: ['62ed25f69ae8f1a8c22d1a2f']
|
|
})
|
|
];
|
|
|
|
describe('EmailAnalyticsProviderMailgun', function () {
|
|
let config, settings;
|
|
|
|
beforeEach(function () {
|
|
// options objects that can be stubbed or spied
|
|
config = {get() {}};
|
|
settings = {get() {}};
|
|
});
|
|
|
|
afterEach(function () {
|
|
sinon.restore();
|
|
});
|
|
|
|
describe('fetchLatest()', function () {
|
|
const LATEST_TIMESTAMP = new Date('Thu Feb 25 2021 12:00:00 GMT+0000');
|
|
const END_EXAMPLE = new Date('Thu Feb 25 2021 14:00:00 GMT+0000');
|
|
const MAILGUN_OPTIONS = {
|
|
event: 'delivered OR opened OR failed OR unsubscribed OR complained',
|
|
limit: 300,
|
|
tags: 'bulk-email',
|
|
begin: 1614254400,
|
|
end: undefined,
|
|
ascending: 'yes'
|
|
};
|
|
|
|
it('passes the correct parameters to mailgun-client', async function () {
|
|
const configStub = sinon.stub(config, 'get');
|
|
configStub.withArgs('bulkEmail').returns({
|
|
mailgun: {
|
|
apiKey: 'apiKey',
|
|
domain: 'domain.com',
|
|
baseUrl: 'https://api.mailgun.net/v3'
|
|
}
|
|
});
|
|
|
|
const mailgunProvider = new EmailAnalyticsProviderMailgun({config, settings});
|
|
|
|
const batchHandler = sinon.spy();
|
|
const mailgunFetchEventsStub = sinon.stub(mailgunProvider.mailgunClient, 'fetchEvents').returns(SAMPLE_EVENTS);
|
|
|
|
await mailgunProvider.fetchLatest(batchHandler, {begin: LATEST_TIMESTAMP});
|
|
sinon.assert.calledWithExactly(mailgunFetchEventsStub, MAILGUN_OPTIONS, batchHandler, {maxEvents: undefined});
|
|
});
|
|
|
|
it('can use end timestamp', async function () {
|
|
const configStub = sinon.stub(config, 'get');
|
|
configStub.withArgs('bulkEmail').returns({
|
|
mailgun: {
|
|
apiKey: 'apiKey',
|
|
domain: 'domain.com',
|
|
baseUrl: 'https://api.mailgun.net/v3'
|
|
}
|
|
});
|
|
|
|
const mailgunProvider = new EmailAnalyticsProviderMailgun({config, settings});
|
|
|
|
const batchHandler = sinon.spy();
|
|
const mailgunFetchEventsStub = sinon.stub(mailgunProvider.mailgunClient, 'fetchEvents').returns(SAMPLE_EVENTS);
|
|
|
|
await mailgunProvider.fetchLatest(batchHandler, {begin: LATEST_TIMESTAMP, end: END_EXAMPLE});
|
|
|
|
const END_EXAMPLE_UNIX = END_EXAMPLE.getTime() / 1000;
|
|
sinon.assert.calledWithExactly(mailgunFetchEventsStub, {...MAILGUN_OPTIONS, end: END_EXAMPLE_UNIX}, batchHandler, {maxEvents: undefined});
|
|
});
|
|
|
|
it('can use end without begin', async function () {
|
|
const configStub = sinon.stub(config, 'get');
|
|
configStub.withArgs('bulkEmail').returns({
|
|
mailgun: {
|
|
apiKey: 'apiKey',
|
|
domain: 'domain.com',
|
|
baseUrl: 'https://api.mailgun.net/v3'
|
|
}
|
|
});
|
|
|
|
const mailgunProvider = new EmailAnalyticsProviderMailgun({config, settings});
|
|
|
|
const batchHandler = sinon.spy();
|
|
const mailgunFetchEventsStub = sinon.stub(mailgunProvider.mailgunClient, 'fetchEvents').returns(SAMPLE_EVENTS);
|
|
|
|
await mailgunProvider.fetchLatest(batchHandler, {end: END_EXAMPLE});
|
|
|
|
const END_EXAMPLE_UNIX = END_EXAMPLE.getTime() / 1000;
|
|
sinon.assert.calledWithExactly(mailgunFetchEventsStub, {...MAILGUN_OPTIONS, begin: undefined, end: END_EXAMPLE_UNIX}, batchHandler, {maxEvents: undefined});
|
|
});
|
|
|
|
it('can use max events', async function () {
|
|
const configStub = sinon.stub(config, 'get');
|
|
configStub.withArgs('bulkEmail').returns({
|
|
mailgun: {
|
|
apiKey: 'apiKey',
|
|
domain: 'domain.com',
|
|
baseUrl: 'https://api.mailgun.net/v3'
|
|
}
|
|
});
|
|
|
|
const mailgunProvider = new EmailAnalyticsProviderMailgun({config, settings});
|
|
|
|
const batchHandler = sinon.spy();
|
|
const mailgunFetchEventsStub = sinon.stub(mailgunProvider.mailgunClient, 'fetchEvents').returns(SAMPLE_EVENTS);
|
|
|
|
await mailgunProvider.fetchLatest(batchHandler, {begin: LATEST_TIMESTAMP, end: END_EXAMPLE, maxEvents: 1000});
|
|
|
|
const END_EXAMPLE_UNIX = END_EXAMPLE.getTime() / 1000;
|
|
sinon.assert.calledWithExactly(mailgunFetchEventsStub, {...MAILGUN_OPTIONS, end: END_EXAMPLE_UNIX}, batchHandler, {maxEvents: 1000});
|
|
});
|
|
|
|
it('uses custom tags when supplied', async function () {
|
|
const configStub = sinon.stub(config, 'get');
|
|
configStub.withArgs('bulkEmail').returns({
|
|
mailgun: {
|
|
apiKey: 'apiKey',
|
|
domain: 'domain.com',
|
|
baseUrl: 'https://api.mailgun.net/v3'
|
|
}
|
|
});
|
|
configStub.withArgs('bulkEmail:mailgun:tag').returns('custom-tag');
|
|
|
|
const mailgunProvider = new EmailAnalyticsProviderMailgun({config, settings});
|
|
|
|
const batchHandler = sinon.spy();
|
|
const mailgunFetchEventsStub = sinon.stub(mailgunProvider.mailgunClient, 'fetchEvents').returns(SAMPLE_EVENTS);
|
|
|
|
await mailgunProvider.fetchLatest(batchHandler, {begin: LATEST_TIMESTAMP});
|
|
|
|
sinon.assert.calledWithExactly(mailgunFetchEventsStub, {
|
|
...MAILGUN_OPTIONS,
|
|
tags: 'bulk-email AND custom-tag'
|
|
}, batchHandler, {maxEvents: undefined});
|
|
});
|
|
});
|
|
});
|