5df49fd662680fb2137adc32d8f7c77f2da7d986
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 // Ensure all interface methods are implemented
74 describe('Implementation', function () {
75 it('implements interface', async
function () {
76 const results
= await Promise
.allSettled(DBStub
._implementation
.map(async (fn
) => {
78 // eslint-disable-next-line security/detect-object-injection
81 assert(!(e
instanceof DBErrors
.NotImplemented
), `${fn} not implemented`);
84 const failures
= results
.filter((x
) => x
.status
=== 'rejected');
85 assert(!failures
.length
, failures
.map((x
) => {
86 x
= x
.reason
.toString();
87 return x
.slice(x
.indexOf(': '));
92 describe('pgpInitOptions', function () {
93 describe('error', function () {
94 it('covers', function () {
97 db
.pgpInitOptions
.error(err
, event
);
98 assert(db
.logger
.error
.called
);
101 describe('query', function () {
102 it('covers', function () {
104 db
.pgpInitOptions
.query(event
);
105 assert(db
.logger
.debug
.called
);
108 describe('receive', function () {
109 it('covers', function () {
112 column_one: 'one', // eslint-disable-line camelcase
113 column_two: 2, // eslint-disable-line camelcase
116 column_one: 'foo', // eslint-disable-line camelcase
117 column_two: 4, // eslint-disable-line camelcase
122 const expectedData
= [
132 db
.pgpInitOptions
.receive(data
, result
, event
)
133 assert(db
.logger
.debug
.called
);
134 assert
.deepStrictEqual(data
, expectedData
);
137 }); // pgpInitOptions
139 describe('_initTables', function () {
140 beforeEach(function () {
141 sinon
.stub(db
.db
, 'oneOrNone');
142 sinon
.stub(db
.db
, 'multiResult');
143 sinon
.stub(db
, '_currentSchema');
146 it('covers apply', async
function() {
147 db
.db
.oneOrNone
.onCall(0).resolves(null).onCall(1).resolves({});
148 db
._currentSchema
.resolves({ major: 0, minor: 0, patch: 0 });
149 await db
._initTables();
151 it('covers exists', async
function() {
152 db
.db
.oneOrNone
.resolves({});
153 db
._currentSchema
.resolves(db
.schemaVersionsSupported
.max
);
154 await db
._initTables();
158 describe('schemaCheck', function () {
159 it('passes supported version', async
function () {
160 const version
= { major: 1, minor: 0, patch: 0 };
161 sinon
.stub(db
.db
, 'one').resolves(version
);
162 await db
.schemaCheck(false);
164 it('fails low version', async
function () {
165 const version
= { major: 0, minor: 0, patch: 0 };
166 sinon
.stub(db
.db
, 'one').resolves(version
);
168 await db
.schemaCheck(false);
169 assert
.fail(noExpectedException
);
171 assert(e
instanceof DBErrors
.MigrationNeeded
);
174 it('fails high version', async
function () {
175 const version
= { major: 100, minor: 100, patch: 100 };
176 sinon
.stub(db
.db
, 'one').resolves(version
);
178 await db
.schemaCheck(false);
179 assert
.fail(noExpectedException
);
181 assert(e
instanceof DBErrors
.MigrationNeeded
);
184 it('covers migration', async
function() {
185 sinon
.stub(db
.db
, 'oneOrNone').resolves({});
186 sinon
.stub(db
.db
, 'multiResult');
187 sinon
.stub(db
, '_currentSchema').resolves(db
.schemaVersionsSupported
.max
);
188 sinon
.stub(db
.db
, 'one').resolves(db
.schemaVersionsSupported
.max
);
189 await db
.schemaCheck();
193 describe('healthCheck', function () {
194 beforeEach(function () {
195 sinon
.stub(db
.db
, 'connect').resolves({
198 serverVersion: '0.0',
202 it('covers', async
function () {
203 const result
= await db
.healthCheck();
204 assert
.deepStrictEqual(result
, { serverVersion: '0.0' });
208 describe('_queryFileHelper', function () {
209 it('covers success', function () {
210 const _queryFile
= db
._queryFileHelper(pgpStub
);
213 it('covers failure', function () {
214 const err
= new Error();
215 pgpStub
.QueryFile
= class {
220 const _queryFile
= db
._queryFileHelper(pgpStub
);
223 assert
.fail(noExpectedException
);
225 assert
.strictEqual(e
, err
);
228 }); // _queryFileHelper
230 describe('_closeConnection', function () {
231 it('success', async
function () {
232 sinon
.stub(db
._pgp
, 'end');
233 await db
._closeConnection();
234 assert(db
._pgp
.end
.called
);
236 it('failure', async
function () {
237 const expected
= new Error();
238 sinon
.stub(db
._pgp
, 'end').throws(expected
);
240 await db
._closeConnection();
241 assert
.fail(noExpectedException
);
243 assert
.deepStrictEqual(e
, expected
);
246 }); // _closeConnection
248 describe('_purgeTables', function () {
249 it('covers not really', async
function () {
250 sinon
.stub(db
.db
, 'tx');
251 await db
._purgeTables(false);
252 assert(!db
.db
.tx
.called
);
254 it('success', async
function () {
255 sinon
.stub(db
.db
, 'batch');
256 await db
._purgeTables(true);
257 assert(db
.db
.batch
.called
);
259 it('failure', async
function () {
260 const expected
= new Error();
261 sinon
.stub(db
.db
, 'tx').rejects(expected
);
263 await db
._purgeTables(true);
264 assert
.fail(noExpectedException
);
266 assert
.deepStrictEqual(e
, expected
);
271 describe('context', function () {
272 it('covers', async
function () {
273 await db
.context(common
.nop
);
277 describe('transaction', function () {
278 it('covers', async
function () {
279 await db
.transaction(db
.db
, common
.nop
);
283 describe('authenticationSuccess', function () {
285 beforeEach(function () {
286 identifier
= 'username';
288 it('success', async
function () {
294 sinon
.stub(db
.db
, 'result').resolves(dbResult
);
295 await db
.authenticationSuccess(dbCtx
, identifier
);
297 it('failure', async
function() {
303 sinon
.stub(db
.db
, 'result').resolves(dbResult
);
305 await db
.authenticationSuccess(dbCtx
, identifier
);
306 assert
.fail(noExpectedException
);
308 assert(e
instanceof DBErrors
.UnexpectedResult
);
311 }); // authenticationSuccess
313 describe('authenticationGet', function () {
314 let identifier
, credential
;
315 beforeEach(function () {
316 identifier
= 'username';
317 credential
= '$z$foo';
319 it('success', async
function () {
320 const dbResult
= { identifier
, credential
};
321 sinon
.stub(db
.db
, 'oneOrNone').resolves(dbResult
);
322 const result
= await db
.authenticationGet(dbCtx
, identifier
);
323 assert
.deepStrictEqual(result
, dbResult
);
325 it('failure', async
function() {
326 const expected
= new Error('blah');
327 sinon
.stub(db
.db
, 'oneOrNone').rejects(expected
);
329 await db
.authenticationGet(dbCtx
, identifier
, credential
);
330 assert
.fail(noExpectedException
);
332 assert
.deepStrictEqual(e
, expected
);
335 }); // authenticationGet
337 describe('authenticationUpsert', function () {
338 let identifier
, credential
;
339 beforeEach(function () {
340 identifier
= 'username';
341 credential
= '$z$foo';
343 it('success', async
function () {
349 sinon
.stub(db
.db
, 'result').resolves(dbResult
);
350 await db
.authenticationUpsert(dbCtx
, identifier
, credential
);
352 it('failure', async
function() {
353 credential
= undefined;
359 sinon
.stub(db
.db
, 'result').resolves(dbResult
);
361 await db
.authenticationUpsert(dbCtx
, identifier
, credential
);
362 assert
.fail(noExpectedException
);
364 assert(e
instanceof DBErrors
.UnexpectedResult
);
367 }); // authenticationUpsert
369 describe('subscriptionsByTopicId', function () {
370 it('success', async
function () {
372 sinon
.stub(db
.db
, 'manyOrNone').resolves(expected
);
373 const result
= await db
.subscriptionsByTopicId(dbCtx
, topicUrl
);
374 assert
.deepStrictEqual(result
, expected
);
376 it('failure', async
function () {
377 const expected
= new Error();
378 sinon
.stub(db
.db
, 'manyOrNone').throws(expected
);
380 await db
.subscriptionsByTopicId(dbCtx
, topicUrl
);
381 assert
.fail(noExpectedException
);
383 assert
.deepStrictEqual(e
, expected
);
386 }); // subscriptionsByTopicId
388 describe('subscriptionCountByTopicUrl', function () {
389 it('success', async
function () {
390 const expected
= { count: 3 };
391 sinon
.stub(db
.db
, 'one').resolves(expected
);
392 const result
= await db
.subscriptionCountByTopicUrl(dbCtx
, topicUrl
);
393 assert
.deepStrictEqual(result
, expected
);
395 it('failure', async
function () {
396 const expected
= new Error();
397 sinon
.stub(db
.db
, 'one').throws(expected
);
399 await db
.subscriptionCountByTopicUrl(dbCtx
, topicUrl
);
400 assert
.fail(noExpectedException
);
402 assert
.deepStrictEqual(e
, expected
);
405 }); // subscriptionCountByTopicUrl
407 describe('subscriptionDelete', function () {
408 it('success', async
function() {
416 lastInsertRowid: undefined,
419 sinon
.stub(db
.db
, 'result').resolves(dbResult
);
420 const result
= await db
.subscriptionDelete(dbCtx
, callback
, topicId
);
421 assert
.deepStrictEqual(result
, expected
);
423 it('failure', async
function () {
424 const expected
= new Error();
425 sinon
.stub(db
.db
, 'result').throws(expected
);
427 await db
.subscriptionDelete(dbCtx
, callback
, topicId
);
428 assert
.fail(noExpectedException
);
430 assert
.deepStrictEqual(e
, expected
);
433 }); // subscriptionDelete
435 describe('subscriptionDeliveryClaim', function () {
436 it('success', async
function() {
439 id: 'c2e254c5-aa6e-4a8f-b1a1-e474b07392bb',
442 const expected
= ['c2e254c5-aa6e-4a8f-b1a1-e474b07392bb'];
443 sinon
.stub(db
.db
, 'manyOrNone').resolves(dbResult
);
444 const result
= await db
.subscriptionDeliveryClaim(dbCtx
, wanted
, claimTimeoutSeconds
, claimant
);
445 assert
.deepStrictEqual(result
, expected
);
447 it('failure', async
function () {
448 const expected
= new Error();
449 sinon
.stub(db
.db
, 'manyOrNone').throws(expected
);
451 await db
.subscriptionDeliveryClaim(dbCtx
, wanted
, claimTimeoutSeconds
, claimant
);
452 assert
.fail(noExpectedException
);
454 assert
.deepStrictEqual(e
, expected
);
457 }); // subscriptionDeliveryClaim
459 describe('subscriptionDeliveryClaimById', function () {
460 it('success', async
function() {
463 rows: [{ id: 'c2e254c5-aa6e-4a8f-b1a1-e474b07392bb' }],
468 lastInsertRowid: 'c2e254c5-aa6e-4a8f-b1a1-e474b07392bb',
471 sinon
.stub(db
.db
, 'result').resolves(dbResult
);
472 const result
= await db
.subscriptionDeliveryClaimById(dbCtx
, subscriptionId
, claimTimeoutSeconds
, claimant
);
473 assert
.deepStrictEqual(result
, expected
);
475 it('failure', async
function () {
481 sinon
.stub(db
.db
, 'result').resolves(dbResult
);
483 await db
.subscriptionDeliveryClaimById(dbCtx
, callback
, topicId
);
484 assert
.fail(noExpectedException
);
486 assert(e
instanceof DBErrors
.UnexpectedResult
);
489 }); // subscriptionDeliveryClaimById
491 describe('subscriptionDeliveryComplete', function () {
492 it('success', async
function() {
496 sinon
.stub(db
.db
, 'result').resolves(dbResult
);
497 await db
.subscriptionDeliveryComplete(dbCtx
, callback
, topicId
);
499 it('failure', async
function () {
503 sinon
.stub(db
.db
, 'result').onCall(0).resolves(dbResult
);
505 await db
.subscriptionDeliveryComplete(dbCtx
, callback
, topicId
);
506 assert
.fail(noExpectedException
);
508 assert(e
instanceof DBErrors
.UnexpectedResult
);
511 it('second failure', async
function () {
518 sinon
.stub(db
.db
, 'result').onCall(0).resolves(dbResult0
).onCall(1).resolves(dbResult1
);
520 await db
.subscriptionDeliveryComplete(dbCtx
, callback
, topicId
);
521 assert
.fail(noExpectedException
);
523 assert(e
instanceof DBErrors
.UnexpectedResult
);
526 }); // subscriptionDeliveryComplete
528 describe('subscriptionDeliveryGone', function () {
529 it('success', async
function() {
533 sinon
.stub(db
.db
, 'result').resolves(dbResult
);
534 await db
.subscriptionDeliveryGone(dbCtx
, callback
, topicId
);
536 it('failure', async
function () {
540 sinon
.stub(db
.db
, 'result').resolves(dbResult
);
542 await db
.subscriptionDeliveryGone(dbCtx
, callback
, topicId
);
543 assert
.fail(noExpectedException
);
545 assert(e
instanceof DBErrors
.UnexpectedResult
);
548 }); // subscriptionDeliveryGone
550 describe('subscriptionDeliveryIncomplete', function () {
551 it('success', async
function() {
552 const dbOne
= { deliveryAttemptsSinceSuccess: 0 };
556 sinon
.stub(db
.db
, 'one').resolves(dbOne
);
557 sinon
.stub(db
.db
, 'result').resolves(dbResult
);
558 await db
.subscriptionDeliveryIncomplete(dbCtx
, callback
, topicId
, retryDelays
);
560 it('success covers default', async
function() {
561 const dbOne
= { deliveryAttemptsSinceSuccess: 0 };
565 sinon
.stub(db
.db
, 'one').resolves(dbOne
);
566 sinon
.stub(db
.db
, 'result').resolves(dbResult
);
567 await db
.subscriptionDeliveryIncomplete(dbCtx
, callback
, topicId
);
569 it('failure', async
function () {
570 const dbOne
= { deliveryAttemptsSinceSuccess: 0 };
574 sinon
.stub(db
.db
, 'one').resolves(dbOne
);
575 sinon
.stub(db
.db
, 'result').resolves(dbResult
);
577 await db
.subscriptionDeliveryIncomplete(dbCtx
, callback
, topicId
, retryDelays
);
578 assert
.fail(noExpectedException
);
580 assert(e
instanceof DBErrors
.UnexpectedResult
);
583 it('second failure', async
function () {
584 const dbOne
= { deliveryAttemptsSinceSuccess: 0 };
591 sinon
.stub(db
.db
, 'one').resolves(dbOne
);
592 sinon
.stub(db
.db
, 'result').onCall(0).resolves(dbResult0
).onCall(1).resolves(dbResult1
);
594 await db
.subscriptionDeliveryIncomplete(dbCtx
, callback
, topicId
, retryDelays
);
595 assert
.fail(noExpectedException
);
597 assert(e
instanceof DBErrors
.UnexpectedResult
);
600 }); // subscriptionDeliveryIncomplete
602 describe('subscriptionGet', function () {
603 it('success', async
function() {
607 sinon
.stub(db
.db
, 'oneOrNone').resolves(expected
);
608 const result
= await db
.subscriptionGet(dbCtx
, callback
, topicId
);
609 assert
.deepStrictEqual(result
, expected
);
611 it('failure', async
function () {
612 const expected
= new Error();
613 sinon
.stub(db
.db
, 'oneOrNone').throws(expected
);
615 await db
.subscriptionGet(dbCtx
, callback
, topicId
);
616 assert
.fail(noExpectedException
);
618 assert
.deepStrictEqual(e
, expected
);
621 }); // subscriptionGet
623 describe('subscriptionGetById', function () {
624 it('success', async
function() {
628 sinon
.stub(db
.db
, 'oneOrNone').resolves(expected
);
629 const result
= await db
.subscriptionGetById(dbCtx
, subscriptionId
);
630 assert
.deepStrictEqual(result
, expected
);
632 it('failure', async
function () {
633 const expected
= new Error();
634 sinon
.stub(db
.db
, 'oneOrNone').throws(expected
);
636 await db
.subscriptionGetById(dbCtx
, subscriptionId
);
637 assert
.fail(noExpectedException
);
639 assert
.deepStrictEqual(e
, expected
);
642 }); // subscriptionGetById
644 describe('subscriptionUpsert', function () {
646 beforeEach(function () {
656 it('success', async
function() {
659 rows: [{ id: subscriptionId
}],
664 lastInsertRowid: subscriptionId
,
667 sinon
.stub(db
.db
, 'result').resolves(dbResult
);
668 const result
= await db
.subscriptionUpsert(dbCtx
, data
);
669 assert
.deepStrictEqual(result
, expected
);
671 it('failure', async
function () {
675 sinon
.stub(db
.db
, 'result').resolves(dbResult
);
677 await db
.subscriptionUpsert(dbCtx
, data
);
678 assert
.fail(noExpectedException
);
680 assert(e
instanceof DBErrors
.UnexpectedResult
);
683 }); // subscriptionUpsert
685 describe('subscriptionUpdate', function () {
687 beforeEach(function () {
689 signatureAlgorithm: 'sha256',
692 it('success', async
function() {
698 sinon
.stub(db
.db
, 'result').resolves(dbResult
);
699 await db
.subscriptionUpdate(dbCtx
, data
);
701 it('failure', async
function () {
705 sinon
.stub(db
.db
, 'result').resolves(dbResult
);
707 await db
.subscriptionUpdate(dbCtx
, data
);
708 assert
.fail(noExpectedException
);
710 assert(e
instanceof DBErrors
.UnexpectedResult
);
713 }); // subscriptionUpdate
715 describe('topicDeleted', function () {
716 it('success', async
function() {
720 sinon
.stub(db
.db
, 'result').resolves(dbResult
);
721 await db
.topicDeleted(dbCtx
, topicId
);
723 it('failure', async
function() {
727 sinon
.stub(db
.db
, 'result').resolves(dbResult
);
729 await db
.topicDeleted(dbCtx
, topicId
);
730 assert
.fail(noExpectedException
);
732 assert(e
instanceof DBErrors
.UnexpectedResult
);
737 describe('topicFetchClaim', function () {
738 it('success', async
function() {
739 const dbResult
= [{ id: topicId
}];
740 const expected
= [topicId
];
741 sinon
.stub(db
.db
, 'manyOrNone').resolves(dbResult
);
742 const result
= await db
.topicFetchClaim(dbCtx
, wanted
, claimTimeoutSeconds
, claimant
);
743 assert
.deepStrictEqual(result
, expected
);
745 it('failure', async
function () {
746 const expected
= new Error();
747 sinon
.stub(db
.db
, 'manyOrNone').throws(expected
);
749 await db
.topicFetchClaim(dbCtx
, wanted
, claimTimeoutSeconds
, claimant
);
750 assert
.fail(noExpectedException
);
752 assert
.deepStrictEqual(e
, expected
);
755 }); // topicFetchClaim
757 describe('topicFetchClaimById', function () {
758 it('success', async
function() {
766 lastInsertRowid: undefined,
769 sinon
.stub(db
.db
, 'result').resolves(dbResult
);
770 const result
= await db
.topicFetchClaimById(dbCtx
, topicId
, claimTimeoutSeconds
, claimant
);
771 assert
.deepStrictEqual(result
, expected
);
773 it('failure', async
function () {
774 const expected
= new Error();
775 sinon
.stub(db
.db
, 'result').throws(expected
);
777 await db
.topicFetchClaimById(dbCtx
, topicId
, claimTimeoutSeconds
, claimant
);
778 assert
.fail(noExpectedException
);
780 assert
.deepStrictEqual(e
, expected
);
783 }); // topicFetchClaimById
785 describe('topicFetchComplete', function () {
786 it('success', async
function() {
792 sinon
.stub(db
.db
, 'result').resolves(dbResult
);
793 await db
.topicFetchComplete(dbCtx
, topicId
);
795 it('failure', async
function () {
801 sinon
.stub(db
.db
, 'result').resolves(dbResult
);
803 await db
.topicFetchComplete(dbCtx
, topicId
);
804 assert
.fail(noExpectedException
);
806 assert(e
instanceof DBErrors
.UnexpectedResult
);
809 it('second failure', async
function () {
820 sinon
.stub(db
.db
, 'result').onCall(0).resolves(dbResult0
).onCall(1).resolves(dbResult1
);
822 await db
.topicFetchComplete(dbCtx
, topicId
);
823 assert
.fail(noExpectedException
);
825 assert(e
instanceof DBErrors
.UnexpectedResult
);
828 }); // topicFetchComplete
830 describe('topicFetchIncomplete', function () {
831 it('success', async
function() {
832 const dbOne
= { currentAttempt: 0 };
845 lastInsertRowid: undefined,
848 sinon
.stub(db
.db
, 'one').resolves(dbOne
);
849 sinon
.stub(db
.db
, 'result').onCall(0).resolves(dbResult0
).onCall(1).resolves(dbResult1
);
850 const result
= await db
.topicFetchIncomplete(dbCtx
, topicId
, retryDelays
);
851 assert
.deepStrictEqual(result
, expected
);
853 it('covers defaults', async
function() {
854 const dbOne
= { currentAttempt: 0 };
867 lastInsertRowid: undefined,
870 sinon
.stub(db
.db
, 'one').resolves(dbOne
);
871 sinon
.stub(db
.db
, 'result').onCall(0).resolves(dbResult0
).onCall(1).resolves(dbResult1
);
872 const result
= await db
.topicFetchIncomplete(dbCtx
, topicId
);
873 assert
.deepStrictEqual(result
, expected
);
875 it('failure', async
function () {
876 const dbOne
= { currentAttempt: 0 };
887 sinon
.stub(db
.db
, 'one').resolves(dbOne
);
888 sinon
.stub(db
.db
, 'result').onCall(0).resolves(dbResult0
).onCall(1).resolves(dbResult1
);
890 await db
.topicFetchIncomplete(dbCtx
, topicId
, retryDelays
);
891 assert
.fail(noExpectedException
);
893 assert(e
instanceof DBErrors
.UnexpectedResult
);
896 it('second failure', async
function () {
897 const dbOne
= { currentAttempt: 0 };
908 sinon
.stub(db
.db
, 'one').resolves(dbOne
);
909 sinon
.stub(db
.db
, 'result').onCall(0).resolves(dbResult0
).onCall(1).resolves(dbResult1
);
911 await db
.topicFetchIncomplete(dbCtx
, topicId
, retryDelays
);
912 assert
.fail(noExpectedException
);
914 assert(e
instanceof DBErrors
.UnexpectedResult
);
917 }); // topicFetchIncomplete
919 describe('topicFetchRequested', function () {
920 it('success', async
function() {
928 lastInsertRowid: undefined,
931 sinon
.stub(db
.db
, 'result').resolves(dbResult
);
932 const result
= await db
.topicFetchRequested(dbCtx
, topicId
);
933 assert
.deepStrictEqual(result
, expected
);
935 it('failure', async
function () {
941 sinon
.stub(db
.db
, 'result').resolves(dbResult
);
943 await db
.topicFetchRequested(dbCtx
, topicId
);
944 assert
.fail(noExpectedException
);
946 assert(e
instanceof DBErrors
.UnexpectedResult
);
949 }); // topicFetchRequested
951 describe('topicGetAll', function () {
952 it('success', async
function() {
953 const expected
= [{ id: topicId
}];
954 sinon
.stub(db
.db
, 'manyOrNone').resolves(expected
);
955 const result
= await db
.topicGetAll(dbCtx
);
956 assert
.deepStrictEqual(result
, expected
);
958 it('covers default', async
function() {
959 const expected
= undefined;
960 sinon
.stub(db
.db
, 'manyOrNone').resolves(expected
);
961 const result
= await db
.topicGetAll(dbCtx
);
962 assert
.deepStrictEqual(result
, expected
);
964 it('failure', async
function () {
965 const expected
= new Error();
966 sinon
.stub(db
.db
, 'manyOrNone').throws(expected
);
968 await db
.topicGetAll(dbCtx
);
969 assert
.fail(noExpectedException
);
971 assert
.deepStrictEqual(e
, expected
);
976 describe('topicGetById', function () {
977 it('success', async
function() {
978 const expected
= { id: topicId
};
979 sinon
.stub(db
.db
, 'oneOrNone').resolves(expected
);
980 const result
= await db
.topicGetById(dbCtx
, topicId
);
981 assert
.deepStrictEqual(result
, expected
);
983 it('covers none', async
function() {
984 const expected
= undefined;
985 sinon
.stub(db
.db
, 'oneOrNone').resolves(expected
);
986 const result
= await db
.topicGetById(dbCtx
, topicId
);
987 assert
.deepStrictEqual(result
, expected
);
989 it('covers no defaults', async
function () {
990 const expected
= { id: topicId
};
991 sinon
.stub(db
.db
, 'oneOrNone').resolves(expected
);
992 const result
= await db
.topicGetById(dbCtx
, topicId
, false);
993 assert
.deepStrictEqual(result
, expected
);
995 it('failure', async
function () {
996 const expected
= new Error();
997 sinon
.stub(db
.db
, 'oneOrNone').throws(expected
);
999 await db
.topicGetById(dbCtx
, topicId
);
1000 assert
.fail(noExpectedException
);
1002 assert
.deepStrictEqual(e
, expected
);
1007 describe('topicGetByUrl', function () {
1008 it('success', async
function() {
1009 const expected
= [];
1010 sinon
.stub(db
.db
, 'oneOrNone').resolves(expected
);
1011 const result
= await db
.topicGetByUrl(dbCtx
, topicUrl
);
1012 assert
.deepStrictEqual(result
, expected
);
1014 it('failure', async
function () {
1015 const expected
= new Error();
1016 sinon
.stub(db
.db
, 'oneOrNone').throws(expected
);
1018 await db
.topicGetByUrl(dbCtx
, topicUrl
);
1019 assert
.fail(noExpectedException
);
1021 assert
.deepStrictEqual(e
, expected
);
1024 }); // topicGetByUrl
1026 describe('topicGetContentById', function () {
1027 it('success', async
function() {
1028 const expected
= { id: topicId
};
1029 sinon
.stub(db
.db
, 'oneOrNone').resolves(expected
);
1030 const result
= await db
.topicGetContentById(dbCtx
, topicId
);
1031 assert
.deepStrictEqual(result
, expected
);
1033 it('covers default', async
function() {
1034 const expected
= undefined;
1035 sinon
.stub(db
.db
, 'oneOrNone').resolves(expected
);
1036 const result
= await db
.topicGetContentById(dbCtx
, topicId
);
1037 assert
.deepStrictEqual(result
, expected
);
1039 it('failure', async
function () {
1040 const expected
= new Error();
1041 sinon
.stub(db
.db
, 'oneOrNone').throws(expected
);
1043 await db
.topicGetContentById(dbCtx
, topicId
);
1044 assert
.fail(noExpectedException
);
1046 assert
.deepStrictEqual(e
, expected
);
1049 }); // topicGetContentById
1051 describe('topicSet', function () {
1053 beforeEach(function () {
1058 it('success', async
function() {
1061 rows: [{ id: topicId
}],
1066 lastInsertRowid: topicId
,
1069 sinon
.stub(db
.db
, 'result').resolves(dbResult
);
1070 const result
= await db
.topicSet(dbCtx
, data
);
1071 assert
.deepStrictEqual(result
, expected
);
1073 it('failure', async
function () {
1079 sinon
.stub(db
.db
, 'result').resolves(dbResult
);
1081 await db
.topicSet(dbCtx
, data
);
1082 assert
.fail(noExpectedException
);
1084 assert(e
instanceof DBErrors
.UnexpectedResult
);
1087 it('fails invalid value', async
function () {
1088 sinon
.stub(db
.db
, 'result');
1090 data
.leaseSecondsPreferred
= -100;
1091 await db
.topicSet(dbCtx
, data
);
1092 assert
.fail(noExpectedException
);
1094 assert(e
instanceof DBErrors
.DataValidation
);
1096 assert(!db
.db
.result
.called
);
1098 it('fails invalid values', async
function () {
1099 sinon
.stub(db
.db
, 'result');
1101 data
.leaseSecondsPreferred
= 10;
1102 data
.leaseSecondsMax
= 100;
1103 data
.leaseSecondsMin
= 50;
1104 await db
.topicSet(dbCtx
, data
);
1105 assert
.fail(noExpectedException
);
1107 assert(e
instanceof DBErrors
.DataValidation
);
1109 assert(!db
.db
.result
.called
);
1113 describe('topicSetContent', function () {
1115 beforeEach(function () {
1118 contentType: 'text/plain',
1119 contentHash: 'abc123',
1122 it('success', async
function() {
1130 lastInsertRowid: undefined,
1133 sinon
.stub(db
.db
, 'result').resolves(dbResult
);
1134 const result
= await db
.topicSetContent(dbCtx
, data
);
1135 assert
.deepStrictEqual(result
, expected
);
1137 it('failure', async
function () {
1143 sinon
.stub(db
.db
, 'result').resolves(dbResult
);
1145 await db
.topicSetContent(dbCtx
, data
);
1146 assert
.fail(noExpectedException
);
1148 assert(e
instanceof DBErrors
.UnexpectedResult
);
1151 }); // topicSetContent
1153 describe('topicUpdate', function () {
1155 beforeEach(function () {
1157 leaseSecondsPreferred: 123,
1158 leaseSecondsMin: 100,
1159 leaseSecondsMax: 1000,
1160 publisherValidationUrl: null,
1161 contentHashAlgorithm: 'sha256',
1164 it('success', async
function() {
1170 sinon
.stub(db
.db
, 'result').resolves(dbResult
);
1171 await db
.topicUpdate(dbCtx
, data
);
1173 it('failure', async
function () {
1179 sinon
.stub(db
.db
, 'result').resolves(dbResult
);
1181 await db
.topicUpdate(dbCtx
, data
);
1182 assert
.fail(noExpectedException
);
1184 assert(e
instanceof DBErrors
.UnexpectedResult
);
1190 describe('verificationClaim', function () {
1191 it('success', async
function() {
1192 const dbManyOrNone
= [{ id: verificationId
}];
1193 const expected
= [verificationId
];
1194 sinon
.stub(db
.db
, 'manyOrNone').resolves(dbManyOrNone
);
1195 const result
= await db
.verificationClaim(dbCtx
, wanted
, claimTimeoutSeconds
, claimant
);
1196 assert
.deepStrictEqual(result
, expected
);
1198 it('failure', async
function () {
1199 const expected
= new Error();
1200 sinon
.stub(db
.db
, 'manyOrNone').throws(expected
);
1202 await db
.verificationClaim(dbCtx
, wanted
, claimTimeoutSeconds
, claimant
);
1203 assert
.fail(noExpectedException
);
1205 assert
.deepStrictEqual(e
, expected
);
1208 }); // verificationClaim
1210 describe('verificationClaimById', function () {
1211 it('success', async
function() {
1214 rows: [ { id: verificationId
} ],
1219 lastInsertRowid: verificationId
,
1222 sinon
.stub(db
.db
, 'result').resolves(dbResult
);
1223 const result
= await db
.verificationClaimById(dbCtx
, verificationId
, claimTimeoutSeconds
, claimant
);
1224 assert
.deepStrictEqual(result
, expected
);
1226 it('failure', async
function () {
1227 const expected
= new Error();
1228 sinon
.stub(db
.db
, 'result').throws(expected
);
1230 await db
.verificationClaimById(dbCtx
, verificationId
, claimTimeoutSeconds
, claimant
);
1231 assert
.fail(noExpectedException
);
1233 assert
.deepStrictEqual(e
, expected
);
1236 }); // verificationClaimById
1238 describe('verificationComplete', function () {
1239 it('success', async
function() {
1245 sinon
.stub(db
.db
, 'result').resolves(dbResult
);
1246 await db
.verificationComplete(dbCtx
, verificationId
, callback
, topicId
);
1248 it('failure', async
function () {
1254 sinon
.stub(db
.db
, 'result').resolves(dbResult
);
1256 await db
.verificationComplete(dbCtx
, verificationId
, callback
, topicId
);
1257 assert
.fail(noExpectedException
);
1259 assert(e
instanceof DBErrors
.UnexpectedResult
);
1262 }); // verificationComplete
1264 describe('verificationGetById', function () {
1265 it('success', async
function() {
1266 const dbOneOrNone
= { id: verificationId
};
1267 const expected
= { id: verificationId
};
1268 sinon
.stub(db
.db
, 'oneOrNone').resolves(dbOneOrNone
);
1269 const result
= await db
.verificationGetById(dbCtx
, verificationId
);
1270 assert
.deepStrictEqual(result
, expected
);
1272 it('failure', async
function () {
1273 const expected
= new Error();
1274 sinon
.stub(db
.db
, 'oneOrNone').throws(expected
);
1276 await db
.verificationGetById(dbCtx
, verificationId
);
1277 assert
.fail(noExpectedException
);
1279 assert
.deepStrictEqual(e
, expected
);
1282 }); // verificationGetById
1284 describe('verificationIncomplete', function () {
1285 it('success', async
function() {
1286 const dbOne
= { attempts: 0 };
1297 sinon
.stub(db
.db
, 'one').resolves(dbOne
);
1298 sinon
.stub(db
.db
, 'result').onCall(0).resolves(dbResult0
).onCall(1).resolves(dbResult1
);
1299 await db
.verificationIncomplete(dbCtx
, verificationId
, retryDelays
);
1301 it('covers defaults', async
function() {
1302 const dbOne
= { attempts: 0 };
1313 sinon
.stub(db
.db
, 'one').resolves(dbOne
);
1314 sinon
.stub(db
.db
, 'result').onCall(0).resolves(dbResult0
).onCall(1).resolves(dbResult1
);
1315 await db
.verificationIncomplete(dbCtx
, verificationId
);
1317 it('failure', async
function () {
1318 const dbOne
= { attempts: 0 };
1329 sinon
.stub(db
.db
, 'one').resolves(dbOne
);
1330 sinon
.stub(db
.db
, 'result').onCall(0).resolves(dbResult0
).onCall(1).resolves(dbResult1
);
1332 await db
.verificationIncomplete(dbCtx
, verificationId
, retryDelays
);
1333 assert
.fail(noExpectedException
);
1335 assert(e
instanceof DBErrors
.UnexpectedResult
);
1338 it('second failure', async
function () {
1339 const dbOne
= { attempts: 0 };
1350 sinon
.stub(db
.db
, 'one').resolves(dbOne
);
1351 sinon
.stub(db
.db
, 'result').onCall(0).resolves(dbResult0
).onCall(1).resolves(dbResult1
);
1353 await db
.verificationIncomplete(dbCtx
, verificationId
, retryDelays
);
1354 assert
.fail(noExpectedException
);
1356 assert(e
instanceof DBErrors
.UnexpectedResult
);
1359 }); // verificationIncomplete
1361 describe('verificationInsert', function () {
1363 beforeEach(function () {
1368 isPublisherValidated: true,
1369 leaseSeconds: 86400,
1372 it('success', async
function() {
1375 rows: [{ id: verificationId
}],
1378 const expected
= verificationId
;
1379 sinon
.stub(db
.db
, 'result').resolves(dbResult
);
1380 const result
= await db
.verificationInsert(dbCtx
, verification
);
1381 assert
.deepStrictEqual(result
, expected
);
1383 it('failure', async
function () {
1389 sinon
.stub(db
.db
, 'result').resolves(dbResult
);
1391 await db
.verificationInsert(dbCtx
, verification
);
1392 assert
.fail(noExpectedException
);
1394 assert(e
instanceof DBErrors
.UnexpectedResult
);
1397 it('fails validation', async
function () {
1398 delete verification
.leaseSeconds
;
1400 await db
.verificationInsert(dbCtx
, verification
);
1401 assert
.fail(noExpectedException
);
1403 assert(e
instanceof DBErrors
.DataValidation
);
1406 }); // verificationInsert
1408 describe('verificationRelease', function () {
1409 it('success', async
function() {
1415 sinon
.stub(db
.db
, 'result').resolves(dbResult
);
1416 await db
.verificationRelease(dbCtx
, verificationId
);
1418 it('failure', async
function () {
1424 sinon
.stub(db
.db
, 'result').resolves(dbResult
);
1426 await db
.verificationRelease(dbCtx
, verificationId
);
1427 assert
.fail(noExpectedException
);
1429 assert(e
instanceof DBErrors
.UnexpectedResult
);
1432 }); // verificationRelease
1434 describe('verificationUpdate', function () {
1436 beforeEach(function () {
1439 isPublisherValidated: true,
1442 it('success', async
function() {
1448 sinon
.stub(db
.db
, 'result').resolves(dbResult
);
1449 await db
.verificationUpdate(dbCtx
, verificationId
, data
);
1451 it('failure', async
function () {
1457 sinon
.stub(db
.db
, 'result').resolves(dbResult
);
1459 await db
.verificationUpdate(dbCtx
, verificationId
, data
);
1460 assert
.fail(noExpectedException
);
1462 assert(e
instanceof DBErrors
.UnexpectedResult
, e
.name
);
1465 it('fails validation', async
function () {
1468 await db
.verificationUpdate(dbCtx
, verificationId
, data
);
1469 assert
.fail(noExpectedException
);
1471 assert(e
instanceof DBErrors
.DataValidation
);
1474 }); // verificationUpdate
1476 describe('verificationValidated', function () {
1477 it('success', async
function() {
1483 sinon
.stub(db
.db
, 'result').resolves(dbResult
);
1484 await db
.verificationValidated(dbCtx
, verificationId
);
1486 it('failure', async
function () {
1492 sinon
.stub(db
.db
, 'result').resolves(dbResult
);
1494 await db
.verificationValidated(dbCtx
, verificationId
);
1495 assert
.fail(noExpectedException
);
1497 assert(e
instanceof DBErrors
.UnexpectedResult
);
1500 }); // verificationValidated
1502 }); // DatabasePostgres