3 const assert
= require('assert');
4 const sinon
= require('sinon');
6 const StubDatabase
= require('../../stub-db');
7 const StubLogger
= require('../../stub-logger');
8 const DB
= require('../../../src/db/abstract');
9 const DBErrors
= require('../../../src/db/errors');
11 describe('DatabaseBase', function () {
12 let db
, logger
, stubDb
;
14 logger
= new StubLogger();
16 stubDb
= new StubDatabase();
18 beforeEach(function () {
19 db
= new DB(logger
, {});
21 afterEach(function () {
25 it('covers no options', function () {
29 describe('Interface', function () {
30 it('covers abstract methods', async
function () {
31 await Promise
.all(stubDb
._implementation
.map(async (m
) => {
33 // eslint-disable-next-line security/detect-object-injection
35 assert
.fail(`${m}: did not catch NotImplemented exception`);
37 assert(e
instanceof DBErrors
.NotImplemented
, `${m}: unexpected exception ${e.name}`);
40 }); // covers abstract methods
41 it('covers private abstract methods', async
function () {
46 // eslint-disable-next-line security/detect-object-injection
49 assert(e
instanceof DBErrors
.NotImplemented
, `${m}: unexpected exception ${e.name}`);
55 describe('_ensureTypes', function () {
57 beforeEach(function () {
59 array: ['foo', 'bar'],
61 buf: Buffer
.from('foop'),
68 uuid: 'a4dd5106-2d64-11ed-a2ba-0025905f714a',
72 it('succeeds', function () {
73 db
._ensureTypes(object
, ['array'], ['array']);
74 db
._ensureTypes(object
, ['bignum'], ['bigint']);
75 db
._ensureTypes(object
, ['bignum', 'num'], ['number']);
76 db
._ensureTypes(object
, ['buf'], ['buffer']);
77 db
._ensureTypes(object
, ['date'], ['date']);
78 db
._ensureTypes(object
, ['infP', 'infN'], ['infinites']);
79 db
._ensureTypes(object
, ['str', 'veryNull'], ['string', 'null']);
81 it('data failure', function () {
82 assert
.throws(() => db
._ensureTypes(object
, ['missingField'], ['string', 'null']), DBErrors
.DataValidation
);
84 it('failure covers singular', function () {
86 db
._ensureTypes(object
, ['missingField'], ['string']);
87 assert
.fail('validation should have failed');
89 assert(e
instanceof DBErrors
.DataValidation
);
92 it('parameter failure', function () {
94 db
._ensureTypes(object
, ['missingField'], undefined);
95 assert
.fail('validation should have failed');
97 assert(e
instanceof DBErrors
.DataValidation
);
100 it('covers unknown type', function () {
101 assert
.throws(() => db
._ensureTypes(object
, ['field'], ['not a type']));
105 describe('_validateAuthentication', function () {
107 beforeEach(function () {
109 identifier: 'username',
110 credential: '$plain$secret',
112 lastAuthentication: -Infinity
,
115 it('covers', function () {
116 db
._validateAuthentication(authentication
);
118 it('covers failure', function () {
119 assert
.throws(() => db
._validateAuthentication(undefined), DBErrors
.DataValidation
);
121 }); // _validateAuthentication
123 describe('_validateResource', function () {
125 beforeEach(function () {
127 resourceId: '42016c1e-2d66-11ed-9e10-0025905f714a',
128 secret: 'secretSecret',
129 description: 'Some other service',
133 it('covers', function () {
134 db
._validateResource(resource
);
136 it('covers failure', function () {
137 assert
.throws(() => db
._validateResource(undefined), DBErrors
.DataValidation
);
139 }); // _validateResource
141 describe('_validateToken', function () {
143 beforeEach(function () {
145 codeId: '9efc7882-2d66-11ed-b03c-0025905f714a',
146 profile: 'https://profile.example.com/',
148 clientId: 'https://app.example.com/',
151 refreshExpires: null,
157 name: 'User von Namey',
161 it('covers', function () {
162 db
._validateToken(token
);
164 it('covers failure', function () {
165 assert
.throws(() => db
._validateToken(undefined), DBErrors
.DataValidation
);
167 }); // _validateToken
169 describe('_profilesScopesBuilder', function () {
170 it('covers empty', function () {
171 const result
= DB
._profilesScopesBuilder();
172 assert
.deepStrictEqual(result
, {
178 it('builds expected structure', function () {
179 const profileScopesRows
= [
180 { profile: 'https://scopeless.example.com/', scope: null, description: null, application: null, isPermanent: null, isManuallyAdded: null },
181 { profile: 'https://profile.example.com/', scope: 'role:private', description: 'level', application: '', isPermanent: false, isManuallyAdded: true },
182 { profile: null, scope: 'profile', description: 'profile', application: 'IndieAuth', isPermanent: true, isManuallyAdded: false },
183 { profile: null, scope: 'role:private', description: 'level', application: '', isPermanent: false, isManuallyAdded: true },
184 { profile: null, scope: 'read', description: 'read', application: 'MicroPub', isPermanent: true, isManuallyAdded: false },
185 { profile: 'https://profile.example.com/', scope: 'profile', description: 'profile', application: 'IndieAuth', isPermanent: true, isManuallyAdded: false },
186 { profile: 'https://another.example.com/', scope: 'profile', description: 'profile', application: 'IndieAuth', isPermanent: true, isManuallyAdded: false },
190 'https://scopeless.example.com/': {},
191 'https://profile.example.com/': {},
192 'https://another.example.com/': {},
196 description: 'level',
199 isManuallyAdded: true,
200 profiles: ['https://profile.example.com/'],
203 description: 'profile',
204 application: 'IndieAuth',
206 isManuallyAdded: false,
207 profiles: ['https://profile.example.com/', 'https://another.example.com/'],
211 application: 'MicroPub',
213 isManuallyAdded: false,
217 profiles: ['https://scopeless.example.com/', 'https://profile.example.com/', 'https://another.example.com/'],
219 expected
.profileScopes
['https://profile.example.com/']['role:private'] = expected
.scopeIndex
['role:private'];
220 expected
.profileScopes
['https://profile.example.com/']['profile'] = expected
.scopeIndex
['profile'];
221 expected
.profileScopes
['https://another.example.com/']['profile'] = expected
.scopeIndex
['profile'];
223 const result
= DB
._profilesScopesBuilder(profileScopesRows
);
224 assert
.deepStrictEqual(result
, expected
);
226 }); // _profilesScopesBuilder
228 describe('initialize', function () {
230 beforeEach(function () {
236 db
.schemaVersionsSupported
= {
237 min: { ...currentSchema
},
238 max: { ...currentSchema
},
240 sinon
.stub(db
, '_currentSchema').resolves(currentSchema
);
242 it('covers success', async
function () {
243 await db
.initialize();
245 it('covers failure', async
function() {
246 db
.schemaVersionsSupported
= {
259 await db
.initialize();
260 assert
.fail('did not get expected exception');
262 assert(e
instanceof DBErrors
.MigrationNeeded
);