};
ctx = {
params: {},
+ queryParams: {},
};
manager = new Manager(stubLogger, stubDb, options);
sinon.stub(manager.communication, 'verificationProcess');
sinon.stub(manager.communication, 'topicFetchProcess');
+ sinon.stub(manager.communication, 'topicFetchClaimAndProcessById');
stubDb._reset();
stubLogger._reset();
});
await manager.getRoot(req, res, ctx);
assert(res.end.called);
});
- it('repeat response', async function () {
- manager.startTime = (new Date()).toGMTString();
- common.isClientCached.returns(true);
- await manager.getRoot(req, res, ctx);
- assert(res.end.called);
- });
- it('cached response', async function () {
- common.isClientCached.returns(true);
- await manager.getRoot(req, res, ctx);
- assert(res.end.called);
- assert.strictEqual(res.statusCode, 304);
- });
}); // getRoot
describe('getHealthcheck', function () {
});
}); // getInfo
- describe('getAdminOverview', function () {
+ describe('_historyBarCaption', function () {
+ it('covers today, none', function () {
+ const result = Manager._historyBarCaption(0, 0);
+ assert.strictEqual(result, 'today, no updates');
+ });
+ it('covers yesterday, singular', function () {
+ const result = Manager._historyBarCaption(1, 1);
+ assert.strictEqual(result, 'yesterday, 1 update');
+ });
+ it('covers older, plural', function () {
+ const result = Manager._historyBarCaption(7, 3);
+ assert.strictEqual(result, '7 days ago, 3 updates');
+ });
+ }); // _historyBarCaption
+
+ describe('getHistorySVG', function () {
+ beforeEach(function () {
+ manager.db.topicPublishHistory.resolves([0, 1, 2, 1, 0, 1, 2, 0, 1]);
+ });
it('covers', async function () {
+ await manager.getHistorySVG(res, ctx);
+ assert(res.end.called);
+ });
+ }); // getHistorySVG
+
+ describe('getAdminOverview', function () {
+ beforeEach(function () {
manager.db.topicGetAll.resolves([
{
id: '56c557ce-e667-11eb-bd80-0025905f714a',
subscribers: 12,
},
]);
+ });
+ it('covers', async function () {
await manager.getAdminOverview(res, ctx);
assert(res.end.called);
});
- });
+ it('covers non-matching profile', async function () {
+ ctx.session = {
+ authenticatedProfile: 'https://different.example.com/profile',
+ };
+ await manager.getAdminOverview(res, ctx);
+ assert.deepStrictEqual(ctx.topics, []);
+ assert(res.end.called);
+ });
+ }); // getAdminOverview
describe('getTopicDetails', function () {
- it('covers', async function() {
+ beforeEach(function () {
ctx.params.topicId = '56c557ce-e667-11eb-bd80-0025905f714a';
manager.db.topicGetById.resolves({
id: '56c557ce-e667-11eb-bd80-0025905f714a',
deliveryAttemptsSinceSuccess: 0,
deliveryNextAttempt: new Date(-Infinity),
}]);
+ manager.db.topicPublishHistory.resolves([0, 1, 0, 1, 0]);
+ });
+ it('covers', async function() {
+ await manager.getTopicDetails(res, ctx);
+ assert(res.end.called);
+ });
+ it('covers non-matching profile', async function () {
+ ctx.session = {
+ authenticatedProfile: 'https://different.example.com/profile',
+ };
+ await manager.getTopicDetails(res, ctx);
+ assert.strictEqual(ctx.topic, null);
+ assert(res.end.called);
+ });
+ it('covers matching profile', async function () {
+ ctx.session = {
+ authenticatedProfile: 'https://example.com/profile',
+ };
await manager.getTopicDetails(res, ctx);
+ assert(ctx.topic);
assert(res.end.called);
});
}); // getTopicDetails
});
}); // _checkMode
- describe('_checkPublish', function () {
- let dbCtx, data, warn, err, requestId;
+ describe('_publishTopics', function () {
+ let dbCtx, data, requestId;
beforeEach(function () {
dbCtx = {};
data = {};
- warn = [];
- err = [];
requestId = 'blah';
});
it('succeeds', async function () {
id: 222,
});
Object.assign(data, testData.validPublishRootData);
- await manager._checkPublish(dbCtx, data, warn, err, requestId);
- assert.strictEqual(warn.length, 0, 'unexpected warnings length');
- assert.strictEqual(err.length, 0, 'unexpected errors length');
- assert.strictEqual(data.topicId, 222, 'unexpected topic id');
+ const topicResults = await manager._publishTopics(dbCtx, data, requestId);
+ assert.strictEqual(topicResults.length, 1);
+ assert.strictEqual(topicResults[0].warn.length, 0, 'unexpected warnings length');
+ assert.strictEqual(topicResults[0].err.length, 0, 'unexpected errors length');
+ assert.strictEqual(topicResults[0].topicId, 222, 'unexpected topic id');
});
it('fails bad url', async function () {
Object.assign(data, testData.validPublishRootData, { topic: 'not_a_url' });
- await manager._checkPublish(dbCtx, data, warn, err, requestId);
- assert.strictEqual(err.length, 1, 'unexpected errors length');
- assert.strictEqual(warn.length, 0);
+ const topicResults = await manager._publishTopics(dbCtx, data, requestId);
+ assert.strictEqual(topicResults.length, 1);
+ assert.strictEqual(topicResults[0].err.length, 1, 'unexpected errors length');
+ assert.strictEqual(topicResults[0].warn.length, 0);
});
it('accepts new public publish topic', async function () {
manager.db.topicGetByUrl.onCall(0).resolves().onCall(1).resolves({
id: 222,
});
Object.assign(data, testData.validPublishRootData);
- await manager._checkPublish(dbCtx, data, warn, err, requestId);
- assert.strictEqual(warn.length, 0, 'unexpected warnings length');
- assert.strictEqual(err.length, 0, 'unexpected errors length');
- assert.strictEqual(data.topicId, 222, 'unexpected topic id');
+ const topicResults = await manager._publishTopics(dbCtx, data, requestId);
+ assert.strictEqual(topicResults.length, 1);
+ assert.strictEqual(topicResults[0].warn.length, 0, 'unexpected warnings length');
+ assert.strictEqual(topicResults[0].err.length, 0, 'unexpected errors length');
+ assert.strictEqual(topicResults[0].topicId, 222, 'unexpected topic id');
});
it('does not publish deleted topic', async function () {
manager.db.topicGetByUrl.resolves({
isDeleted: true,
});
Object.assign(data, testData.validPublishRootData);
- await manager._checkPublish(dbCtx, data, warn, err, requestId);
- assert.strictEqual(warn.length, 0, 'unexpected warnings length');
- assert.strictEqual(err.length, 1, 'unexpected errors length');
- assert.strictEqual(data.topicId, undefined, 'unexpected topic id');
+ const topicResults = await manager._publishTopics(dbCtx, data, requestId);
+ assert.strictEqual(topicResults.length, 1);
+ assert.strictEqual(topicResults[0].warn.length, 0, 'unexpected warnings length');
+ assert.strictEqual(topicResults[0].err.length, 1, 'unexpected errors length');
+ assert.strictEqual(topicResults[0].topicId, undefined, 'unexpected topic id');
+ });
+ it('no topics', async function() {
+ Object.assign(data, testData.validPublishRootData);
+ delete data.topic;
+ const topicResults = await manager._publishTopics(dbCtx, data, requestId);
+ assert.strictEqual(topicResults.length, 0);
+ });
+ it('multiple valid topics', async function () {
+ manager.db.topicGetByUrl.resolves({
+ id: 222,
+ });
+ Object.assign(data, testData.validPublishRootData);
+ data.url = ['https://example.com/first', 'https://example.com/second'];
+ data.topic = ['https://example.com/third'];
+ const topicResults = await manager._publishTopics(dbCtx, data, requestId);
+ assert.strictEqual(topicResults.length, 3);
+ assert.strictEqual(topicResults[0].warn.length, 0, 'unexpected warnings length');
+ assert.strictEqual(topicResults[0].err.length, 0, 'unexpected errors length');
+ assert.strictEqual(topicResults[0].topicId, 222, 'unexpected topic id');
+ assert.strictEqual(topicResults[1].warn.length, 0, 'unexpected warnings length');
+ assert.strictEqual(topicResults[1].err.length, 0, 'unexpected errors length');
+ assert.strictEqual(topicResults[1].topicId, 222, 'unexpected topic id');
+ assert.strictEqual(topicResults[2].warn.length, 0, 'unexpected warnings length');
+ assert.strictEqual(topicResults[2].err.length, 0, 'unexpected errors length');
+ assert.strictEqual(topicResults[2].topicId, 222, 'unexpected topic id');
+ });
+ it('mix of valid and invalid topics', async function () {
+ manager.db.topicGetByUrl.onCall(1).resolves().resolves({
+ id: 222,
+ });
+ Object.assign(data, testData.validPublishRootData);
+ data.url = ['https://example.com/first', 'not a url'];
+ data.topic = ['https://example.com/third'];
+ const topicResults = await manager._publishTopics(dbCtx, data, requestId);
+ assert.strictEqual(topicResults.length, 3);
+ assert.strictEqual(topicResults[0].warn.length, 0, 'unexpected warnings length');
+ assert.strictEqual(topicResults[0].err.length, 0, 'unexpected errors length');
+ assert.strictEqual(topicResults[0].topicId, 222, 'unexpected topic id');
+ assert.strictEqual(topicResults[1].warn.length, 0, 'unexpected warnings length');
+ assert.strictEqual(topicResults[1].err.length, 1, 'unexpected errors length');
+ assert.strictEqual(topicResults[1].topicId, undefined, 'unexpected topic id');
+ assert.strictEqual(topicResults[2].warn.length, 0, 'unexpected warnings length');
+ assert.strictEqual(topicResults[2].err.length, 0, 'unexpected errors length');
+ assert.strictEqual(topicResults[2].topicId, 222, 'unexpected topic id');
+ });
+ }); // _publishTopics
+
+ describe('_publishRequest', function () {
+ let dbCtx, data, res, ctx;
+ beforeEach(function () {
+ dbCtx = {};
+ data = {};
+ res = {
+ end: sinon.stub(),
+ };
+ ctx = {};
+ });
+ it('requires a topic', async function () {
+ try {
+ await manager._publishRequest(dbCtx, data, res, ctx);
+ assert.fail(noExpectedException);
+ } catch (e) {
+ assert(e instanceof Errors.ResponseError);
+ }
+ });
+ it('processes one topic', async function() {
+ manager.db.topicGetByUrl.resolves({
+ id: 222,
+ });
+ Object.assign(data, testData.validPublishRootData);
+ manager.db.topicFetchRequested.resolves();
+ await manager._publishRequest(dbCtx, data, res, ctx);
+ assert(manager.db.topicFetchRequested.called);
+ assert.strictEqual(res.statusCode, 202);
+ assert(res.end.called);
+ });
+ it('processes mix of valid and invalid topics', async function () {
+ ctx.responseType = 'application/json';
+ manager.db.topicGetByUrl.onCall(1).resolves().resolves({
+ id: 222,
+ });
+ Object.assign(data, testData.validPublishRootData);
+ data.url = ['https://example.com/first', 'not a url'];
+ data.topic = ['https://example.com/third'];
+ await manager._publishRequest(dbCtx, data, res, ctx);
+ assert.strictEqual(res.statusCode, 207);
+ assert(res.end.called);
+ });
+ it('covers topicFetchRequest failure', async function () {
+ manager.db.topicGetByUrl.resolves({
+ id: 222,
+ });
+ Object.assign(data, testData.validPublishRootData);
+ const expected = new Error('boo');
+ manager.db.topicFetchRequested.rejects(expected);
+ try {
+ await manager._publishRequest(dbCtx, data, res, ctx);
+ assert.fail(noExpectedException);
+ } catch (e) {
+ assert.deepStrictEqual(e, expected);
+ }
});
- }); // _checkPublish
+ it('covers immediate processing error', async function() {
+ manager.options.manager.processImmediately = true;
+ manager.db.topicGetByUrl.onCall(0).resolves().onCall(1).resolves({
+ id: 222,
+ });
+ manager.communication.topicFetchClaimAndProcessById.rejects();
+ Object.assign(data, testData.validPublishRootData);
+ await manager._publishRequest(dbCtx, data, res, ctx);
+ assert(manager.db.topicFetchRequested.called);
+ assert.strictEqual(res.statusCode, 202);
+ assert(res.end.called);
+ assert(manager.communication.topicFetchClaimAndProcessById.called)
+ });
+ it('covers no immediate processing', async function() {
+ manager.options.manager.processImmediately = false;
+ manager.db.topicGetByUrl.onCall(0).resolves().onCall(1).resolves({
+ id: 222,
+ });
+ Object.assign(data, testData.validPublishRootData);
+ await manager._publishRequest(dbCtx, data, res, ctx);
+ assert(manager.db.topicFetchRequested.called);
+ assert.strictEqual(res.statusCode, 202);
+ assert(res.end.called);
+ assert(!manager.communication.topicFetchClaimAndProcessById.called)
+ });
+ }); // _publishRequest
+
+ describe('multiPublishContent', function () {
+ let publishTopics;
+ beforeEach(function () {
+ publishTopics = [{
+ url: 'https://example.com/first',
+ warn: [],
+ err: [],
+ topicId: 222,
+ status: 202,
+ statusMessage: 'Accepted',
+ },
+ {
+ url: 'not a url',
+ warn: [],
+ err: [ 'invalid topic url (failed to parse url)' ],
+ topicId: undefined,
+ status: 400,
+ statusMessage: 'Bad Request',
+ }];
+ });
+ it('covers json response', function () {
+ ctx.responseType = 'application/json';
+ const expected = '[{"href":"https://example.com/first","status":202,"statusMessage":"Accepted","errors":[],"warnings":[]},{"href":"not a url","status":400,"statusMessage":"Bad Request","errors":["invalid topic url (failed to parse url)"],"warnings":[]}]';
+ const result = Manager.multiPublishContent(ctx, publishTopics);
+ assert.deepStrictEqual(result, expected);
+ });
+ it('covers text response', function () {
+ ctx.responseType = 'text/plain';
+ const expected = `https://example.com/first [202 Accepted]
+----
+not a url [400 Bad Request]
+\terror: invalid topic url (failed to parse url)`;
+ const result = Manager.multiPublishContent(ctx, publishTopics);
+ assert.deepStrictEqual(result, expected);
+ });
+ }); // multiPublishContent
describe('processTasks', function () {
it('covers', async function () {