ef4790542cd147a076a0fdc11985da6641f10b64
1 /* eslint-disable sonarjs/no-identical-functions */
3 /* eslint-disable sonarjs/no-duplicate-string */
6 /* This provides implementation coverage, stubbing pg-promise. */
8 const assert
= require('assert');
9 // eslint-disable-next-line node/no-unpublished-require
10 const sinon
= require('sinon');
11 const DBStub
= require('../../stub-db');
12 const stubLogger
= require('../../stub-logger');
13 const DB
= require('../../../src/db/postgres');
14 const DBErrors
= require('../../../src/db/errors');
15 const common
= require('../../../src/common');
16 const Config
= require('../../../config');
18 const noExpectedException
= 'did not receive expected exception';
20 describe('DatabasePostgres', function () {
21 let db
, options
, pgpStub
;
22 let dbCtx
, claimant
, claimTimeoutSeconds
, callback
, subscriptionId
, topicId
, verificationId
;
23 let topicUrl
, leaseSeconds
, secret
, httpRemoteAddr
, httpFrom
, retryDelays
, wanted
;
27 result: () => ({ rows: [] }),
32 manyOrNone: common
.nop
,
33 oneOrNone: common
.nop
,
36 multiResult: common
.nop
,
39 stub
.tx
= (fn
) => fn(stub
);
40 stub
.txIf
= (fn
) => fn(stub
);
41 stub
.task
= (fn
) => fn(stub
);
47 pgpStub
.QueryFile
= class {};
48 pgpStub
.end
= common
.nop
,
49 options
= new Config('test');
50 db
= new DB(stubLogger
, options
, pgpStub
);
52 beforeEach(function () {
55 claimant
= '19af19b8-6be3-4a6f-8946-65f5f1ccc5d7';
56 claimTimeoutSeconds
= 300;
57 subscriptionId
= 'fbaf8f19-ed9c-4a21-89ae-98b7005e3bf6';
58 topicUrl
= 'https://example.com/blog';
59 callback
= 'https://example.com/callback?id=123';
60 topicId
= 'c59d4bda-10ad-41d9-99df-4ce8bc331424';
61 verificationId
= '55cd7748-d2d5-11eb-b355-0025905f714a';
65 httpRemoteAddr
= '127.0.0.1';
66 httpFrom
= 'user@example.com';
69 afterEach(function () {
73 it('covers listener', function () {
74 const listenerOptions
= new Config('test');
75 listenerOptions
.db
.cacheEnabled
= true;
76 const listenerDb
= new DB(stubLogger
, listenerOptions
, pgpStub
);
80 // Ensure all interface methods are implemented
81 describe('Implementation', function () {
82 it('implements interface', async
function () {
83 const results
= await Promise
.allSettled(DBStub
._implementation
.map(async (fn
) => {
85 // eslint-disable-next-line security/detect-object-injection
88 assert(!(e
instanceof DBErrors
.NotImplemented
), `${fn} not implemented`);
91 const failures
= results
.filter((x
) => x
.status
=== 'rejected');
92 assert(!failures
.length
, failures
.map((x
) => {
93 x
= x
.reason
.toString();
94 return x
.slice(x
.indexOf(': '));
99 describe('pgpInitOptions', function () {
100 describe('error', function () {
101 it('covers', function () {
104 db
.pgpInitOptions
.error(err
, event
);
105 assert(db
.logger
.error
.called
);
108 describe('query', function () {
109 it('covers', function () {
111 db
.pgpInitOptions
.query(event
);
112 assert(db
.logger
.debug
.called
);
114 it('covers NOTIFY', function () {
115 const event
= { query: 'NOTIFY thing' };
116 db
.pgpInitOptions
.query(event
);
117 assert(!db
.logger
.debug
.called
);
120 describe('receive', function () {
121 it('covers', function () {
124 column_one: 'one', // eslint-disable-line camelcase
125 column_two: 2, // eslint-disable-line camelcase
128 column_one: 'foo', // eslint-disable-line camelcase
129 column_two: 4, // eslint-disable-line camelcase
134 const expectedData
= [
144 db
.pgpInitOptions
.receive(data
, result
, event
)
145 assert(db
.logger
.debug
.called
);
146 assert
.deepStrictEqual(data
, expectedData
);
148 it('covers NOTIFY', function () {
151 column_one: 'one', // eslint-disable-line camelcase
152 column_two: 2, // eslint-disable-line camelcase
155 column_one: 'foo', // eslint-disable-line camelcase
156 column_two: 4, // eslint-disable-line camelcase
163 const expectedData
= [
173 db
.pgpInitOptions
.receive(data
, result
, event
)
174 assert(!db
.logger
.debug
.called
);
175 assert
.deepStrictEqual(data
, expectedData
);
178 }); // pgpInitOptions
180 describe('_initTables', function () {
181 beforeEach(function () {
182 sinon
.stub(db
.db
, 'oneOrNone');
183 sinon
.stub(db
.db
, 'multiResult');
184 sinon
.stub(db
, '_currentSchema');
187 it('covers apply', async
function() {
188 db
.db
.oneOrNone
.onCall(0).resolves(null).onCall(1).resolves({});
189 db
._currentSchema
.resolves({ major: 0, minor: 0, patch: 0 });
190 await db
._initTables();
192 it('covers exists', async
function() {
193 db
.db
.oneOrNone
.resolves({});
194 db
._currentSchema
.resolves(db
.schemaVersionsSupported
.max
);
195 await db
._initTables();
199 describe('initialize', function () {
203 it('passes supported version', async
function () {
204 const version
= { major: 1, minor: 0, patch: 0 };
205 sinon
.stub(db
.db
, 'one').resolves(version
);
206 await db
.initialize(false);
208 it('fails low version', async
function () {
209 const version
= { major: 0, minor: 0, patch: 0 };
210 sinon
.stub(db
.db
, 'one').resolves(version
);
212 await db
.initialize(false);
213 assert
.fail(noExpectedException
);
215 assert(e
instanceof DBErrors
.MigrationNeeded
);
218 it('fails high version', async
function () {
219 const version
= { major: 100, minor: 100, patch: 100 };
220 sinon
.stub(db
.db
, 'one').resolves(version
);
222 await db
.initialize(false);
223 assert
.fail(noExpectedException
);
225 assert(e
instanceof DBErrors
.MigrationNeeded
);
228 it('covers migration', async
function() {
229 sinon
.stub(db
.db
, 'oneOrNone').resolves({});
230 sinon
.stub(db
.db
, 'multiResult');
231 sinon
.stub(db
, '_currentSchema').resolves(db
.schemaVersionsSupported
.max
);
232 sinon
.stub(db
.db
, 'one').resolves(db
.schemaVersionsSupported
.max
);
233 await db
.initialize();
235 it('covers listener', async
function() {
239 const version
= { major: 1, minor: 0, patch: 0 };
240 sinon
.stub(db
.db
, 'one').resolves(version
);
241 await db
.initialize(false);
242 assert(db
.listener
.start
.called
);
246 describe('healthCheck', function () {
247 beforeEach(function () {
248 sinon
.stub(db
.db
, 'connect').resolves({
251 serverVersion: '0.0',
255 it('covers', async
function () {
256 const result
= await db
.healthCheck();
257 assert
.deepStrictEqual(result
, { serverVersion: '0.0' });
261 describe('_queryFileHelper', function () {
262 it('covers success', function () {
263 const _queryFile
= db
._queryFileHelper(pgpStub
);
266 it('covers failure', function () {
267 const err
= new Error();
268 pgpStub
.QueryFile
= class {
273 const _queryFile
= db
._queryFileHelper(pgpStub
);
276 assert
.fail(noExpectedException
);
278 assert
.strictEqual(e
, err
);
281 }); // _queryFileHelper
283 describe('_closeConnection', function () {
287 it('success', async
function () {
288 sinon
.stub(db
._pgp
, 'end');
289 await db
._closeConnection();
290 assert(db
._pgp
.end
.called
);
292 it('failure', async
function () {
293 const expected
= new Error();
294 sinon
.stub(db
._pgp
, 'end').throws(expected
);
296 await db
._closeConnection();
297 assert
.fail(noExpectedException
);
299 assert
.deepStrictEqual(e
, expected
);
302 it('covers listener', async
function () {
306 sinon
.stub(db
._pgp
, 'end');
307 await db
._closeConnection();
308 assert(db
._pgp
.end
.called
);
310 }); // _closeConnection
312 describe('_purgeTables', function () {
313 it('covers not really', async
function () {
314 sinon
.stub(db
.db
, 'tx');
315 await db
._purgeTables(false);
316 assert(!db
.db
.tx
.called
);
318 it('success', async
function () {
319 sinon
.stub(db
.db
, 'batch');
320 await db
._purgeTables(true);
321 assert(db
.db
.batch
.called
);
323 it('failure', async
function () {
324 const expected
= new Error();
325 sinon
.stub(db
.db
, 'tx').rejects(expected
);
327 await db
._purgeTables(true);
328 assert
.fail(noExpectedException
);
330 assert
.deepStrictEqual(e
, expected
);
335 describe('_topicChanged', function () {
336 beforeEach(function () {
337 db
.cache
= new Map();
338 sinon
.stub(db
.cache
, 'delete');
343 it('covers', function () {
344 db
._topicChanged('topic-id');
345 assert(db
.cache
.delete.called
);
347 it('ignores ping', function () {
348 db
._topicChanged('ping');
349 assert(!db
.cache
.delete.called
);
353 describe('_listenerEstablished', function () {
354 it('creates cache', function () {
356 db
._listenerEstablished();
357 assert(db
.cache
instanceof Map
);
359 }); // _listenerEstablished
361 describe('_listenerLost', function () {
362 it('removes cache', function () {
363 db
.cache
= new Map();
369 describe('_cacheGet', function () {
371 beforeEach(function () {
374 it('nothing if no cache', function () {
376 const result
= db
._cacheGet(key
);
377 assert
.strictEqual(result
, undefined);
379 it('nothing if no entry', function () {
380 db
.cache
= new Map();
381 const result
= db
._cacheGet(key
);
382 assert
.strictEqual(result
, undefined);
384 it('returns cached entry', function () {
385 db
.cache
= new Map();
389 db
._cacheSet(key
, expected
);
390 const result
= db
._cacheGet(key
);
391 assert
.deepStrictEqual(result
, expected
);
395 describe('_cacheSet', function () {
397 beforeEach(function () {
400 it('covers no cache', function () {
402 db
._cacheSet(key
, 'data');
404 it('covers cache', function () {
405 db
.cache
= new Map();
406 const expected
= 'blah';
407 db
._cacheSet(key
, expected
);
408 const result
= db
._cacheGet(key
);
409 assert
.deepStrictEqual(result
, expected
);
413 describe('context', function () {
414 it('covers', async
function () {
415 await db
.context(common
.nop
);
419 describe('transaction', function () {
420 it('covers', async
function () {
421 await db
.transaction(db
.db
, common
.nop
);
425 describe('authenticationSuccess', function () {
427 beforeEach(function () {
428 identifier
= 'username';
430 it('success', async
function () {
436 sinon
.stub(db
.db
, 'result').resolves(dbResult
);
437 await db
.authenticationSuccess(dbCtx
, identifier
);
439 it('failure', async
function() {
445 sinon
.stub(db
.db
, 'result').resolves(dbResult
);
447 await db
.authenticationSuccess(dbCtx
, identifier
);
448 assert
.fail(noExpectedException
);
450 assert(e
instanceof DBErrors
.UnexpectedResult
);
453 }); // authenticationSuccess
455 describe('authenticationGet', function () {
456 let identifier
, credential
;
457 beforeEach(function () {
458 identifier
= 'username';
459 credential
= '$z$foo';
461 it('success', async
function () {
462 const dbResult
= { identifier
, credential
};
463 sinon
.stub(db
.db
, 'oneOrNone').resolves(dbResult
);
464 const result
= await db
.authenticationGet(dbCtx
, identifier
);
465 assert
.deepStrictEqual(result
, dbResult
);
467 it('failure', async
function() {
468 const expected
= new Error('blah');
469 sinon
.stub(db
.db
, 'oneOrNone').rejects(expected
);
471 await db
.authenticationGet(dbCtx
, identifier
, credential
);
472 assert
.fail(noExpectedException
);
474 assert
.deepStrictEqual(e
, expected
);
477 }); // authenticationGet
479 describe('authenticationUpsert', function () {
480 let identifier
, credential
;
481 beforeEach(function () {
482 identifier
= 'username';
483 credential
= '$z$foo';
485 it('success', async
function () {
491 sinon
.stub(db
.db
, 'result').resolves(dbResult
);
492 await db
.authenticationUpsert(dbCtx
, identifier
, credential
);
494 it('failure', async
function() {
495 credential
= undefined;
501 sinon
.stub(db
.db
, 'result').resolves(dbResult
);
503 await db
.authenticationUpsert(dbCtx
, identifier
, credential
);
504 assert
.fail(noExpectedException
);
506 assert(e
instanceof DBErrors
.UnexpectedResult
);
509 }); // authenticationUpsert
511 describe('subscriptionsByTopicId', function () {
512 it('success', async
function () {
514 sinon
.stub(db
.db
, 'manyOrNone').resolves(expected
);
515 const result
= await db
.subscriptionsByTopicId(dbCtx
, topicUrl
);
516 assert
.deepStrictEqual(result
, expected
);
518 it('failure', async
function () {
519 const expected
= new Error();
520 sinon
.stub(db
.db
, 'manyOrNone').throws(expected
);
522 await db
.subscriptionsByTopicId(dbCtx
, topicUrl
);
523 assert
.fail(noExpectedException
);
525 assert
.deepStrictEqual(e
, expected
);
528 }); // subscriptionsByTopicId
530 describe('subscriptionCountByTopicUrl', function () {
531 it('success', async
function () {
532 const expected
= { count: 3 };
533 sinon
.stub(db
.db
, 'one').resolves(expected
);
534 const result
= await db
.subscriptionCountByTopicUrl(dbCtx
, topicUrl
);
535 assert
.deepStrictEqual(result
, expected
);
537 it('failure', async
function () {
538 const expected
= new Error();
539 sinon
.stub(db
.db
, 'one').throws(expected
);
541 await db
.subscriptionCountByTopicUrl(dbCtx
, topicUrl
);
542 assert
.fail(noExpectedException
);
544 assert
.deepStrictEqual(e
, expected
);
547 }); // subscriptionCountByTopicUrl
549 describe('subscriptionDelete', function () {
550 it('success', async
function() {
558 lastInsertRowid: undefined,
561 sinon
.stub(db
.db
, 'result').resolves(dbResult
);
562 const result
= await db
.subscriptionDelete(dbCtx
, callback
, topicId
);
563 assert
.deepStrictEqual(result
, expected
);
565 it('failure', async
function () {
566 const expected
= new Error();
567 sinon
.stub(db
.db
, 'result').throws(expected
);
569 await db
.subscriptionDelete(dbCtx
, callback
, topicId
);
570 assert
.fail(noExpectedException
);
572 assert
.deepStrictEqual(e
, expected
);
575 }); // subscriptionDelete
577 describe('subscriptionDeliveryClaim', function () {
578 it('success', async
function() {
581 id: 'c2e254c5-aa6e-4a8f-b1a1-e474b07392bb',
584 const expected
= ['c2e254c5-aa6e-4a8f-b1a1-e474b07392bb'];
585 sinon
.stub(db
.db
, 'manyOrNone').resolves(dbResult
);
586 const result
= await db
.subscriptionDeliveryClaim(dbCtx
, wanted
, claimTimeoutSeconds
, claimant
);
587 assert
.deepStrictEqual(result
, expected
);
589 it('failure', async
function () {
590 const expected
= new Error();
591 sinon
.stub(db
.db
, 'manyOrNone').throws(expected
);
593 await db
.subscriptionDeliveryClaim(dbCtx
, wanted
, claimTimeoutSeconds
, claimant
);
594 assert
.fail(noExpectedException
);
596 assert
.deepStrictEqual(e
, expected
);
599 }); // subscriptionDeliveryClaim
601 describe('subscriptionDeliveryClaimById', function () {
602 it('success', async
function() {
605 rows: [{ id: 'c2e254c5-aa6e-4a8f-b1a1-e474b07392bb' }],
610 lastInsertRowid: 'c2e254c5-aa6e-4a8f-b1a1-e474b07392bb',
613 sinon
.stub(db
.db
, 'result').resolves(dbResult
);
614 const result
= await db
.subscriptionDeliveryClaimById(dbCtx
, subscriptionId
, claimTimeoutSeconds
, claimant
);
615 assert
.deepStrictEqual(result
, expected
);
617 it('failure', async
function () {
623 sinon
.stub(db
.db
, 'result').resolves(dbResult
);
625 await db
.subscriptionDeliveryClaimById(dbCtx
, callback
, topicId
);
626 assert
.fail(noExpectedException
);
628 assert(e
instanceof DBErrors
.UnexpectedResult
);
631 }); // subscriptionDeliveryClaimById
633 describe('subscriptionDeliveryComplete', function () {
634 it('success', async
function() {
638 sinon
.stub(db
.db
, 'result').resolves(dbResult
);
639 await db
.subscriptionDeliveryComplete(dbCtx
, callback
, topicId
);
641 it('failure', async
function () {
645 sinon
.stub(db
.db
, 'result').onCall(0).resolves(dbResult
);
647 await db
.subscriptionDeliveryComplete(dbCtx
, callback
, topicId
);
648 assert
.fail(noExpectedException
);
650 assert(e
instanceof DBErrors
.UnexpectedResult
);
653 it('second failure', async
function () {
660 sinon
.stub(db
.db
, 'result').onCall(0).resolves(dbResult0
).onCall(1).resolves(dbResult1
);
662 await db
.subscriptionDeliveryComplete(dbCtx
, callback
, topicId
);
663 assert
.fail(noExpectedException
);
665 assert(e
instanceof DBErrors
.UnexpectedResult
);
668 }); // subscriptionDeliveryComplete
670 describe('subscriptionDeliveryGone', function () {
671 it('success', async
function() {
675 sinon
.stub(db
.db
, 'result').resolves(dbResult
);
676 await db
.subscriptionDeliveryGone(dbCtx
, callback
, topicId
);
678 it('failure', async
function () {
682 sinon
.stub(db
.db
, 'result').resolves(dbResult
);
684 await db
.subscriptionDeliveryGone(dbCtx
, callback
, topicId
);
685 assert
.fail(noExpectedException
);
687 assert(e
instanceof DBErrors
.UnexpectedResult
);
690 }); // subscriptionDeliveryGone
692 describe('subscriptionDeliveryIncomplete', function () {
693 it('success', async
function() {
694 const dbOne
= { deliveryAttemptsSinceSuccess: 0 };
698 sinon
.stub(db
.db
, 'one').resolves(dbOne
);
699 sinon
.stub(db
.db
, 'result').resolves(dbResult
);
700 await db
.subscriptionDeliveryIncomplete(dbCtx
, callback
, topicId
, retryDelays
);
702 it('success covers default', async
function() {
703 const dbOne
= { deliveryAttemptsSinceSuccess: 0 };
707 sinon
.stub(db
.db
, 'one').resolves(dbOne
);
708 sinon
.stub(db
.db
, 'result').resolves(dbResult
);
709 await db
.subscriptionDeliveryIncomplete(dbCtx
, callback
, topicId
);
711 it('failure', async
function () {
712 const dbOne
= { deliveryAttemptsSinceSuccess: 0 };
716 sinon
.stub(db
.db
, 'one').resolves(dbOne
);
717 sinon
.stub(db
.db
, 'result').resolves(dbResult
);
719 await db
.subscriptionDeliveryIncomplete(dbCtx
, callback
, topicId
, retryDelays
);
720 assert
.fail(noExpectedException
);
722 assert(e
instanceof DBErrors
.UnexpectedResult
);
725 it('second failure', async
function () {
726 const dbOne
= { deliveryAttemptsSinceSuccess: 0 };
733 sinon
.stub(db
.db
, 'one').resolves(dbOne
);
734 sinon
.stub(db
.db
, 'result').onCall(0).resolves(dbResult0
).onCall(1).resolves(dbResult1
);
736 await db
.subscriptionDeliveryIncomplete(dbCtx
, callback
, topicId
, retryDelays
);
737 assert
.fail(noExpectedException
);
739 assert(e
instanceof DBErrors
.UnexpectedResult
);
742 }); // subscriptionDeliveryIncomplete
744 describe('subscriptionGet', function () {
745 it('success', async
function() {
749 sinon
.stub(db
.db
, 'oneOrNone').resolves(expected
);
750 const result
= await db
.subscriptionGet(dbCtx
, callback
, topicId
);
751 assert
.deepStrictEqual(result
, expected
);
753 it('failure', async
function () {
754 const expected
= new Error();
755 sinon
.stub(db
.db
, 'oneOrNone').throws(expected
);
757 await db
.subscriptionGet(dbCtx
, callback
, topicId
);
758 assert
.fail(noExpectedException
);
760 assert
.deepStrictEqual(e
, expected
);
763 }); // subscriptionGet
765 describe('subscriptionGetById', function () {
766 it('success', async
function() {
770 sinon
.stub(db
.db
, 'oneOrNone').resolves(expected
);
771 const result
= await db
.subscriptionGetById(dbCtx
, subscriptionId
);
772 assert
.deepStrictEqual(result
, expected
);
774 it('failure', async
function () {
775 const expected
= new Error();
776 sinon
.stub(db
.db
, 'oneOrNone').throws(expected
);
778 await db
.subscriptionGetById(dbCtx
, subscriptionId
);
779 assert
.fail(noExpectedException
);
781 assert
.deepStrictEqual(e
, expected
);
784 }); // subscriptionGetById
786 describe('subscriptionUpsert', function () {
788 beforeEach(function () {
798 it('success', async
function() {
801 rows: [{ id: subscriptionId
}],
806 lastInsertRowid: subscriptionId
,
809 sinon
.stub(db
.db
, 'result').resolves(dbResult
);
810 const result
= await db
.subscriptionUpsert(dbCtx
, data
);
811 assert
.deepStrictEqual(result
, expected
);
813 it('failure', async
function () {
817 sinon
.stub(db
.db
, 'result').resolves(dbResult
);
819 await db
.subscriptionUpsert(dbCtx
, data
);
820 assert
.fail(noExpectedException
);
822 assert(e
instanceof DBErrors
.UnexpectedResult
);
825 }); // subscriptionUpsert
827 describe('subscriptionUpdate', function () {
829 beforeEach(function () {
831 signatureAlgorithm: 'sha256',
834 it('success', async
function() {
840 sinon
.stub(db
.db
, 'result').resolves(dbResult
);
841 await db
.subscriptionUpdate(dbCtx
, data
);
843 it('failure', async
function () {
847 sinon
.stub(db
.db
, 'result').resolves(dbResult
);
849 await db
.subscriptionUpdate(dbCtx
, data
);
850 assert
.fail(noExpectedException
);
852 assert(e
instanceof DBErrors
.UnexpectedResult
);
855 }); // subscriptionUpdate
857 describe('topicDeleted', function () {
858 it('success', async
function() {
862 sinon
.stub(db
.db
, 'result').resolves(dbResult
);
863 await db
.topicDeleted(dbCtx
, topicId
);
865 it('failure', async
function() {
869 sinon
.stub(db
.db
, 'result').resolves(dbResult
);
871 await db
.topicDeleted(dbCtx
, topicId
);
872 assert
.fail(noExpectedException
);
874 assert(e
instanceof DBErrors
.UnexpectedResult
);
879 describe('topicFetchClaim', function () {
880 it('success', async
function() {
881 const dbResult
= [{ id: topicId
}];
882 const expected
= [topicId
];
883 sinon
.stub(db
.db
, 'manyOrNone').resolves(dbResult
);
884 const result
= await db
.topicFetchClaim(dbCtx
, wanted
, claimTimeoutSeconds
, claimant
);
885 assert
.deepStrictEqual(result
, expected
);
887 it('failure', async
function () {
888 const expected
= new Error();
889 sinon
.stub(db
.db
, 'manyOrNone').throws(expected
);
891 await db
.topicFetchClaim(dbCtx
, wanted
, claimTimeoutSeconds
, claimant
);
892 assert
.fail(noExpectedException
);
894 assert
.deepStrictEqual(e
, expected
);
897 }); // topicFetchClaim
899 describe('topicFetchClaimById', function () {
900 it('success', async
function() {
908 lastInsertRowid: undefined,
911 sinon
.stub(db
.db
, 'result').resolves(dbResult
);
912 const result
= await db
.topicFetchClaimById(dbCtx
, topicId
, claimTimeoutSeconds
, claimant
);
913 assert
.deepStrictEqual(result
, expected
);
915 it('failure', async
function () {
916 const expected
= new Error();
917 sinon
.stub(db
.db
, 'result').throws(expected
);
919 await db
.topicFetchClaimById(dbCtx
, topicId
, claimTimeoutSeconds
, claimant
);
920 assert
.fail(noExpectedException
);
922 assert
.deepStrictEqual(e
, expected
);
925 }); // topicFetchClaimById
927 describe('topicFetchComplete', function () {
928 it('success', async
function() {
934 sinon
.stub(db
.db
, 'result').resolves(dbResult
);
935 await db
.topicFetchComplete(dbCtx
, topicId
);
937 it('failure', async
function () {
943 sinon
.stub(db
.db
, 'result').resolves(dbResult
);
945 await db
.topicFetchComplete(dbCtx
, topicId
);
946 assert
.fail(noExpectedException
);
948 assert(e
instanceof DBErrors
.UnexpectedResult
);
951 it('second failure', async
function () {
962 sinon
.stub(db
.db
, 'result').onCall(0).resolves(dbResult0
).onCall(1).resolves(dbResult1
);
964 await db
.topicFetchComplete(dbCtx
, topicId
);
965 assert
.fail(noExpectedException
);
967 assert(e
instanceof DBErrors
.UnexpectedResult
);
970 }); // topicFetchComplete
972 describe('topicFetchIncomplete', function () {
973 it('success', async
function() {
974 const dbOne
= { currentAttempt: 0 };
987 lastInsertRowid: undefined,
990 sinon
.stub(db
.db
, 'one').resolves(dbOne
);
991 sinon
.stub(db
.db
, 'result').onCall(0).resolves(dbResult0
).onCall(1).resolves(dbResult1
);
992 const result
= await db
.topicFetchIncomplete(dbCtx
, topicId
, retryDelays
);
993 assert
.deepStrictEqual(result
, expected
);
995 it('covers defaults', async
function() {
996 const dbOne
= { currentAttempt: 0 };
1009 lastInsertRowid: undefined,
1012 sinon
.stub(db
.db
, 'one').resolves(dbOne
);
1013 sinon
.stub(db
.db
, 'result').onCall(0).resolves(dbResult0
).onCall(1).resolves(dbResult1
);
1014 const result
= await db
.topicFetchIncomplete(dbCtx
, topicId
);
1015 assert
.deepStrictEqual(result
, expected
);
1017 it('failure', async
function () {
1018 const dbOne
= { currentAttempt: 0 };
1029 sinon
.stub(db
.db
, 'one').resolves(dbOne
);
1030 sinon
.stub(db
.db
, 'result').onCall(0).resolves(dbResult0
).onCall(1).resolves(dbResult1
);
1032 await db
.topicFetchIncomplete(dbCtx
, topicId
, retryDelays
);
1033 assert
.fail(noExpectedException
);
1035 assert(e
instanceof DBErrors
.UnexpectedResult
);
1038 it('second failure', async
function () {
1039 const dbOne
= { currentAttempt: 0 };
1050 sinon
.stub(db
.db
, 'one').resolves(dbOne
);
1051 sinon
.stub(db
.db
, 'result').onCall(0).resolves(dbResult0
).onCall(1).resolves(dbResult1
);
1053 await db
.topicFetchIncomplete(dbCtx
, topicId
, retryDelays
);
1054 assert
.fail(noExpectedException
);
1056 assert(e
instanceof DBErrors
.UnexpectedResult
);
1059 }); // topicFetchIncomplete
1061 describe('topicFetchRequested', function () {
1062 it('success', async
function() {
1070 lastInsertRowid: undefined,
1073 sinon
.stub(db
.db
, 'result').resolves(dbResult
);
1074 const result
= await db
.topicFetchRequested(dbCtx
, topicId
);
1075 assert
.deepStrictEqual(result
, expected
);
1077 it('failure', async
function () {
1083 sinon
.stub(db
.db
, 'result').resolves(dbResult
);
1085 await db
.topicFetchRequested(dbCtx
, topicId
);
1086 assert
.fail(noExpectedException
);
1088 assert(e
instanceof DBErrors
.UnexpectedResult
);
1091 }); // topicFetchRequested
1093 describe('topicGetAll', function () {
1094 it('success', async
function() {
1095 const expected
= [{ id: topicId
}];
1096 sinon
.stub(db
.db
, 'manyOrNone').resolves(expected
);
1097 const result
= await db
.topicGetAll(dbCtx
);
1098 assert
.deepStrictEqual(result
, expected
);
1100 it('covers default', async
function() {
1101 const expected
= undefined;
1102 sinon
.stub(db
.db
, 'manyOrNone').resolves(expected
);
1103 const result
= await db
.topicGetAll(dbCtx
);
1104 assert
.deepStrictEqual(result
, expected
);
1106 it('failure', async
function () {
1107 const expected
= new Error();
1108 sinon
.stub(db
.db
, 'manyOrNone').throws(expected
);
1110 await db
.topicGetAll(dbCtx
);
1111 assert
.fail(noExpectedException
);
1113 assert
.deepStrictEqual(e
, expected
);
1118 describe('topicGetById', function () {
1119 it('success', async
function() {
1120 const expected
= { id: topicId
};
1121 sinon
.stub(db
.db
, 'oneOrNone').resolves(expected
);
1122 const result
= await db
.topicGetById(dbCtx
, topicId
);
1123 assert
.deepStrictEqual(result
, expected
);
1125 it('covers none', async
function() {
1126 const expected
= undefined;
1127 sinon
.stub(db
.db
, 'oneOrNone').resolves(expected
);
1128 const result
= await db
.topicGetById(dbCtx
, topicId
);
1129 assert
.deepStrictEqual(result
, expected
);
1131 it('covers no defaults', async
function () {
1132 const expected
= { id: topicId
};
1133 sinon
.stub(db
.db
, 'oneOrNone').resolves(expected
);
1134 const result
= await db
.topicGetById(dbCtx
, topicId
, false);
1135 assert
.deepStrictEqual(result
, expected
);
1137 it('failure', async
function () {
1138 const expected
= new Error();
1139 sinon
.stub(db
.db
, 'oneOrNone').throws(expected
);
1141 await db
.topicGetById(dbCtx
, topicId
);
1142 assert
.fail(noExpectedException
);
1144 assert
.deepStrictEqual(e
, expected
);
1149 describe('topicGetByUrl', function () {
1150 it('success', async
function() {
1151 const expected
= [];
1152 sinon
.stub(db
.db
, 'oneOrNone').resolves(expected
);
1153 const result
= await db
.topicGetByUrl(dbCtx
, topicUrl
);
1154 assert
.deepStrictEqual(result
, expected
);
1156 it('failure', async
function () {
1157 const expected
= new Error();
1158 sinon
.stub(db
.db
, 'oneOrNone').throws(expected
);
1160 await db
.topicGetByUrl(dbCtx
, topicUrl
);
1161 assert
.fail(noExpectedException
);
1163 assert
.deepStrictEqual(e
, expected
);
1166 }); // topicGetByUrl
1168 describe('topicGetContentById', function () {
1170 beforeEach(function () {
1176 it('success', async
function() {
1177 const expected
= topic
;
1178 sinon
.stub(db
.db
, 'oneOrNone').resolves(expected
);
1179 const result
= await db
.topicGetContentById(dbCtx
, topicId
);
1180 assert
.deepStrictEqual(result
, expected
);
1182 it('covers default', async
function() {
1183 const expected
= undefined;
1184 sinon
.stub(db
.db
, 'oneOrNone').resolves(expected
);
1185 const result
= await db
.topicGetContentById(dbCtx
, topicId
);
1186 assert
.deepStrictEqual(result
, expected
);
1188 it('failure', async
function () {
1189 const expected
= new Error();
1190 sinon
.stub(db
.db
, 'oneOrNone').throws(expected
);
1192 await db
.topicGetContentById(dbCtx
, topicId
);
1193 assert
.fail(noExpectedException
);
1195 assert
.deepStrictEqual(e
, expected
);
1198 it('caches success', async
function () {
1199 db
.cache
= new Map();
1200 const expected
= topic
;
1201 sinon
.stub(db
.db
, 'oneOrNone').resolves(expected
);
1202 const result
= await db
.topicGetContentById(dbCtx
, topicId
);
1203 assert
.deepStrictEqual(result
, expected
);
1205 it('covers cached entry', async
function() {
1207 db
.cache
= new Map();
1208 const expected
= topic
;
1209 sinon
.stub(db
.db
, 'oneOrNone').resolves(expected
);
1210 result
= await db
.topicGetContentById(dbCtx
, topicId
);
1211 assert
.deepStrictEqual(result
, expected
);
1212 result
= await db
.topicGetContentById(dbCtx
, topicId
);
1213 assert
.deepStrictEqual(result
, expected
);
1215 }); // topicGetContentById
1217 describe('topicSet', function () {
1219 beforeEach(function () {
1224 it('success', async
function() {
1227 rows: [{ id: topicId
}],
1232 lastInsertRowid: topicId
,
1235 sinon
.stub(db
.db
, 'result').resolves(dbResult
);
1236 const result
= await db
.topicSet(dbCtx
, data
);
1237 assert
.deepStrictEqual(result
, expected
);
1239 it('failure', async
function () {
1245 sinon
.stub(db
.db
, 'result').resolves(dbResult
);
1247 await db
.topicSet(dbCtx
, data
);
1248 assert
.fail(noExpectedException
);
1250 assert(e
instanceof DBErrors
.UnexpectedResult
);
1253 it('fails invalid value', async
function () {
1254 sinon
.stub(db
.db
, 'result');
1256 data
.leaseSecondsPreferred
= -100;
1257 await db
.topicSet(dbCtx
, data
);
1258 assert
.fail(noExpectedException
);
1260 assert(e
instanceof DBErrors
.DataValidation
);
1262 assert(!db
.db
.result
.called
);
1264 it('fails invalid values', async
function () {
1265 sinon
.stub(db
.db
, 'result');
1267 data
.leaseSecondsPreferred
= 10;
1268 data
.leaseSecondsMax
= 100;
1269 data
.leaseSecondsMin
= 50;
1270 await db
.topicSet(dbCtx
, data
);
1271 assert
.fail(noExpectedException
);
1273 assert(e
instanceof DBErrors
.DataValidation
);
1275 assert(!db
.db
.result
.called
);
1279 describe('topicSetContent', function () {
1281 beforeEach(function () {
1284 contentType: 'text/plain',
1285 contentHash: 'abc123',
1288 it('success', async
function() {
1296 lastInsertRowid: undefined,
1299 sinon
.stub(db
.db
, 'result').resolves(dbResult
);
1300 const result
= await db
.topicSetContent(dbCtx
, data
);
1301 assert
.deepStrictEqual(result
, expected
);
1303 it('failure', async
function () {
1309 sinon
.stub(db
.db
, 'result').resolves(dbResult
);
1311 await db
.topicSetContent(dbCtx
, data
);
1312 assert
.fail(noExpectedException
);
1314 assert(e
instanceof DBErrors
.UnexpectedResult
);
1317 }); // topicSetContent
1319 describe('topicUpdate', function () {
1321 beforeEach(function () {
1323 leaseSecondsPreferred: 123,
1324 leaseSecondsMin: 100,
1325 leaseSecondsMax: 1000,
1326 publisherValidationUrl: null,
1327 contentHashAlgorithm: 'sha256',
1330 it('success', async
function() {
1336 sinon
.stub(db
.db
, 'result').resolves(dbResult
);
1337 await db
.topicUpdate(dbCtx
, data
);
1339 it('failure', async
function () {
1345 sinon
.stub(db
.db
, 'result').resolves(dbResult
);
1347 await db
.topicUpdate(dbCtx
, data
);
1348 assert
.fail(noExpectedException
);
1350 assert(e
instanceof DBErrors
.UnexpectedResult
);
1356 describe('verificationClaim', function () {
1357 it('success', async
function() {
1358 const dbManyOrNone
= [{ id: verificationId
}];
1359 const expected
= [verificationId
];
1360 sinon
.stub(db
.db
, 'manyOrNone').resolves(dbManyOrNone
);
1361 const result
= await db
.verificationClaim(dbCtx
, wanted
, claimTimeoutSeconds
, claimant
);
1362 assert
.deepStrictEqual(result
, expected
);
1364 it('failure', async
function () {
1365 const expected
= new Error();
1366 sinon
.stub(db
.db
, 'manyOrNone').throws(expected
);
1368 await db
.verificationClaim(dbCtx
, wanted
, claimTimeoutSeconds
, claimant
);
1369 assert
.fail(noExpectedException
);
1371 assert
.deepStrictEqual(e
, expected
);
1374 }); // verificationClaim
1376 describe('verificationClaimById', function () {
1377 it('success', async
function() {
1380 rows: [ { id: verificationId
} ],
1385 lastInsertRowid: verificationId
,
1388 sinon
.stub(db
.db
, 'result').resolves(dbResult
);
1389 const result
= await db
.verificationClaimById(dbCtx
, verificationId
, claimTimeoutSeconds
, claimant
);
1390 assert
.deepStrictEqual(result
, expected
);
1392 it('failure', async
function () {
1393 const expected
= new Error();
1394 sinon
.stub(db
.db
, 'result').throws(expected
);
1396 await db
.verificationClaimById(dbCtx
, verificationId
, claimTimeoutSeconds
, claimant
);
1397 assert
.fail(noExpectedException
);
1399 assert
.deepStrictEqual(e
, expected
);
1402 }); // verificationClaimById
1404 describe('verificationComplete', function () {
1405 it('success', async
function() {
1411 sinon
.stub(db
.db
, 'result').resolves(dbResult
);
1412 await db
.verificationComplete(dbCtx
, verificationId
, callback
, topicId
);
1414 it('failure', async
function () {
1420 sinon
.stub(db
.db
, 'result').resolves(dbResult
);
1422 await db
.verificationComplete(dbCtx
, verificationId
, callback
, topicId
);
1423 assert
.fail(noExpectedException
);
1425 assert(e
instanceof DBErrors
.UnexpectedResult
);
1428 }); // verificationComplete
1430 describe('verificationGetById', function () {
1431 it('success', async
function() {
1432 const dbOneOrNone
= { id: verificationId
};
1433 const expected
= { id: verificationId
};
1434 sinon
.stub(db
.db
, 'oneOrNone').resolves(dbOneOrNone
);
1435 const result
= await db
.verificationGetById(dbCtx
, verificationId
);
1436 assert
.deepStrictEqual(result
, expected
);
1438 it('failure', async
function () {
1439 const expected
= new Error();
1440 sinon
.stub(db
.db
, 'oneOrNone').throws(expected
);
1442 await db
.verificationGetById(dbCtx
, verificationId
);
1443 assert
.fail(noExpectedException
);
1445 assert
.deepStrictEqual(e
, expected
);
1448 }); // verificationGetById
1450 describe('verificationIncomplete', function () {
1451 it('success', async
function() {
1452 const dbOne
= { attempts: 0 };
1463 sinon
.stub(db
.db
, 'one').resolves(dbOne
);
1464 sinon
.stub(db
.db
, 'result').onCall(0).resolves(dbResult0
).onCall(1).resolves(dbResult1
);
1465 await db
.verificationIncomplete(dbCtx
, verificationId
, retryDelays
);
1467 it('covers defaults', async
function() {
1468 const dbOne
= { attempts: 0 };
1479 sinon
.stub(db
.db
, 'one').resolves(dbOne
);
1480 sinon
.stub(db
.db
, 'result').onCall(0).resolves(dbResult0
).onCall(1).resolves(dbResult1
);
1481 await db
.verificationIncomplete(dbCtx
, verificationId
);
1483 it('failure', async
function () {
1484 const dbOne
= { attempts: 0 };
1495 sinon
.stub(db
.db
, 'one').resolves(dbOne
);
1496 sinon
.stub(db
.db
, 'result').onCall(0).resolves(dbResult0
).onCall(1).resolves(dbResult1
);
1498 await db
.verificationIncomplete(dbCtx
, verificationId
, retryDelays
);
1499 assert
.fail(noExpectedException
);
1501 assert(e
instanceof DBErrors
.UnexpectedResult
);
1504 it('second failure', async
function () {
1505 const dbOne
= { attempts: 0 };
1516 sinon
.stub(db
.db
, 'one').resolves(dbOne
);
1517 sinon
.stub(db
.db
, 'result').onCall(0).resolves(dbResult0
).onCall(1).resolves(dbResult1
);
1519 await db
.verificationIncomplete(dbCtx
, verificationId
, retryDelays
);
1520 assert
.fail(noExpectedException
);
1522 assert(e
instanceof DBErrors
.UnexpectedResult
);
1525 }); // verificationIncomplete
1527 describe('verificationInsert', function () {
1529 beforeEach(function () {
1534 isPublisherValidated: true,
1535 leaseSeconds: 86400,
1538 it('success', async
function() {
1541 rows: [{ id: verificationId
}],
1544 const expected
= verificationId
;
1545 sinon
.stub(db
.db
, 'result').resolves(dbResult
);
1546 const result
= await db
.verificationInsert(dbCtx
, verification
);
1547 assert
.deepStrictEqual(result
, expected
);
1549 it('failure', async
function () {
1555 sinon
.stub(db
.db
, 'result').resolves(dbResult
);
1557 await db
.verificationInsert(dbCtx
, verification
);
1558 assert
.fail(noExpectedException
);
1560 assert(e
instanceof DBErrors
.UnexpectedResult
);
1563 it('fails validation', async
function () {
1564 delete verification
.leaseSeconds
;
1566 await db
.verificationInsert(dbCtx
, verification
);
1567 assert
.fail(noExpectedException
);
1569 assert(e
instanceof DBErrors
.DataValidation
);
1572 }); // verificationInsert
1574 describe('verificationRelease', function () {
1575 it('success', async
function() {
1581 sinon
.stub(db
.db
, 'result').resolves(dbResult
);
1582 await db
.verificationRelease(dbCtx
, verificationId
);
1584 it('failure', async
function () {
1590 sinon
.stub(db
.db
, 'result').resolves(dbResult
);
1592 await db
.verificationRelease(dbCtx
, verificationId
);
1593 assert
.fail(noExpectedException
);
1595 assert(e
instanceof DBErrors
.UnexpectedResult
);
1598 }); // verificationRelease
1600 describe('verificationUpdate', function () {
1602 beforeEach(function () {
1605 isPublisherValidated: true,
1608 it('success', async
function() {
1614 sinon
.stub(db
.db
, 'result').resolves(dbResult
);
1615 await db
.verificationUpdate(dbCtx
, verificationId
, data
);
1617 it('failure', async
function () {
1623 sinon
.stub(db
.db
, 'result').resolves(dbResult
);
1625 await db
.verificationUpdate(dbCtx
, verificationId
, data
);
1626 assert
.fail(noExpectedException
);
1628 assert(e
instanceof DBErrors
.UnexpectedResult
, e
.name
);
1631 it('fails validation', async
function () {
1634 await db
.verificationUpdate(dbCtx
, verificationId
, data
);
1635 assert
.fail(noExpectedException
);
1637 assert(e
instanceof DBErrors
.DataValidation
);
1640 }); // verificationUpdate
1642 describe('verificationValidated', function () {
1643 it('success', async
function() {
1649 sinon
.stub(db
.db
, 'result').resolves(dbResult
);
1650 await db
.verificationValidated(dbCtx
, verificationId
);
1652 it('failure', async
function () {
1658 sinon
.stub(db
.db
, 'result').resolves(dbResult
);
1660 await db
.verificationValidated(dbCtx
, verificationId
);
1661 assert
.fail(noExpectedException
);
1663 assert(e
instanceof DBErrors
.UnexpectedResult
);
1666 }); // verificationValidated
1668 }); // DatabasePostgres