update dependencies and devDependencies, fix a comment
[websub-hub] / test / src / db / sqlite.js
1 /* eslint-disable sonarjs/no-identical-functions */
2 /* eslint-env mocha */
3 /* eslint-disable sonarjs/no-duplicate-string */
4 'use strict';
5
6 /* This provides implementation coverage, stubbing parts of better-sqlite3. */
7
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/sqlite');
14 const DBErrors = require('../../../src/db/errors');
15 const common = require('../../../src/common');
16 const Config = require('../../../config');
17
18 const noExpectedException = 'did not receive expected exception';
19
20 describe('DatabaseSQLite', function () {
21 let db, options;
22 let dbCtx, claimant, claimTimeoutSeconds, callback, subscriptionId, topicId, verificationId;
23 let topicUrl, leaseSeconds, secret, httpRemoteAddr, httpFrom, retryDelays, wanted;
24 before(function () {
25 options = new Config('test');
26 options.db.connectionString = 'sqlite://:memory:';
27 db = new DB(stubLogger, options);
28 });
29 beforeEach(function () {
30 stubLogger._reset();
31 dbCtx = db.db;
32 claimant = '19af19b8-6be3-4a6f-8946-65f5f1ccc5d7';
33 claimTimeoutSeconds = 300;
34 subscriptionId = 'fbaf8f19-ed9c-4a21-89ae-98b7005e3bf6';
35 topicUrl = 'https://example.com/blog';
36 callback = 'https://example.com/callback?id=123';
37 topicId = 'c59d4bda-10ad-41d9-99df-4ce8bc331424';
38 verificationId = '55cd7748-d2d5-11eb-b355-0025905f714a';
39 retryDelays = [60];
40 leaseSeconds = 86400;
41 secret = 'secret';
42 httpRemoteAddr = '127.0.0.1';
43 httpFrom = 'user@example.com';
44 wanted = 5;
45 });
46 afterEach(function () {
47 sinon.restore();
48 });
49
50 // Ensure all interface methods are implemented
51 describe('Implementation', function () {
52 it('implements interface', async function () {
53 const results = await Promise.allSettled(DBStub._implementation.map(async (fn) => {
54 try {
55 // eslint-disable-next-line security/detect-object-injection
56 await db[fn](db.db);
57 } catch (e) {
58 assert(!(e instanceof DBErrors.NotImplemented), `${fn} not implemented`);
59 }
60 }));
61 const failures = results.filter((x) => x.status === 'rejected');
62 assert(!failures.length, failures.map((x) => {
63 x = x.reason.toString();
64 return x.slice(x.indexOf(': '));
65 }));
66 });
67 }); // Implementation
68
69 describe('_currentSchema', function () {
70 it('covers', async function () {
71 const version = { major: 1, minor: 0, patch: 0 };
72 sinon.stub(db.db, 'prepare').returns({
73 get: () => version,
74 });
75 const result = await db._currentSchema();
76 assert.deepStrictEqual(result, version);
77 });
78 }); // _currentSchema
79
80 describe('_closeConnection', function () {
81 it('success', async function () {
82 sinon.stub(db.db, 'close');
83 await db._closeConnection();
84 assert(db.db.close.called);
85 });
86 it('failure', async function () {
87 const expected = new Error();
88 sinon.stub(db.db, 'close').throws(expected);
89 try {
90 await db._closeConnection();
91 assert.fail(noExpectedException);
92 } catch (e) {
93 assert.deepStrictEqual(e, expected);
94 }
95 });
96 }); // _closeConnection
97
98 describe('_purgeTables', function () {
99 beforeEach(function () {
100 sinon.stub(db.db, 'prepare').returns({
101 run: sinon.stub(),
102 });
103 });
104 it('covers not really', async function () {
105 await db._purgeTables(false);
106 assert(!db.db.prepare.called);
107 });
108 it('success', async function () {
109 await db._purgeTables(true);
110 assert(db.db.prepare.called);
111 });
112 it('failure', async function () {
113 const expected = new Error();
114 db.db.prepare.restore();
115 sinon.stub(db.db, 'prepare').throws(expected);
116 try {
117 await db._purgeTables(true);
118 assert.fail(noExpectedException);
119 } catch (e) {
120 assert.deepStrictEqual(e, expected);
121 }
122 });
123 }); // _purgeTables
124
125 describe('_optimize', function () {
126 let origOAC;
127 beforeEach(function () {
128 origOAC = db.optimizeAfterChanges;
129 sinon.stub(db.statement._optimize, 'all');
130 sinon.stub(db.db, 'pragma');
131 });
132 this.afterEach(function () {
133 db.optimizeAfterChanges = origOAC;
134 });
135 it('covers', async function () {
136 db.optimizeAfterChanges = 10;
137 db.changesSinceLastOptimize = BigInt(20);
138 await db._optimize();
139 assert(db.db.pragma.called);
140 });
141 it('covers none', async function () {
142 db.optimizeAfterChanges = 0;
143 await db._optimize();
144 assert(!db.db.pragma.called);
145 });
146 it('covers not enough changes', async function () {
147 db.optimizeAfterChanges = 10;
148 db.changesSinceLastOptimize = BigInt(5);
149 await db._optimize();
150 assert(!db.db.pragma.called);
151 });
152 }); // _optimize
153
154 describe('_deOphidiate', function () {
155 it('covers non-array', function () {
156 const obj = {
157 'snake_case': 1,
158 };
159 const expected = {
160 snakeCase: 1,
161 };
162 const result = DB._deOphidiate(obj);
163 assert.deepStrictEqual(result, expected);
164 });
165 it('covers array', function () {
166 const rows = [
167 {
168 'snek_field': 'foo',
169 },
170 {
171 'snek_field': 'bar',
172 },
173 ];
174 const expected = [
175 {
176 snekField: 'foo',
177 },
178 {
179 snekField: 'bar',
180 },
181 ];
182 const result = DB._deOphidiate(rows);
183 assert.deepStrictEqual(result, expected);
184 });
185 }); // _deOphidiate
186
187 describe('_topicDataToNative', function () {
188 it('covers', function () {
189 const now = new Date();
190 const nowEpoch = now.getTime() / 1000;
191 const topic = {
192 isActive: 1,
193 isDeleted: 0,
194 created: nowEpoch,
195 lastPublish: nowEpoch,
196 contentFetchNextAttempt: nowEpoch,
197 contentUpdated: nowEpoch,
198 url: 'https://example.com/',
199 };
200 const expected = {
201 isActive: true,
202 isDeleted: false,
203 created: now,
204 lastPublish: now,
205 contentFetchNextAttempt: now,
206 contentUpdated: now,
207 url: topic.url,
208 }
209 const result = DB._topicDataToNative(topic);
210 assert.deepStrictEqual(result, expected);
211 });
212 it('covers empty', function () {
213 const topic = undefined;
214 const result = DB._topicDataToNative(topic);
215 assert.deepStrictEqual(result, topic);
216 });
217 }); // _topicDataToNative
218
219 describe('healthCheck', function () {
220 let origDb;
221 beforeEach(function () {
222 origDb = db.db;
223 });
224 afterEach(function () {
225 db.db = origDb;
226 });
227 it('covers', function () {
228 db.healthCheck();
229 });
230 it('covers failure', function () {
231 db.db = { open: false };
232 try {
233 db.healthCheck();
234 assert.fail(noExpectedException);
235 } catch (e) {
236 assert(e instanceof DBErrors.UnexpectedResult);
237 }
238 });
239 }); // healthCheck
240
241 describe('context', function () {
242 it('covers', async function () {
243 await db.context(common.nop);
244 });
245 }); // context
246
247 describe('transaction', function () {
248 it('covers', async function () {
249 await db.transaction(db.db, common.nop);
250 });
251 it('covers no context', async function () {
252 await db.transaction(undefined, common.nop);
253 });
254 }); // transaction
255
256 describe('authenticationSuccess', function () {
257 let identifier;
258 beforeEach(function () {
259 identifier = 'username';
260 });
261 it('success', async function() {
262 const dbResult = {
263 changes: 1,
264 lastInsertRowid: undefined,
265 };
266 sinon.stub(db.statement.authenticationSuccess, 'run').returns(dbResult);
267 await db.authenticationSuccess(dbCtx, identifier);
268 });
269 it('failure', async function () {
270 const dbResult = {
271 changes: 0,
272 lastInsertRowid: undefined,
273 };
274 sinon.stub(db.statement.authenticationSuccess, 'run').returns(dbResult);
275 try {
276 await db.authenticationSuccess(dbCtx, identifier);
277 assert.fail(noExpectedException);
278 } catch (e) {
279 assert(e instanceof DBErrors.UnexpectedResult);
280 }
281 });
282 }); // authenticationSuccess
283
284 describe('authenticationGet', function () {
285 let identifier, credential;
286 beforeEach(function () {
287 identifier = 'username';
288 credential = '$z$foo';
289 });
290 it('success', async function() {
291 const expected = {
292 identifier,
293 credential,
294 };
295 sinon.stub(db.statement.authenticationGet, 'get').returns(expected);
296 const result = await db.authenticationGet(dbCtx, identifier);
297 assert.deepStrictEqual(result, expected);
298 });
299 it('failure', async function () {
300 const expected = new Error();
301 sinon.stub(db.statement.authenticationGet, 'get').throws(expected);
302 try {
303 await db.authenticationGet(dbCtx, identifier);
304 assert.fail(noExpectedException);
305 } catch (e) {
306 assert.deepStrictEqual(e, expected);
307 }
308 });
309 }); // authenticationGet
310
311 describe('authenticationUpsert', function () {
312 let identifier, credential;
313 beforeEach(function () {
314 identifier = 'username';
315 credential = '$z$foo';
316 });
317 it('success', async function() {
318 const dbResult = {
319 changes: 1,
320 lastInsertRowid: undefined,
321 };
322 sinon.stub(db.statement.authenticationUpsert, 'run').returns(dbResult);
323 await db.authenticationUpsert(dbCtx, identifier, credential);
324 });
325 it('failure', async function () {
326 const dbResult = {
327 changes: 0,
328 lastInsertRowid: undefined,
329 };
330 sinon.stub(db.statement.authenticationUpsert, 'run').returns(dbResult);
331 try {
332 await db.authenticationUpsert(dbCtx, identifier, credential);
333 assert.fail(noExpectedException);
334 } catch (e) {
335 assert(e instanceof DBErrors.UnexpectedResult);
336 }
337 });
338 }); // authenticationUpsert
339
340 describe('subscriptionsByTopicId', function () {
341 it('success', async function () {
342 const expected = [{ id: 3 }];
343 sinon.stub(db.statement.subscriptionsByTopicId, 'all').returns(expected);
344 const result = await db.subscriptionsByTopicId(dbCtx, topicUrl);
345 assert.deepStrictEqual(result, expected);
346 });
347 it('failure', async function () {
348 const expected = new Error();
349 sinon.stub(db.statement.subscriptionsByTopicId, 'all').throws(expected);
350 try {
351 await db.subscriptionsByTopicId(dbCtx, topicUrl);
352 assert.fail(noExpectedException);
353 } catch (e) {
354 assert.deepStrictEqual(e, expected);
355 }
356 });
357 }); // subscriptionsByTopicId
358
359 describe('subscriptionCountByTopicUrl', function () {
360 it('success', async function () {
361 const expected = { count: 3 };
362 sinon.stub(db.statement.subscriptionCountByTopicUrl, 'get').returns(expected);
363 const result = await db.subscriptionCountByTopicUrl(dbCtx, topicUrl);
364 assert.deepStrictEqual(result, expected);
365 });
366 it('failure', async function () {
367 const expected = new Error();
368 sinon.stub(db.statement.subscriptionCountByTopicUrl, 'get').throws(expected);
369 try {
370 await db.subscriptionCountByTopicUrl(dbCtx, topicUrl);
371 assert.fail(noExpectedException);
372 } catch (e) {
373 assert.deepStrictEqual(e, expected);
374 }
375 });
376 }); // subscriptionCountByTopicUrl
377
378 describe('subscriptionDelete', function () {
379 it('success', async function() {
380 const dbResult = {
381 changes: 1,
382 lastInsertRowid: undefined,
383 };
384 const expected = {
385 changes: 1,
386 lastInsertRowid: undefined,
387 };
388 sinon.stub(db.statement.subscriptionDelete, 'run').returns(dbResult);
389 const result = await db.subscriptionDelete(dbCtx, callback, topicId);
390 assert.deepStrictEqual(result, expected);
391 });
392 it('failure', async function () {
393 const dbResult = {
394 changes: 0,
395 lastInsertRowid: undefined,
396 };
397 sinon.stub(db.statement.subscriptionDelete, 'run').returns(dbResult);
398 try {
399 await db.subscriptionDelete(dbCtx, callback, topicId);
400 assert.fail(noExpectedException);
401 } catch (e) {
402 assert(e instanceof DBErrors.UnexpectedResult);
403 }
404 });
405 }); // subscriptionDelete
406
407 describe('subscriptionDeleteExpired', function () {
408 it('success', async function () {
409 const dbResult = {
410 changes: 1,
411 lastInsertRowid: undefined,
412 };
413 const expected = {
414 changes: 1,
415 lastInsertRowid: undefined,
416 };
417 sinon.stub(db.statement.subscriptionDeleteExpired, 'run').returns(dbResult);
418 const result = await db.subscriptionDeleteExpired(dbCtx, topicId);
419 assert.deepStrictEqual(result, expected);
420 });
421 it('failure', async function () {
422 const expected = new Error();
423 sinon.stub(db.statement.subscriptionDeleteExpired, 'run').throws(expected);
424 try {
425 await db.subscriptionDeleteExpired(dbCtx, topicId);
426 assert.fail(noExpectedException);
427 } catch (e) {
428 assert.deepStrictEqual(e, expected);
429 }
430 });
431 });
432
433 describe('subscriptionDeliveryClaim', function () {
434 it('success', async function () {
435 const dbAllResult = [
436 {
437 id: 'c2e254c5-aa6e-4a8f-b1a1-e474b07392bb',
438 },
439 ];
440 const dbRunResult = {
441 changes: 1,
442 lastInsertRowid: undefined,
443 };
444 const expected = ['c2e254c5-aa6e-4a8f-b1a1-e474b07392bb'];
445 sinon.stub(db.statement.subscriptionDeliveryNeeded, 'all').returns(dbAllResult);
446 sinon.stub(db.statement.subscriptionDeliveryClaimById, 'run').returns(dbRunResult);
447 const result = await db.subscriptionDeliveryClaim(dbCtx, wanted, claimTimeoutSeconds, claimant);
448 assert.deepStrictEqual(result, expected);
449 });
450 it('failure', async function () {
451 const dbAllResult = [
452 {
453 id: 'c2e254c5-aa6e-4a8f-b1a1-e474b07392bb',
454 },
455 ];
456 const dbRunResult = {
457 changes: 0,
458 lastInsertRowid: undefined,
459 };
460 sinon.stub(db.statement.subscriptionDeliveryNeeded, 'all').returns(dbAllResult);
461 sinon.stub(db.statement.subscriptionDeliveryClaimById, 'run').returns(dbRunResult);
462 try {
463 await db.subscriptionDeliveryClaim(dbCtx, wanted, claimTimeoutSeconds, claimant );
464 assert.fail(noExpectedException);
465 } catch (e) {
466 assert(e instanceof DBErrors.UnexpectedResult);
467 }
468 });
469 }); // subscriptionDeliveryClaim
470
471 describe('subscriptionDeliveryClaimById', function () {
472 it('success', async function() {
473 const dbResult = {
474 changes: 1,
475 lastInsertRowid: undefined,
476 };
477 sinon.stub(db.statement.subscriptionDeliveryClaimById, 'run').returns(dbResult);
478 const result = await db.subscriptionDeliveryClaimById(dbCtx, subscriptionId, claimTimeoutSeconds, claimant);
479 assert.deepStrictEqual(result, dbResult);
480 });
481 it('failure', async function () {
482 const dbResult = {
483 changes: 0,
484 lastInsertRowid: undefined,
485 };
486 sinon.stub(db.statement.subscriptionDeliveryClaimById, 'run').returns(dbResult);
487 try {
488 await db.subscriptionDeliveryClaimById(dbCtx, subscriptionId, claimTimeoutSeconds, claimant);
489 assert.fail(noExpectedException);
490 } catch (e) {
491 assert(e instanceof DBErrors.UnexpectedResult);
492 }
493 });
494 }); // subscriptionDeliveryClaimById
495
496 describe('subscriptionDeliveryComplete', function () {
497 it('success', async function() {
498 const dbResult = {
499 changes: 1,
500 };
501 sinon.stub(db.statement.subscriptionDeliverySuccess, 'run').returns(dbResult);
502 sinon.stub(db.statement.subscriptionDeliveryDone, 'run').returns(dbResult);
503 await db.subscriptionDeliveryComplete(dbCtx, callback, topicId);
504 });
505 it('failure', async function () {
506 const dbResult = {
507 changes: 0,
508 };
509 sinon.stub(db.statement.subscriptionDeliverySuccess, 'run').returns(dbResult);
510 sinon.stub(db.statement.subscriptionDeliveryDone, 'run').returns(dbResult);
511 try {
512 await db.subscriptionDeliveryComplete(dbCtx, callback, topicId);
513 assert.fail(noExpectedException);
514 } catch (e) {
515 assert(e instanceof DBErrors.UnexpectedResult);
516 }
517 });
518 it('second failure', async function () {
519 const dbResult0 = {
520 changes: 1,
521 };
522 const dbResult1 = {
523 changes: 0,
524 };
525 sinon.stub(db.statement.subscriptionDeliverySuccess, 'run').returns(dbResult0);
526 sinon.stub(db.statement.subscriptionDeliveryDone, 'run').returns(dbResult1);
527 try {
528 await db.subscriptionDeliveryComplete(dbCtx, callback, topicId);
529 assert.fail(noExpectedException);
530 } catch (e) {
531 assert(e instanceof DBErrors.UnexpectedResult);
532 }
533 });
534 }); // subscriptionDeliveryComplete
535
536 describe('subscriptionDeliveryGone', function () {
537 it('success', async function() {
538 const dbResult = {
539 changes: 1,
540 };
541 sinon.stub(db.statement.subscriptionDelete, 'run').returns(dbResult);
542 await db.subscriptionDeliveryGone(dbCtx, callback, topicId);
543 });
544 it('failure', async function () {
545 const dbResult = {
546 changes: 0,
547 };
548 sinon.stub(db.statement.subscriptionDelete, 'run').returns(dbResult);
549 try {
550 await db.subscriptionDeliveryGone(dbCtx, callback, topicId);
551 assert.fail(noExpectedException);
552 } catch (e) {
553 assert(e instanceof DBErrors.UnexpectedResult);
554 }
555 });
556 }); // subscriptionDeliveryGone
557
558 describe('subscriptionDeliveryIncomplete', function () {
559 it('success', async function() {
560 const dbGet = { deliveryAttemptsSinceSuccess: 0 };
561 const dbResult = {
562 changes: 1,
563 };
564 sinon.stub(db.statement.subscriptionDeliveryAttempts, 'get').returns(dbGet);
565 sinon.stub(db.statement.subscriptionDeliveryFailure, 'run').returns(dbResult);
566 sinon.stub(db.statement.subscriptionDeliveryDone, 'run').returns(dbResult);
567 await db.subscriptionDeliveryIncomplete(dbCtx, callback, topicId, retryDelays);
568 });
569 it('success covers default', async function() {
570 const dbGet = { deliveryAttemptsSinceSuccess: 0 };
571 const dbResult = {
572 changes: 1,
573 };
574 sinon.stub(db.statement.subscriptionDeliveryAttempts, 'get').returns(dbGet);
575 sinon.stub(db.statement.subscriptionDeliveryFailure, 'run').returns(dbResult);
576 sinon.stub(db.statement.subscriptionDeliveryDone, 'run').returns(dbResult);
577 await db.subscriptionDeliveryIncomplete(dbCtx, callback, topicId);
578 });
579 it('failure', async function () {
580 const dbGet = { deliveryAttemptsSinceSuccess: 0 };
581 const dbResult = {
582 changes: 0,
583 };
584 sinon.stub(db.statement.subscriptionDeliveryAttempts, 'get').returns(dbGet);
585 sinon.stub(db.statement.subscriptionDeliveryFailure, 'run').returns(dbResult);
586 sinon.stub(db.statement.subscriptionDeliveryDone, 'run').returns(dbResult);
587 try {
588 await db.subscriptionDeliveryIncomplete(dbCtx, callback, topicId, retryDelays);
589 assert.fail(noExpectedException);
590 } catch (e) {
591 assert(e instanceof DBErrors.UnexpectedResult);
592 }
593 });
594 it('second failure', async function () {
595 const dbGet = { deliveryAttemptsSinceSuccess: 0 };
596 const dbResult0 = {
597 changes: 1,
598 };
599 const dbResult1 = {
600 changes: 0,
601 };
602 sinon.stub(db.statement.subscriptionDeliveryAttempts, 'get').returns(dbGet);
603 sinon.stub(db.statement.subscriptionDeliveryFailure, 'run').returns(dbResult0);
604 sinon.stub(db.statement.subscriptionDeliveryDone, 'run').returns(dbResult1);
605 try {
606 await db.subscriptionDeliveryIncomplete(dbCtx, callback, topicId, retryDelays);
607 assert.fail(noExpectedException);
608 } catch (e) {
609 assert(e instanceof DBErrors.UnexpectedResult);
610 }
611 });
612 }); // subscriptionDeliveryIncomplete
613
614 describe('subscriptionGet', function () {
615 it('success', async function() {
616 const expected = {
617 id: subscriptionId,
618 };
619 sinon.stub(db.statement.subscriptionGet, 'get').returns(expected);
620 const result = await db.subscriptionGet(dbCtx, callback, topicId);
621 assert.deepStrictEqual(result, expected);
622 });
623 it('failure', async function () {
624 const expected = new Error();
625 sinon.stub(db.statement.subscriptionGet, 'get').throws(expected);
626 try {
627 await db.subscriptionGet(dbCtx, callback, topicId);
628 assert.fail(noExpectedException);
629 } catch (e) {
630 assert.deepStrictEqual(e, expected);
631 }
632 });
633 }); // subscriptionGet
634
635 describe('subscriptionGetById', function () {
636 it('success', async function() {
637 const expected = {
638 id: subscriptionId,
639 };
640 sinon.stub(db.statement.subscriptionGetById, 'get').returns(expected);
641 const result = await db.subscriptionGetById(dbCtx, subscriptionId);
642 assert.deepStrictEqual(result, expected);
643 });
644 it('failure', async function () {
645 const expected = new Error();
646 sinon.stub(db.statement.subscriptionGetById, 'get').throws(expected);
647 try {
648 await db.subscriptionGetById(dbCtx, subscriptionId);
649 assert.fail(noExpectedException);
650 } catch (e) {
651 assert.deepStrictEqual(e, expected);
652 }
653 });
654 }); // subscriptionGetById
655
656 describe('subscriptionUpdate', function () {
657 let data;
658 beforeEach(function () {
659 data = {
660 subscriptionId,
661 signatureAlgorithm: 'sha256',
662 };
663 });
664 it('success', async function() {
665 const dbResult = {
666 changes: 1,
667 lastInsertRowid: subscriptionId,
668 };
669 sinon.stub(db.statement.subscriptionUpdate, 'run').returns(dbResult);
670 await db.subscriptionUpdate(dbCtx, data);
671 });
672 it('failure', async function () {
673 const dbResult = {
674 changes: 0,
675 };
676 sinon.stub(db.statement.subscriptionUpdate, 'run').returns(dbResult);
677 try {
678 await db.subscriptionUpdate(dbCtx, data);
679 assert.fail(noExpectedException);
680 } catch (e) {
681 assert(e instanceof DBErrors.UnexpectedResult, e);
682 }
683 });
684 }); // subscriptionUpdate
685
686 describe('subscriptionUpsert', function () {
687 let data;
688 beforeEach(function () {
689 data = {
690 callback,
691 topicId,
692 leaseSeconds,
693 secret,
694 httpRemoteAddr,
695 httpFrom,
696 };
697 });
698 it('success', async function() {
699 const dbResult = {
700 changes: 1,
701 lastInsertRowid: subscriptionId,
702 };
703 const expected = {
704 changes: 1,
705 lastInsertRowid: subscriptionId,
706 };
707 sinon.stub(db.statement.subscriptionUpsert, 'run').returns(dbResult);
708 const result = await db.subscriptionUpsert(dbCtx, data);
709 assert.deepStrictEqual(result, expected);
710 });
711 it('failure', async function () {
712 const dbResult = {
713 changes: 0,
714 };
715 sinon.stub(db.statement.subscriptionUpsert, 'run').returns(dbResult);
716 try {
717 await db.subscriptionUpsert(dbCtx, data);
718 assert.fail(noExpectedException);
719 } catch (e) {
720 assert(e instanceof DBErrors.UnexpectedResult);
721 }
722 });
723 }); // subscriptionUpsert
724
725 describe('topicDeleted', function () {
726 it('success', async function () {
727 sinon.stub(db.statement.topicDeleted, 'run').returns({ changes: 1 });
728 await db.topicDeleted(dbCtx, { topicId });
729 });
730 it('failure', async function () {
731 sinon.stub(db.statement.topicDeleted, 'run').returns({ changes: 0 });
732 try {
733 await db.topicDeleted(dbCtx, { topicId });
734 assert.fail(noExpectedException);
735 } catch (e) {
736 assert(e instanceof DBErrors.UnexpectedResult);
737 }
738 });
739 }); // topicDeleted
740
741 describe('topicFetchClaim', function () {
742 it('success', async function() {
743 const dbAll = [{ id: topicId }];
744 const dbResult = {
745 changes: 1,
746 };
747 const expected = [topicId];
748 sinon.stub(db.statement.topicContentFetchNeeded, 'all').returns(dbAll);
749 sinon.stub(db.statement.topicContentFetchClaimById, 'run').returns(dbResult);
750 const result = await db.topicFetchClaim(dbCtx, wanted, claimTimeoutSeconds, claimant);
751 assert.deepStrictEqual(result, expected);
752 });
753 it('failure', async function () {
754 const dbAll = [{ id: topicId }];
755 const dbResult = {
756 changes: 0,
757 };
758 sinon.stub(db.statement.topicContentFetchNeeded, 'all').returns(dbAll);
759 sinon.stub(db.statement.topicContentFetchClaimById, 'run').returns(dbResult);
760 try {
761 await db.topicFetchClaim(dbCtx, wanted, claimTimeoutSeconds, claimant);
762 assert.fail(noExpectedException);
763 } catch (e) {
764 assert(e instanceof DBErrors.UnexpectedResult);
765 }
766 });
767 }); // topicFetchClaim
768
769 describe('topicFetchClaimById', function () {
770 it('success', async function() {
771 const expected = {
772 changes: 1,
773 lastInsertRowid: undefined,
774 };
775 sinon.stub(db.statement.topicContentFetchClaimById, 'run').returns(expected);
776 const result = await db.topicFetchClaimById(dbCtx, topicId, claimTimeoutSeconds, claimant);
777 assert.deepStrictEqual(result, expected);
778 });
779 it('failure', async function () {
780 const expected = {
781 changes: 0,
782 lastInsertRowid: undefined,
783 };
784 sinon.stub(db.statement.topicContentFetchClaimById, 'run').returns(expected);
785 try {
786 await db.topicFetchClaimById(dbCtx, topicId, claimTimeoutSeconds, claimant);
787 assert.fail(noExpectedException);
788 } catch (e) {
789 assert(e instanceof DBErrors.UnexpectedResult);
790 }
791 });
792 }); // topicFetchClaimById
793
794 describe('topicFetchComplete', function () {
795 it('success', async function() {
796 const dbResult = {
797 changes: 1,
798 lastInsertRowid: undefined,
799 };
800 sinon.stub(db.statement.topicAttemptsReset, 'run').returns(dbResult);
801 sinon.stub(db.statement.topicContentFetchDone, 'run').returns(dbResult);
802 await db.topicFetchComplete(dbCtx, topicId);
803 });
804 it('failure', async function () {
805 const dbResult = {
806 changes: 0,
807 lastInsertRowid: undefined,
808 };
809 sinon.stub(db.statement.topicAttemptsReset, 'run').returns(dbResult);
810 sinon.stub(db.statement.topicContentFetchDone, 'run').returns(dbResult);
811 try {
812 await db.topicFetchComplete(dbCtx, topicId);
813 assert.fail(noExpectedException);
814 } catch (e) {
815 assert(e instanceof DBErrors.UnexpectedResult);
816 }
817 });
818 it('second failure', async function () {
819 const dbResult0 = {
820 changes: 1,
821 lastInsertRowid: undefined,
822 };
823 const dbResult1 = {
824 changes: 0,
825 lastInsertRowid: undefined,
826 };
827 sinon.stub(db.statement.topicAttemptsReset, 'run').returns(dbResult0);
828 sinon.stub(db.statement.topicContentFetchDone, 'run').returns(dbResult1);
829 try {
830 await db.topicFetchComplete(dbCtx, topicId);
831 assert.fail(noExpectedException);
832 } catch (e) {
833 assert(e instanceof DBErrors.UnexpectedResult);
834 }
835 });
836 }); // topicFetchComplete
837
838 describe('topicFetchIncomplete', function () {
839 it('success', async function() {
840 const dbGet = { currentAttempt: 0 };
841 const dbResult0 = {
842 changes: 1,
843 lastInsertRowid: undefined,
844 };
845 const dbResult1 = {
846 changes: 1,
847 lastInsertRowid: undefined,
848 }
849 const expected = {
850 changes: 1,
851 lastInsertRowid: undefined,
852 };
853 sinon.stub(db.statement.topicAttempts, 'get').returns(dbGet);
854 sinon.stub(db.statement.topicAttemptsIncrement, 'run').returns(dbResult0);
855 sinon.stub(db.statement.topicContentFetchDone, 'run').returns(dbResult1);
856 const result = await db.topicFetchIncomplete(dbCtx, topicId, retryDelays);
857 assert.deepStrictEqual(result, expected);
858 });
859 it('covers defaults', async function() {
860 const dbGet = { currentAttempt: 0 };
861 const dbResult0 = {
862 changes: 1,
863 lastInsertRowid: undefined,
864 };
865 const dbResult1 = {
866 changes: 1,
867 lastInsertRowid: undefined,
868 }
869 const expected = {
870 changes: 1,
871 lastInsertRowid: undefined,
872 };
873 sinon.stub(db.statement.topicAttempts, 'get').returns(dbGet);
874 sinon.stub(db.statement.topicAttemptsIncrement, 'run').returns(dbResult0);
875 sinon.stub(db.statement.topicContentFetchDone, 'run').returns(dbResult1);
876 const result = await db.topicFetchIncomplete(dbCtx, topicId);
877 assert.deepStrictEqual(result, expected);
878 });
879 it('failure', async function () {
880 const dbGet = { currentAttempt: 0 };
881 const dbResult0 = {
882 changes: 1,
883 lastInsertRowid: undefined,
884 };
885 const dbResult1 = {
886 changes: 0,
887 lastInsertRowid: undefined,
888 }
889 sinon.stub(db.statement.topicAttempts, 'get').returns(dbGet);
890 sinon.stub(db.statement.topicAttemptsIncrement, 'run').returns(dbResult0);
891 sinon.stub(db.statement.topicContentFetchDone, 'run').returns(dbResult1);
892 try {
893 await db.topicFetchIncomplete(dbCtx, topicId, retryDelays);
894 assert.fail(noExpectedException);
895 } catch (e) {
896 assert(e instanceof DBErrors.UnexpectedResult);
897 }
898 });
899 it('second failure', async function () {
900 const dbGet = { currentAttempt: 0 };
901 const dbResult0 = {
902 changes: 0,
903 lastInsertRowid: undefined,
904 };
905 const dbResult1 = {
906 changes: 0,
907 lastInsertRowid: undefined,
908 }
909 sinon.stub(db.statement.topicAttempts, 'get').returns(dbGet);
910 sinon.stub(db.statement.topicAttemptsIncrement, 'run').returns(dbResult0);
911 sinon.stub(db.statement.topicContentFetchDone, 'run').returns(dbResult1);
912 try {
913 await db.topicFetchIncomplete(dbCtx, topicId, retryDelays);
914 assert.fail(noExpectedException);
915 } catch (e) {
916 assert(e instanceof DBErrors.UnexpectedResult);
917 }
918 });
919 }); // topicFetchIncomplete
920
921 describe('topicFetchRequested', function () {
922 it('success', async function() {
923 const dbResult = {
924 changes: 1,
925 lastInsertRowid: undefined,
926 };
927 const expected = {
928 changes: 1,
929 lastInsertRowid: undefined,
930 };
931 sinon.stub(db.statement.topicContentFetchRequested, 'run').returns(dbResult);
932 const result = await db.topicFetchRequested(dbCtx, topicId);
933 assert.deepStrictEqual(result, expected);
934 });
935 it('failure', async function () {
936 const dbResult = {
937 changes: 0,
938 lastInsertRowid: undefined,
939 };
940 sinon.stub(db.statement.topicContentFetchRequested, 'run').returns(dbResult);
941 try {
942 await db.topicFetchRequested(dbCtx, topicId);
943 assert.fail(noExpectedException);
944 } catch (e) {
945 assert(e instanceof DBErrors.UnexpectedResult);
946 }
947 });
948 }); // topicFetchRequested
949
950 describe('topicGetAll', function () {
951 it('success', async function() {
952 const expected = [{ id: topicId }];
953 sinon.stub(db.statement.topicGetInfoAll, 'all').returns(expected);
954 const result = await db.topicGetAll(dbCtx);
955 assert.deepStrictEqual(result, expected);
956 });
957 it('covers none', async function() {
958 const expected = undefined;
959 sinon.stub(db.statement.topicGetInfoAll, 'all').returns(expected);
960 const result = await db.topicGetAll(dbCtx);
961 assert.deepStrictEqual(result, expected);
962 });
963 it('failure', async function () {
964 const expected = new Error();
965 sinon.stub(db.statement.topicGetInfoAll, 'all').throws(expected);
966 try {
967 await db.topicGetAll(dbCtx);
968 assert.fail(noExpectedException);
969 } catch (e) {
970 assert.deepStrictEqual(e, expected);
971 }
972 });
973 }); // topicGetById
974
975 describe('topicGetById', function () {
976 it('success', async function() {
977 const expected = { id: topicId };
978 sinon.stub(db.statement.topicGetById, 'get').returns(expected);
979 const result = await db.topicGetById(dbCtx, topicId);
980 assert.deepStrictEqual(result, expected);
981 });
982 it('covers no defaults', async function () {
983 const expected = { id: topicId };
984 sinon.stub(db.statement.topicGetById, 'get').returns(expected);
985 const result = await db.topicGetById(dbCtx, topicId, false);
986 assert.deepStrictEqual(result, expected);
987 });
988 it('covers default', async function() {
989 const expected = undefined;
990 sinon.stub(db.statement.topicGetById, 'get').returns(expected);
991 const result = await db.topicGetById(dbCtx, topicId);
992 assert.deepStrictEqual(result, expected);
993 });
994 it('failure', async function () {
995 const expected = new Error();
996 sinon.stub(db.statement.topicGetById, 'get').throws(expected);
997 try {
998 await db.topicGetById(dbCtx, topicId);
999 assert.fail(noExpectedException);
1000 } catch (e) {
1001 assert.deepStrictEqual(e, expected);
1002 }
1003 });
1004 }); // topicGetById
1005
1006 describe('topicGetByUrl', function () {
1007 it('success', async function() {
1008 const expected = [];
1009 sinon.stub(db.statement.topicGetByUrl, 'get').returns(expected);
1010 const result = await db.topicGetByUrl(dbCtx, topicUrl);
1011 assert.deepStrictEqual(result, expected);
1012 });
1013 it('failure', async function () {
1014 const expected = new Error();
1015 sinon.stub(db.statement.topicGetByUrl, 'get').throws(expected);
1016 try {
1017 await db.topicGetByUrl(dbCtx, topicUrl);
1018 assert.fail(noExpectedException);
1019 } catch (e) {
1020 assert.deepStrictEqual(e, expected);
1021 }
1022 });
1023 }); // topicGetByUrl
1024
1025 describe('topicGetContentById', function () {
1026 it('success', async function() {
1027 const expected = { id: topicId };
1028 sinon.stub(db.statement.topicGetContentById, 'get').returns(expected);
1029 const result = await db.topicGetContentById(dbCtx, topicId);
1030 assert.deepStrictEqual(result, expected);
1031 });
1032 it('covers default', async function() {
1033 const expected = undefined;
1034 sinon.stub(db.statement.topicGetContentById, 'get').returns(expected);
1035 const result = await db.topicGetContentById(dbCtx, topicId);
1036 assert.deepStrictEqual(result, expected);
1037 });
1038 it('failure', async function () {
1039 const expected = new Error();
1040 sinon.stub(db.statement.topicGetContentById, 'get').throws(expected);
1041 try {
1042 await db.topicGetContentById(dbCtx, topicId);
1043 assert.fail(noExpectedException);
1044 } catch (e) {
1045 assert.deepStrictEqual(e, expected);
1046 }
1047 });
1048 }); // topicGetContentById
1049
1050 describe('topicPendingDelete', function () {
1051 beforeEach(function () {
1052 sinon.stub(db.statement.topicGetById, 'get');
1053 sinon.stub(db.statement.subscriptionCountByTopicUrl, 'get');
1054 sinon.stub(db.statement.topicDeleteById, 'run');
1055 });
1056 it('success', async function () {
1057 db.statement.topicGetById.get.returns({
1058 id: topicId,
1059 isDeleted: true,
1060 });
1061 db.statement.subscriptionCountByTopicUrl.get.returns({
1062 count: 0,
1063 });
1064 db.statement.topicDeleteById.run.returns({
1065 changes: 1,
1066 });
1067 db.topicPendingDelete(dbCtx, topicId);
1068 assert(db.statement.topicDeleteById.run.called);
1069 });
1070 it('does not delete non-deleted topic', async function () {
1071 db.statement.topicGetById.get.returns({
1072 id: topicId,
1073 isDeleted: false,
1074 });
1075 db.statement.subscriptionCountByTopicUrl.get.returns({
1076 count: 0,
1077 });
1078 db.statement.topicDeleteById.run.returns({
1079 changes: 1,
1080 });
1081 db.topicPendingDelete(dbCtx, topicId);
1082 assert(!db.statement.topicDeleteById.run.called);
1083 });
1084 it('does not delete topic with active subscriptions', async function () {
1085 db.statement.topicGetById.get.returns({
1086 id: topicId,
1087 isDeleted: true,
1088 });
1089 db.statement.subscriptionCountByTopicUrl.get.returns({
1090 count: 10,
1091 });
1092 db.statement.topicDeleteById.run.returns({
1093 changes: 1,
1094 });
1095 db.topicPendingDelete(dbCtx, topicId);
1096 assert(!db.statement.topicDeleteById.run.called);
1097 });
1098 it('covers no deletion', async function () {
1099 db.statement.topicGetById.get.returns({
1100 id: topicId,
1101 isDeleted: true,
1102 });
1103 db.statement.subscriptionCountByTopicUrl.get.returns({
1104 count: 0,
1105 });
1106 db.statement.topicDeleteById.run.returns({
1107 changes: 0,
1108 });
1109 try {
1110 db.topicPendingDelete(dbCtx, topicId);
1111 assert.fail(noExpectedException);
1112
1113 } catch (e) {
1114 assert(e instanceof DBErrors.UnexpectedResult);
1115 }
1116 assert(db.statement.topicDeleteById.run.called);
1117 });
1118 });
1119
1120 describe('topicSet', function () {
1121 let data;
1122 beforeEach(function () {
1123 data = {
1124 url: topicUrl,
1125 };
1126 });
1127 it('success', async function() {
1128 const dbResult = {
1129 changes: 1,
1130 lastInsertRowid: topicId,
1131 };
1132 const expected = {
1133 changes: 1,
1134 lastInsertRowid: topicId,
1135 };
1136 sinon.stub(db.statement.topicUpsert, 'run').returns(dbResult);
1137 const result = await db.topicSet(dbCtx, data);
1138 assert.deepStrictEqual(result, expected);
1139 });
1140 it('failure', async function () {
1141 const dbResult = {
1142 changes: 0,
1143 lastInsertRowid: undefined,
1144 };
1145 sinon.stub(db.statement.topicUpsert, 'run').returns(dbResult);
1146 try {
1147 await db.topicSet(dbCtx, data);
1148 assert.fail(noExpectedException);
1149 } catch (e) {
1150 assert(e instanceof DBErrors.UnexpectedResult);
1151 }
1152 });
1153 it('fails invalid value', async function () {
1154 sinon.stub(db.statement.topicUpsert, 'run');
1155 try {
1156 data.leaseSecondsPreferred = -100;
1157 await db.topicSet(dbCtx, data);
1158 assert.fail(noExpectedException);
1159 } catch (e) {
1160 assert(e instanceof DBErrors.DataValidation);
1161 }
1162 assert(!db.statement.topicUpsert.run.called);
1163 });
1164 it('fails invalid values', async function () {
1165 sinon.stub(db.statement.topicUpsert, 'run');
1166 try {
1167 data.leaseSecondsPreferred = 10;
1168 data.leaseSecondsMax = 100;
1169 data.leaseSecondsMin = 50;
1170 await db.topicSet(dbCtx, data);
1171 assert.fail(noExpectedException);
1172 } catch (e) {
1173 assert(e instanceof DBErrors.DataValidation);
1174 }
1175 assert(!db.statement.topicUpsert.run.called);
1176 });
1177 }); // topicSet
1178
1179 describe('topicSetContent', function () {
1180 let data;
1181 beforeEach(function () {
1182 data = {
1183 content: 'content',
1184 contentType: 'text/plain',
1185 contentHash: 'abc123',
1186 };
1187 });
1188 it('success', async function() {
1189 const dbResult = {
1190 changes: 1,
1191 lastInsertRowid: undefined,
1192 };
1193 const expected = {
1194 changes: 1,
1195 lastInsertRowid: undefined,
1196 };
1197 sinon.stub(db.statement.topicSetContent, 'run').returns(dbResult);
1198 const result = await db.topicSetContent(dbCtx, data);
1199 assert.deepStrictEqual(result, expected);
1200 });
1201 it('failure', async function () {
1202 const dbResult = {
1203 changes: 0,
1204 lastInsertRowid: undefined,
1205 };
1206 sinon.stub(db.statement.topicSetContent, 'run').returns(dbResult);
1207 try {
1208 await db.topicSetContent(dbCtx, data);
1209 assert.fail(noExpectedException);
1210 } catch (e) {
1211 assert(e instanceof DBErrors.UnexpectedResult);
1212 }
1213 });
1214 }); // topicSetContent
1215
1216 describe('topicUpdate', function () {
1217 let data;
1218 beforeEach(function () {
1219 data = {
1220 topicId,
1221 leaseSecondsPreferred: 9999,
1222 leaseSecondsMax: 99999,
1223 leaseSecondsMin: 999,
1224 publisherValidationUrl: null,
1225 contentHashAlgorithm: 'sha256',
1226 };
1227 });
1228 it('success', async function() {
1229 const dbResult = {
1230 changes: 1,
1231 lastInsertRowid: topicId,
1232 };
1233 sinon.stub(db.statement.topicUpdate, 'run').returns(dbResult);
1234 await db.topicUpdate(dbCtx, data);
1235 });
1236 it('failure', async function () {
1237 const dbResult = {
1238 changes: 0,
1239 lastInsertRowid: undefined,
1240 };
1241 sinon.stub(db.statement.topicUpdate, 'run').returns(dbResult);
1242 try {
1243 await db.topicUpdate(dbCtx, data);
1244 assert.fail(noExpectedException);
1245 } catch (e) {
1246 assert(e instanceof DBErrors.UnexpectedResult, e);
1247 }
1248 });
1249 it('fails invalid value', async function () {
1250 sinon.stub(db.statement.topicUpdate, 'run');
1251 try {
1252 data.leaseSecondsPreferred = -100;
1253 await db.topicUpdate(dbCtx, data);
1254 assert.fail(noExpectedException);
1255 } catch (e) {
1256 assert(e instanceof DBErrors.DataValidation, e);
1257 }
1258 assert(!db.statement.topicUpdate.run.called);
1259 });
1260 it('fails invalid values', async function () {
1261 sinon.stub(db.statement.topicUpdate, 'run');
1262 try {
1263 data.leaseSecondsPreferred = 10;
1264 data.leaseSecondsMax = 100;
1265 data.leaseSecondsMin = 50;
1266 await db.topicUpdate(dbCtx, data);
1267 assert.fail(noExpectedException);
1268 } catch (e) {
1269 assert(e instanceof DBErrors.DataValidation, e);
1270 }
1271 assert(!db.statement.topicUpdate.run.called);
1272 });
1273 }); // topicUpdate
1274
1275 describe('verificationClaim', function () {
1276 it('success', async function() {
1277 const dbAll = [{ id: verificationId }];
1278 const dbRun = {
1279 changes: 1,
1280 lastInsertRowid: undefined,
1281 };
1282 const expected = [verificationId];
1283 sinon.stub(db.statement.verificationNeeded, 'all').returns(dbAll);
1284 sinon.stub(db.statement.verificationClaimById, 'run').returns(dbRun);
1285 const result = await db.verificationClaim(dbCtx, wanted, claimTimeoutSeconds, claimant);
1286 assert.deepStrictEqual(result, expected);
1287 });
1288 it('failure', async function () {
1289 const dbAll = [{ id: verificationId }];
1290 const dbRun = {
1291 changes: 0,
1292 lastInsertRowid: undefined,
1293 };
1294 sinon.stub(db.statement.verificationNeeded, 'all').returns(dbAll);
1295 sinon.stub(db.statement.verificationClaimById, 'run').returns(dbRun);
1296 try {
1297 await db.verificationClaim(dbCtx, wanted, claimTimeoutSeconds, claimant);
1298 assert.fail(noExpectedException);
1299 } catch (e) {
1300 assert(e instanceof DBErrors.UnexpectedResult);
1301 }
1302 });
1303 }); // verificationClaim
1304
1305 describe('verificationClaimById', function () {
1306 it('success', async function() {
1307 const dbRun = {
1308 changes: 1,
1309 lastInsertRowid: undefined,
1310 };
1311 sinon.stub(db.statement.verificationClaimById, 'run').returns(dbRun);
1312 const result = await db.verificationClaimById(dbCtx, verificationId, claimTimeoutSeconds, claimant);
1313 assert.deepStrictEqual(result, dbRun);
1314 });
1315 it('failure', async function () {
1316 const dbRun = {
1317 changes: 0,
1318 lastInsertRowid: undefined,
1319 };
1320 sinon.stub(db.statement.verificationClaimById, 'run').returns(dbRun);
1321 try {
1322 await db.verificationClaimById(dbCtx, verificationId, claimTimeoutSeconds, claimant);
1323 assert.fail(noExpectedException);
1324 } catch (e) {
1325 assert(e instanceof DBErrors.UnexpectedResult);
1326 }
1327 });
1328 }); // verificationClaimById
1329
1330 describe('verificationComplete', function () {
1331 it('success', async function() {
1332 const dbResult = {
1333 changes: 1,
1334 lastInsertRowid: undefined,
1335 };
1336 sinon.stub(db.statement.verificationScrub, 'run').returns(dbResult);
1337 await db.verificationComplete(dbCtx, verificationId, callback, topicId);
1338 });
1339 it('failure', async function () {
1340 const dbResult = {
1341 changes: 0,
1342 lastInsertRowid: undefined,
1343 };
1344 sinon.stub(db.statement.verificationScrub, 'run').returns(dbResult);
1345 try {
1346 await db.verificationComplete(dbCtx, verificationId, callback, topicId);
1347 assert.fail(noExpectedException);
1348 } catch (e) {
1349 assert(e instanceof DBErrors.UnexpectedResult);
1350 }
1351 });
1352 }); // verificationComplete
1353
1354 describe('verificationGetById', function () {
1355 it('success', async function() {
1356 const dbOneOrNone = { id: verificationId, isPublisherValidated: 1 };
1357 const expected = { id: verificationId, isPublisherValidated: true };
1358 sinon.stub(db.statement.verificationGetById, 'get').returns(dbOneOrNone);
1359 const result = await db.verificationGetById(dbCtx, verificationId);
1360 assert.deepStrictEqual(result, expected);
1361 });
1362 it('failure', async function () {
1363 const expected = new Error();
1364 sinon.stub(db.statement.verificationGetById, 'get').throws(expected);
1365 try {
1366 await db.verificationGetById(dbCtx, verificationId);
1367 assert.fail(noExpectedException);
1368 } catch (e) {
1369 assert.deepStrictEqual(e, expected);
1370 }
1371 });
1372 }); // verificationGetById
1373
1374 describe('verificationIncomplete', function () {
1375 it('success', async function() {
1376 const dbOne = { attempts: 0 };
1377 const dbResult0 = {
1378 changes: 1,
1379 lastInsertRowid: undefined,
1380 };
1381 const dbResult1 = {
1382 changes: 1,
1383 lastInsertRowid: undefined,
1384 };
1385 sinon.stub(db.statement.verificationAttempts, 'get').returns(dbOne);
1386 sinon.stub(db.statement.verificationAttemptsIncrement, 'run').returns(dbResult0);
1387 sinon.stub(db.statement.verificationDone, 'run').returns(dbResult1);
1388 await db.verificationIncomplete(dbCtx, verificationId, retryDelays);
1389 });
1390 it('covers defaults', async function() {
1391 const dbOne = { attempts: 0 };
1392 const dbResult0 = {
1393 changes: 1,
1394 lastInsertRowid: undefined,
1395 };
1396 const dbResult1 = {
1397 changes: 1,
1398 lastInsertRowid: undefined,
1399 };
1400 sinon.stub(db.statement.verificationAttempts, 'get').returns(dbOne);
1401 sinon.stub(db.statement.verificationAttemptsIncrement, 'run').returns(dbResult0);
1402 sinon.stub(db.statement.verificationDone, 'run').returns(dbResult1);
1403 await db.verificationIncomplete(dbCtx, verificationId);
1404 });
1405 it('failure', async function () {
1406 const dbOne = { attempts: 0 };
1407 const dbResult0 = {
1408 changes: 0,
1409 lastInsertRowid: undefined,
1410 };
1411 const dbResult1 = {
1412 changes: 1,
1413 lastInsertRowid: undefined,
1414 };
1415 sinon.stub(db.statement.verificationAttempts, 'get').returns(dbOne);
1416 sinon.stub(db.statement.verificationAttemptsIncrement, 'run').returns(dbResult0);
1417 sinon.stub(db.statement.verificationDone, 'run').returns(dbResult1);
1418 try {
1419 await db.verificationIncomplete(dbCtx, verificationId, retryDelays);
1420 assert.fail(noExpectedException);
1421 } catch (e) {
1422 assert(e instanceof DBErrors.UnexpectedResult);
1423 }
1424 });
1425 it('second failure', async function () {
1426 const dbOne = { attempts: 0 };
1427 const dbResult0 = {
1428 changes: 1,
1429 lastInsertRowid: undefined,
1430 };
1431 const dbResult1 = {
1432 changes: 0,
1433 lastInsertRowid: undefined,
1434 };
1435 sinon.stub(db.statement.verificationAttempts, 'get').returns(dbOne);
1436 sinon.stub(db.statement.verificationAttemptsIncrement, 'run').returns(dbResult0);
1437 sinon.stub(db.statement.verificationDone, 'run').returns(dbResult1);
1438 try {
1439 await db.verificationIncomplete(dbCtx, verificationId, retryDelays);
1440 assert.fail(noExpectedException);
1441 } catch (e) {
1442 assert(e instanceof DBErrors.UnexpectedResult);
1443 }
1444 });
1445 }); // verificationIncomplete
1446
1447 describe('_verificationDataToEngine', function () {
1448 it('covers no data', function () {
1449 DB._verificationDataToEngine();
1450 });
1451 it('covers true', function () {
1452 const data = {
1453 isPublisherValidated: true,
1454 };
1455 DB._verificationDataToEngine(data);
1456 assert.strictEqual(data.isPublisherValidated, 1);
1457 });
1458 it('covers false', function () {
1459 const data = {
1460 isPublisherValidated: false,
1461 };
1462 DB._verificationDataToEngine(data);
1463 assert.strictEqual(data.isPublisherValidated, 0);
1464 });
1465 }) // _verificationDataToEngine
1466
1467 describe('verificationInsert', function () {
1468 let verification;
1469 beforeEach(function () {
1470 verification = {
1471 topicId,
1472 callback,
1473 mode: 'subscribe',
1474 isPublisherValidated: true,
1475 leaseSeconds: 86400,
1476 };
1477 });
1478 it('success', async function() {
1479 const dbResult = {
1480 changes: 1,
1481 lastInsertRowid: verificationId,
1482 };
1483 const expected = verificationId;
1484 sinon.stub(db.statement.verificationInsert, 'run').returns(dbResult);
1485 const result = await db.verificationInsert(dbCtx, verification);
1486 assert.deepStrictEqual(result, expected);
1487 });
1488 it('failure', async function () {
1489 const dbResult = {
1490 changes: 0,
1491 lastInsertRowid: undefined,
1492 };
1493 sinon.stub(db.statement.verificationInsert, 'run').returns(dbResult);
1494 try {
1495 await db.verificationInsert(dbCtx, verification);
1496 assert.fail(noExpectedException);
1497 } catch (e) {
1498 assert(e instanceof DBErrors.UnexpectedResult);
1499 }
1500 });
1501 it('fails validation', async function () {
1502 delete verification.leaseSeconds;
1503 try {
1504 await db.verificationInsert(dbCtx, verification);
1505 assert.fail(noExpectedException);
1506 } catch (e) {
1507 assert(e instanceof DBErrors.DataValidation);
1508 }
1509 });
1510 }); // verificationInsert
1511
1512 describe('verificationRelease', function () {
1513 it('success', async function() {
1514 const dbResult = {
1515 changes: 1,
1516 lastInsertRowid: undefined,
1517 };
1518 sinon.stub(db.statement.verificationDone, 'run').returns(dbResult);
1519 await db.verificationRelease(dbCtx, verificationId);
1520 });
1521 it('failure', async function () {
1522 const dbResult = {
1523 changes: 0,
1524 lastInsertRowid: undefined,
1525 };
1526 sinon.stub(db.statement.verificationDone, 'run').returns(dbResult);
1527 try {
1528 await db.verificationRelease(dbCtx, verificationId);
1529 assert.fail(noExpectedException);
1530 } catch (e) {
1531 assert(e instanceof DBErrors.UnexpectedResult);
1532 }
1533 });
1534 }); // verificationRelease
1535
1536 describe('verificationUpdate', function () {
1537 let data;
1538 beforeEach(function () {
1539 data = {
1540 mode: 'subscribe',
1541 isPublisherValidated: true,
1542 };
1543 });
1544 it('success', async function() {
1545 const dbResult = {
1546 changes: 1,
1547 lastInsertRowid: undefined,
1548 };
1549 sinon.stub(db.statement.verificationUpdate, 'run').returns(dbResult);
1550 await db.verificationUpdate(dbCtx, verificationId, data);
1551 });
1552 it('failure', async function () {
1553 const dbResult = {
1554 changes: 0,
1555 lastInsertRowid: undefined,
1556 }
1557 sinon.stub(db.statement.verificationUpdate, 'run').returns(dbResult);
1558 try {
1559 await db.verificationUpdate(dbCtx, verificationId, data);
1560 assert.fail(noExpectedException);
1561 } catch (e) {
1562 assert(e instanceof DBErrors.UnexpectedResult, e.name);
1563 }
1564 });
1565 it('fails validation', async function () {
1566 delete data.mode;
1567 try {
1568 await db.verificationUpdate(dbCtx, data);
1569 assert.fail(noExpectedException);
1570 } catch (e) {
1571 assert(e instanceof DBErrors.DataValidation);
1572 }
1573 });
1574 }); // verificationUpdate
1575
1576 describe('verificationValidated', function () {
1577 it('success', async function() {
1578 const dbResult = {
1579 changes: 1,
1580 lastInsertRowid: undefined,
1581 }
1582 sinon.stub(db.statement.verificationValidate, 'run').returns(dbResult);
1583 await db.verificationValidated(dbCtx, verificationId);
1584 });
1585 it('failure', async function () {
1586 const dbResult = {
1587 changes: 0,
1588 lastInsertRowid: undefined,
1589 }
1590 sinon.stub(db.statement.verificationValidate, 'run').returns(dbResult);
1591 try {
1592 await db.verificationValidated(dbCtx, verificationId);
1593 assert.fail(noExpectedException);
1594 } catch (e) {
1595 assert(e instanceof DBErrors.UnexpectedResult);
1596 }
1597 });
1598 }); // verificationValidated
1599
1600 }); // DatabaseSQLite