@adaptivestone/framework 4.7.0 → 4.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +15 -1
- package/Cli.js +1 -0
- package/commands/SyncIndexes.js +1 -1
- package/commands/migration/Create.js +4 -3
- package/controllers/Auth.js +3 -5
- package/controllers/index.js +0 -2
- package/coverage/base.css +224 -0
- package/coverage/block-navigation.js +87 -0
- package/coverage/clover.xml +3573 -0
- package/coverage/coverage-final.json +44 -0
- package/coverage/favicon.png +0 -0
- package/coverage/framework/config/auth.js.html +100 -0
- package/coverage/framework/config/http.js.html +112 -0
- package/coverage/framework/config/i18n.js.html +121 -0
- package/coverage/framework/config/index.html +236 -0
- package/coverage/framework/config/log.js.html +151 -0
- package/coverage/framework/config/mail.js.html +172 -0
- package/coverage/framework/config/mongo.js.html +94 -0
- package/coverage/framework/config/rateLimiter.js.html +133 -0
- package/coverage/framework/config/redis.js.html +97 -0
- package/coverage/framework/config/validate.js.html +94 -0
- package/coverage/framework/controllers/Auth.js.html +715 -0
- package/coverage/framework/controllers/Home.js.html +169 -0
- package/coverage/framework/controllers/index.html +146 -0
- package/coverage/framework/controllers/index.js.html +259 -0
- package/coverage/framework/controllers/test/SomeController.js.html +571 -0
- package/coverage/framework/controllers/test/index.html +116 -0
- package/coverage/framework/helpers/files.js.html +310 -0
- package/coverage/framework/helpers/index.html +131 -0
- package/coverage/framework/helpers/logger.js.html +142 -0
- package/coverage/framework/helpers/redis/clearNamespace.js.html +127 -0
- package/coverage/framework/helpers/redis/index.html +116 -0
- package/coverage/framework/index.html +116 -0
- package/coverage/framework/models/Migration.js.html +130 -0
- package/coverage/framework/models/Sequence.js.html +151 -0
- package/coverage/framework/models/User.js.html +859 -0
- package/coverage/framework/models/index.html +146 -0
- package/coverage/framework/modules/AbstractController.js.html +1309 -0
- package/coverage/framework/modules/AbstractModel.js.html +268 -0
- package/coverage/framework/modules/Base.js.html +244 -0
- package/coverage/framework/modules/index.html +146 -0
- package/coverage/framework/server.js.html +1279 -0
- package/coverage/framework/services/cache/Cache.js.html +445 -0
- package/coverage/framework/services/cache/index.html +116 -0
- package/coverage/framework/services/documentation/DocumentationGenerator.js.html +592 -0
- package/coverage/framework/services/documentation/index.html +116 -0
- package/coverage/framework/services/http/HttpServer.js.html +373 -0
- package/coverage/framework/services/http/index.html +116 -0
- package/coverage/framework/services/http/middleware/AbstractMiddleware.js.html +238 -0
- package/coverage/framework/services/http/middleware/Auth.js.html +145 -0
- package/coverage/framework/services/http/middleware/GetUserByToken.js.html +223 -0
- package/coverage/framework/services/http/middleware/I18n.js.html +442 -0
- package/coverage/framework/services/http/middleware/Pagination.js.html +253 -0
- package/coverage/framework/services/http/middleware/PrepareAppInfo.js.html +139 -0
- package/coverage/framework/services/http/middleware/RateLimiter.js.html +472 -0
- package/coverage/framework/services/http/middleware/RequestLogger.js.html +151 -0
- package/coverage/framework/services/http/middleware/RequestParser.js.html +199 -0
- package/coverage/framework/services/http/middleware/Role.js.html +172 -0
- package/coverage/framework/services/http/middleware/index.html +251 -0
- package/coverage/framework/services/http/middleware/test/CheckFlag.js.html +139 -0
- package/coverage/framework/services/http/middleware/test/index.html +116 -0
- package/coverage/framework/services/messaging/email/index.html +116 -0
- package/coverage/framework/services/messaging/email/index.js.html +739 -0
- package/coverage/framework/services/messaging/index.html +116 -0
- package/coverage/framework/services/messaging/index.js.html +100 -0
- package/coverage/framework/services/validate/ValidateService.js.html +556 -0
- package/coverage/framework/services/validate/drivers/AbstractValidator.js.html +196 -0
- package/coverage/framework/services/validate/drivers/CustomValidator.js.html +241 -0
- package/coverage/framework/services/validate/drivers/YupValidator.js.html +394 -0
- package/coverage/framework/services/validate/drivers/index.html +146 -0
- package/coverage/framework/services/validate/index.html +116 -0
- package/coverage/index.html +356 -0
- package/coverage/prettify.css +1 -0
- package/coverage/prettify.js +2 -0
- package/coverage/sort-arrow-sprite.png +0 -0
- package/coverage/sorter.js +196 -0
- package/helpers/files.js +75 -0
- package/helpers/logger.js +19 -0
- package/models/Migration.test.js +19 -0
- package/models/User.test.js +3 -3
- package/modules/AbstractController.js +1 -3
- package/modules/Base.js +6 -56
- package/modules/BaseCli.js +0 -3
- package/package.json +3 -2
- package/server.d.ts +14 -0
- package/server.js +165 -86
- package/services/cache/Cache.js +10 -5
- package/services/cache/Cache.test.js +81 -0
- package/services/http/middleware/Auth.test.js +57 -0
- package/services/http/middleware/I18n.test.js +16 -4
- package/services/http/middleware/PrepareAppInfo.test.js +1 -1
- package/services/http/middleware/RateLimiter.test.js +7 -7
- package/services/http/middleware/Role.test.js +93 -0
- package/services/validate/ValidateService.test.js +3 -3
- package/tests/setup.js +3 -0
- package/tests/setupVitest.js +3 -4
package/server.js
CHANGED
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
/* eslint-disable no-console */
|
|
2
2
|
const EventEmitter = require('node:events');
|
|
3
|
+
const { hrtime } = require('node:process');
|
|
3
4
|
|
|
4
5
|
require('dotenv').config();
|
|
5
6
|
const merge = require('deepmerge');
|
|
6
7
|
const winston = require('winston');
|
|
8
|
+
const { getFilesPathWithInheritance } = require('./helpers/files');
|
|
9
|
+
const { consoleLogger } = require('./helpers/logger');
|
|
10
|
+
|
|
11
|
+
const Cache = require('./services/cache/Cache');
|
|
7
12
|
|
|
8
13
|
/**
|
|
9
14
|
* Main framework class.
|
|
@@ -11,6 +16,8 @@ const winston = require('winston');
|
|
|
11
16
|
class Server {
|
|
12
17
|
#realLogger = null;
|
|
13
18
|
|
|
19
|
+
#isInited = false;
|
|
20
|
+
|
|
14
21
|
/**
|
|
15
22
|
* Construct new server
|
|
16
23
|
* @param {Object} config main config object
|
|
@@ -46,6 +53,7 @@ class Server {
|
|
|
46
53
|
this.cache = {
|
|
47
54
|
configs: new Map(),
|
|
48
55
|
models: new Map(),
|
|
56
|
+
modelConstructors: new Map(),
|
|
49
57
|
};
|
|
50
58
|
|
|
51
59
|
this.cli = false;
|
|
@@ -57,13 +65,11 @@ class Server {
|
|
|
57
65
|
* @returns {Promise}
|
|
58
66
|
*/
|
|
59
67
|
async startServer(callbackBefore404 = async () => Promise.resolve()) {
|
|
60
|
-
// const HttpServer = require('./services/http/HttpServer');
|
|
61
|
-
// const ControllerManager = require('./controllers/index');
|
|
62
|
-
// TODO wait until https://github.com/nodejs/node/issues/35889
|
|
63
68
|
const [{ default: HttpServer }, { default: ControllerManager }] =
|
|
64
69
|
await Promise.all([
|
|
65
70
|
import('./services/http/HttpServer.js'), // Speed optimisation
|
|
66
71
|
import('./controllers/index.js'), // Speed optimisation
|
|
72
|
+
this.init(),
|
|
67
73
|
]);
|
|
68
74
|
|
|
69
75
|
this.addErrorHandling();
|
|
@@ -78,20 +84,150 @@ class Server {
|
|
|
78
84
|
this.app.httpServer.add404Page();
|
|
79
85
|
}
|
|
80
86
|
|
|
87
|
+
/**
|
|
88
|
+
* Do an initialization (config reading, etc)
|
|
89
|
+
* @returns {Promise}
|
|
90
|
+
*/
|
|
91
|
+
async init({ isSkipModelInit = false } = {}) {
|
|
92
|
+
if (this.#isInited) {
|
|
93
|
+
return true;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
console.time('Server init. Done');
|
|
97
|
+
console.time('Loading config and model files. Time');
|
|
98
|
+
await Promise.all([this.#initConfigFiles(), this.#loadModelFiles()]);
|
|
99
|
+
console.timeEnd('Loading config and model files. Time');
|
|
100
|
+
|
|
101
|
+
if (!isSkipModelInit) {
|
|
102
|
+
await this.initAllModels();
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
this.#isInited = true;
|
|
106
|
+
|
|
107
|
+
console.timeEnd('Server init. Done');
|
|
108
|
+
|
|
109
|
+
return true;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Load model and init them
|
|
114
|
+
* @returns {Promise}
|
|
115
|
+
*/
|
|
116
|
+
async initAllModels() {
|
|
117
|
+
console.time('Initing models. Time');
|
|
118
|
+
|
|
119
|
+
if (this.app.getConfig('mongo').connectionString) {
|
|
120
|
+
for (const [modelName, ModelConstructor] of this.cache
|
|
121
|
+
.modelConstructors) {
|
|
122
|
+
try {
|
|
123
|
+
const model = new ModelConstructor(this.app);
|
|
124
|
+
this.cache.models.set(modelName, model.mongooseModel);
|
|
125
|
+
} catch (e) {
|
|
126
|
+
this.app.logger.error(
|
|
127
|
+
`Problem with model ${modelName}, ${e.message}`,
|
|
128
|
+
);
|
|
129
|
+
this.app.logger.error(e);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
} else {
|
|
133
|
+
this.app.logger.info(
|
|
134
|
+
'Skipping inited models as we have no mongo connection string',
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
console.timeEnd('Initing models. Time');
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
async #initConfigFiles() {
|
|
142
|
+
const files = await getFilesPathWithInheritance({
|
|
143
|
+
internalFolder: `${__dirname}/config`,
|
|
144
|
+
externalFolder: this.app.foldersConfig.config,
|
|
145
|
+
loggerFileType: 'CONFIG',
|
|
146
|
+
logger: (m) => consoleLogger('info', m),
|
|
147
|
+
filter: {
|
|
148
|
+
startWithCapital: false,
|
|
149
|
+
},
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
const configFiles = {};
|
|
153
|
+
|
|
154
|
+
for (const file of files) {
|
|
155
|
+
const config = file.file.split('.');
|
|
156
|
+
if (!configFiles[config[0]]) {
|
|
157
|
+
configFiles[config[0]] = {};
|
|
158
|
+
}
|
|
159
|
+
if (config.length === 2) {
|
|
160
|
+
configFiles[config[0]].default = file.path;
|
|
161
|
+
} else {
|
|
162
|
+
configFiles[config[0]][config[1]] = file.path;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
const loadConfig = async (configName, values) => {
|
|
167
|
+
const promises = [import(values.default)];
|
|
168
|
+
if (process.env.NODE_ENV && values[process.env.NODE_ENV]) {
|
|
169
|
+
promises.push(import(values[process.env.NODE_ENV]));
|
|
170
|
+
}
|
|
171
|
+
const result = await Promise.all(promises);
|
|
172
|
+
return {
|
|
173
|
+
name: configName,
|
|
174
|
+
finalValue: merge(result[0].default, result[1]?.default || {}, {
|
|
175
|
+
arrayMerge: (destinationArray, sourceArray) => sourceArray,
|
|
176
|
+
}),
|
|
177
|
+
};
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
const loadingPromises = [];
|
|
181
|
+
|
|
182
|
+
for (const [configFile, value] of Object.entries(configFiles)) {
|
|
183
|
+
loadingPromises.push(loadConfig(configFile, value));
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
const configs = await Promise.all(loadingPromises);
|
|
187
|
+
|
|
188
|
+
for (const config of configs) {
|
|
189
|
+
this.cache.configs.set(config.name, config.finalValue);
|
|
190
|
+
}
|
|
191
|
+
return true;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
async #loadModelFiles() {
|
|
195
|
+
const files = await getFilesPathWithInheritance({
|
|
196
|
+
internalFolder: `${__dirname}/models`,
|
|
197
|
+
externalFolder: this.app.foldersConfig.models,
|
|
198
|
+
loggerFileType: 'MODEL',
|
|
199
|
+
logger: (m) => consoleLogger('info', m),
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
const promises = [];
|
|
203
|
+
for (const file of files) {
|
|
204
|
+
const t = hrtime.bigint();
|
|
205
|
+
promises.push(
|
|
206
|
+
import(file.path).then((f) => ({
|
|
207
|
+
name: file.file.split('.')[0],
|
|
208
|
+
file: f,
|
|
209
|
+
took: hrtime.bigint() - t,
|
|
210
|
+
})),
|
|
211
|
+
);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
const loadedModels = await Promise.all(promises);
|
|
215
|
+
|
|
216
|
+
for (const model of loadedModels) {
|
|
217
|
+
this.cache.modelConstructors.set(model.name, model.file.default);
|
|
218
|
+
}
|
|
219
|
+
return true;
|
|
220
|
+
}
|
|
221
|
+
|
|
81
222
|
/**
|
|
82
223
|
* Add error logging on promise reject
|
|
83
224
|
*/
|
|
84
|
-
// eslint-disable-next-line class-methods-use-this
|
|
85
225
|
addErrorHandling() {
|
|
86
|
-
process.on('uncaughtException',
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
' reason: ',
|
|
92
|
-
reason,
|
|
93
|
-
);
|
|
94
|
-
console.trace('unhandledRejection');
|
|
226
|
+
process.on('uncaughtException', (e) =>
|
|
227
|
+
this.app.logger.error('uncaughtException', e),
|
|
228
|
+
);
|
|
229
|
+
process.on('unhandledRejection', (e) => {
|
|
230
|
+
this.app.logger.error('unhandledRejection', e);
|
|
95
231
|
});
|
|
96
232
|
}
|
|
97
233
|
|
|
@@ -106,24 +242,14 @@ class Server {
|
|
|
106
242
|
* @returns {Object} config object. Structure depends of config file
|
|
107
243
|
*/
|
|
108
244
|
getConfig(configName) {
|
|
109
|
-
// const configName = name.charAt(0).toUpperCase() + name.slice(1);
|
|
110
245
|
if (!this.cache.configs.has(configName)) {
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
envConfig =
|
|
114
|
-
this.getFileWithExtendingInhirence(
|
|
115
|
-
'config',
|
|
116
|
-
`${configName}.${process.env.NODE_ENV}.js`,
|
|
117
|
-
) || envConfig;
|
|
246
|
+
if (!this.#isInited) {
|
|
247
|
+
throw new Error('You should call Server.init() before using getConfig');
|
|
118
248
|
}
|
|
119
|
-
this.
|
|
120
|
-
configName
|
|
121
|
-
merge(
|
|
122
|
-
this.getFileWithExtendingInhirence('config', configName),
|
|
123
|
-
envConfig,
|
|
124
|
-
{ arrayMerge: (destinationArray, sourceArray) => sourceArray },
|
|
125
|
-
),
|
|
249
|
+
this.app.logger.warn(
|
|
250
|
+
`You asked for config ${configName} that not exists. Please check you codebase `,
|
|
126
251
|
);
|
|
252
|
+
return {};
|
|
127
253
|
}
|
|
128
254
|
return this.cache.configs.get(configName);
|
|
129
255
|
}
|
|
@@ -225,24 +351,21 @@ class Server {
|
|
|
225
351
|
*/
|
|
226
352
|
getModel(modelName) {
|
|
227
353
|
if (modelName.endsWith('s')) {
|
|
228
|
-
|
|
354
|
+
this.app.logger.warn(
|
|
229
355
|
`Probably your model name '${modelName}' in plural from. Try to avoid plural form`,
|
|
230
356
|
);
|
|
231
357
|
}
|
|
358
|
+
if (!this.#isInited) {
|
|
359
|
+
this.app.logger.error(
|
|
360
|
+
new Error('You should call Server.init() before using getModel'),
|
|
361
|
+
);
|
|
362
|
+
return false;
|
|
363
|
+
}
|
|
232
364
|
if (!this.cache.models.has(modelName)) {
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
}
|
|
238
|
-
try {
|
|
239
|
-
const model = new Model(this.app);
|
|
240
|
-
|
|
241
|
-
this.cache.models.set(modelName, model.mongooseModel);
|
|
242
|
-
} catch (e) {
|
|
243
|
-
console.error(`Problem with model ${modelName}, ${e.message}`);
|
|
244
|
-
console.error(e);
|
|
245
|
-
}
|
|
365
|
+
this.app.logger.warn(
|
|
366
|
+
`You asked for model ${modelName} that not exists. Please check you codebase `,
|
|
367
|
+
);
|
|
368
|
+
return {};
|
|
246
369
|
}
|
|
247
370
|
return this.cache.models.get(modelName);
|
|
248
371
|
}
|
|
@@ -254,9 +377,7 @@ class Server {
|
|
|
254
377
|
*/
|
|
255
378
|
async runCliCommand(commandName, args) {
|
|
256
379
|
if (!this.cli) {
|
|
257
|
-
// TODO wait until https://github.com/nodejs/node/issues/35889
|
|
258
380
|
const { default: BaseCli } = await import('./modules/BaseCli.js'); // Speed optimisation
|
|
259
|
-
// const BaseCli = require('./modules/BaseCli');
|
|
260
381
|
this.cli = new BaseCli(this);
|
|
261
382
|
}
|
|
262
383
|
return this.cli.run(commandName, args);
|
|
@@ -268,52 +389,10 @@ class Server {
|
|
|
268
389
|
*/
|
|
269
390
|
getCache() {
|
|
270
391
|
if (!this.cacheService) {
|
|
271
|
-
// eslint-disable-next-line global-require
|
|
272
|
-
const Cache = require('./services/cache/Cache'); // Speed optimisation
|
|
273
392
|
this.cacheService = new Cache(this.app);
|
|
274
393
|
}
|
|
275
394
|
return this.cacheService;
|
|
276
395
|
}
|
|
277
|
-
|
|
278
|
-
/**
|
|
279
|
-
* Get file using Inhirence (ability to overrite models, configs, etc)
|
|
280
|
-
* @param {('models'|'config')} fileType type of file to load
|
|
281
|
-
* @param {string} fileName name of file to load
|
|
282
|
-
*/
|
|
283
|
-
getFileWithExtendingInhirence(fileType, fileName) {
|
|
284
|
-
let file;
|
|
285
|
-
try {
|
|
286
|
-
// eslint-disable-next-line global-require, import/no-dynamic-require
|
|
287
|
-
file = require(`${this.config.folders[fileType]}/${fileName}`);
|
|
288
|
-
} catch (e) {
|
|
289
|
-
try {
|
|
290
|
-
// eslint-disable-next-line global-require, import/no-dynamic-require
|
|
291
|
-
file = require(`./${fileType}/${fileName}`);
|
|
292
|
-
} catch (e2) {
|
|
293
|
-
const levels = [
|
|
294
|
-
'error',
|
|
295
|
-
'warn',
|
|
296
|
-
'info',
|
|
297
|
-
'http',
|
|
298
|
-
'verbose',
|
|
299
|
-
'debug',
|
|
300
|
-
'silly',
|
|
301
|
-
];
|
|
302
|
-
|
|
303
|
-
if (
|
|
304
|
-
!process.env.LOGGER_CONSOLE_LEVEL ||
|
|
305
|
-
levels.indexOf(process.env.LOGGER_CONSOLE_LEVEL) > 0 // as a warn level
|
|
306
|
-
) {
|
|
307
|
-
console.warn(
|
|
308
|
-
`Config not found '${fileName}'. This can be a normal (in case this an environment config)`,
|
|
309
|
-
);
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
file = false;
|
|
313
|
-
}
|
|
314
|
-
}
|
|
315
|
-
return file;
|
|
316
|
-
}
|
|
317
396
|
}
|
|
318
397
|
|
|
319
398
|
module.exports = Server;
|
package/services/cache/Cache.js
CHANGED
|
@@ -1,13 +1,17 @@
|
|
|
1
|
-
const redis = require('redis');
|
|
2
1
|
const Base = require('../../modules/Base');
|
|
3
2
|
|
|
4
3
|
class Cache extends Base {
|
|
5
4
|
constructor(app) {
|
|
5
|
+
super(app);
|
|
6
|
+
this.whenReady = this.#init();
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
async #init() {
|
|
6
10
|
// todo for now only redis. refactor for drives support in future
|
|
7
11
|
// at least memory and redis drivers should be presented
|
|
8
12
|
// memory drives should works on master process level
|
|
9
13
|
// we should support multiple cashe same time
|
|
10
|
-
|
|
14
|
+
const redis = await import('redis');
|
|
11
15
|
const conf = this.app.getConfig('redis');
|
|
12
16
|
this.redisClient = redis.createClient({
|
|
13
17
|
url: conf.url,
|
|
@@ -33,6 +37,7 @@ class Cache extends Base {
|
|
|
33
37
|
}
|
|
34
38
|
|
|
35
39
|
async getSetValue(keyValue, onNotFound, storeTime = 60 * 5) {
|
|
40
|
+
await this.whenReady;
|
|
36
41
|
if (!this.redisClient.isOpen) {
|
|
37
42
|
await this.redisClient.connect();
|
|
38
43
|
}
|
|
@@ -58,9 +63,7 @@ class Cache extends Base {
|
|
|
58
63
|
try {
|
|
59
64
|
result = await onNotFound();
|
|
60
65
|
} catch (e) {
|
|
61
|
-
this.logger.error(
|
|
62
|
-
`Cache onNotFound for key '${key}' error: ${e.message}`,
|
|
63
|
-
);
|
|
66
|
+
this.logger.error(`Cache onNotFound for key '${key}' error: ${e}`);
|
|
64
67
|
this.promiseMapping.delete(key);
|
|
65
68
|
reject(e);
|
|
66
69
|
return Promise.reject(e);
|
|
@@ -100,6 +103,8 @@ class Cache extends Base {
|
|
|
100
103
|
}
|
|
101
104
|
|
|
102
105
|
async removeKey(keyValue) {
|
|
106
|
+
await this.whenReady;
|
|
107
|
+
|
|
103
108
|
if (!this.redisClient.isOpen) {
|
|
104
109
|
await this.redisClient.connect();
|
|
105
110
|
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { setTimeout } from 'node:timers/promises';
|
|
3
|
+
|
|
4
|
+
describe('cache', () => {
|
|
5
|
+
const time = Date.now();
|
|
6
|
+
|
|
7
|
+
it('can get set values', async () => {
|
|
8
|
+
expect.assertions(2);
|
|
9
|
+
|
|
10
|
+
const { cache } = global.server.app;
|
|
11
|
+
|
|
12
|
+
const res = await cache.getSetValue('TEST_TIME', () => time);
|
|
13
|
+
expect(res).toStrictEqual(time);
|
|
14
|
+
|
|
15
|
+
const res2 = await cache.getSetValue('TEST_TIME', () => '123');
|
|
16
|
+
expect(res2).toStrictEqual(time);
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it('can delete values', async () => {
|
|
20
|
+
expect.assertions(1);
|
|
21
|
+
const { cache } = global.server.app;
|
|
22
|
+
|
|
23
|
+
await cache.removeKey('TEST_TIME');
|
|
24
|
+
|
|
25
|
+
const res2 = await cache.getSetValue('TEST_TIME', () => '123');
|
|
26
|
+
expect(res2).toBe('123');
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it('can works with big int', async () => {
|
|
30
|
+
expect.assertions(2);
|
|
31
|
+
const { cache } = global.server.app;
|
|
32
|
+
|
|
33
|
+
const res = await cache.getSetValue('BIN_INT', () => 1n);
|
|
34
|
+
expect(res).toBe(1n);
|
|
35
|
+
|
|
36
|
+
const res2 = await cache.getSetValue('BIN_INT', () => '1111');
|
|
37
|
+
expect(res2).toBe(1n);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it('can execute only one request per time', async () => {
|
|
41
|
+
expect.assertions(3);
|
|
42
|
+
const { cache } = global.server.app;
|
|
43
|
+
let counter = 0;
|
|
44
|
+
|
|
45
|
+
const f = async () => {
|
|
46
|
+
await setTimeout(10);
|
|
47
|
+
counter += 1;
|
|
48
|
+
return 1;
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
const [res, res1] = await Promise.all([
|
|
52
|
+
cache.getSetValue('T', f),
|
|
53
|
+
cache.getSetValue('T', f),
|
|
54
|
+
]);
|
|
55
|
+
|
|
56
|
+
expect(counter).toBe(1);
|
|
57
|
+
|
|
58
|
+
expect(res).toBe(1);
|
|
59
|
+
expect(res1).toBe(1);
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it('can handle problems on onNotFound', async () => {
|
|
63
|
+
expect.assertions(1);
|
|
64
|
+
const getAsyncThrow = async () => {
|
|
65
|
+
throw new Error('err');
|
|
66
|
+
};
|
|
67
|
+
let err;
|
|
68
|
+
|
|
69
|
+
const { cache } = global.server.app;
|
|
70
|
+
|
|
71
|
+
try {
|
|
72
|
+
await Promise.all([
|
|
73
|
+
cache.getSetValue('THROW', getAsyncThrow),
|
|
74
|
+
cache.getSetValue('THROW', getAsyncThrow),
|
|
75
|
+
]);
|
|
76
|
+
} catch (e) {
|
|
77
|
+
err = e;
|
|
78
|
+
}
|
|
79
|
+
expect(err.message).toBe('err');
|
|
80
|
+
});
|
|
81
|
+
});
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { beforeAll, describe, it, expect } from 'vitest';
|
|
2
|
+
import Auth from './Auth';
|
|
3
|
+
|
|
4
|
+
describe('atuh middleware methods', () => {
|
|
5
|
+
let middleware;
|
|
6
|
+
beforeAll(() => {
|
|
7
|
+
middleware = new Auth(global.server.app);
|
|
8
|
+
});
|
|
9
|
+
it('have description fields', async () => {
|
|
10
|
+
expect.assertions(1);
|
|
11
|
+
expect(middleware.constructor.description).toBeDefined();
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
it('middleware pass when user presented', async () => {
|
|
15
|
+
expect.assertions(1);
|
|
16
|
+
let isCalled = false;
|
|
17
|
+
const nextFunction = () => {
|
|
18
|
+
isCalled = true;
|
|
19
|
+
};
|
|
20
|
+
const req = {
|
|
21
|
+
appInfo: {
|
|
22
|
+
user: true,
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
await middleware.middleware(req, {}, nextFunction);
|
|
26
|
+
expect(isCalled).toBeTruthy();
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it('middleware NOT pass when user NOT presented', async () => {
|
|
30
|
+
expect.assertions(3);
|
|
31
|
+
let isCalled = false;
|
|
32
|
+
let status;
|
|
33
|
+
let isSend;
|
|
34
|
+
const nextFunction = () => {
|
|
35
|
+
isCalled = true;
|
|
36
|
+
};
|
|
37
|
+
const req = {
|
|
38
|
+
appInfo: {}, // no user
|
|
39
|
+
};
|
|
40
|
+
await middleware.middleware(
|
|
41
|
+
req,
|
|
42
|
+
{
|
|
43
|
+
status(statusCode) {
|
|
44
|
+
status = statusCode;
|
|
45
|
+
return this;
|
|
46
|
+
},
|
|
47
|
+
json() {
|
|
48
|
+
isSend = true;
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
nextFunction,
|
|
52
|
+
);
|
|
53
|
+
expect(isCalled).toBeFalsy();
|
|
54
|
+
expect(status).toBe(401);
|
|
55
|
+
expect(isSend).toBeTruthy();
|
|
56
|
+
});
|
|
57
|
+
});
|
|
@@ -12,7 +12,7 @@ describe('i18n middleware methods', () => {
|
|
|
12
12
|
});
|
|
13
13
|
|
|
14
14
|
it('detectors should works correctly', async () => {
|
|
15
|
-
expect.assertions(
|
|
15
|
+
expect.assertions(6);
|
|
16
16
|
const request = {
|
|
17
17
|
get: () => 'en',
|
|
18
18
|
query: {
|
|
@@ -42,10 +42,13 @@ describe('i18n middleware methods', () => {
|
|
|
42
42
|
};
|
|
43
43
|
lang = await middleware.detectLang(request);
|
|
44
44
|
expect(lang).toBe('en');
|
|
45
|
+
|
|
46
|
+
lang = await middleware.detectLang(request, false);
|
|
47
|
+
expect(lang).toBe('en-GB');
|
|
45
48
|
});
|
|
46
49
|
|
|
47
50
|
it('middleware that works', async () => {
|
|
48
|
-
expect.assertions(
|
|
51
|
+
expect.assertions(6);
|
|
49
52
|
let isCalled = false;
|
|
50
53
|
const nextFunction = () => {
|
|
51
54
|
isCalled = true;
|
|
@@ -55,10 +58,19 @@ describe('i18n middleware methods', () => {
|
|
|
55
58
|
appInfo: {},
|
|
56
59
|
};
|
|
57
60
|
await middleware.middleware(req, {}, nextFunction);
|
|
58
|
-
expect(isCalled).
|
|
61
|
+
expect(isCalled).toBeTruthy();
|
|
59
62
|
expect(req.appInfo.i18n).toBeDefined();
|
|
63
|
+
expect(req.appInfo.i18n.language).toBe('en');
|
|
60
64
|
expect(req.appInfo.i18n.t('aaaaa')).toBe('aaaaa');
|
|
61
65
|
expect(req.i18n.t('aaaaa')).toBe('aaaaa'); // proxy test
|
|
66
|
+
|
|
67
|
+
const req2 = {
|
|
68
|
+
get: () => 'fakeLang',
|
|
69
|
+
appInfo: {},
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
await middleware.middleware(req2, {}, nextFunction);
|
|
73
|
+
expect(req2.appInfo.i18n.language).toBe('en');
|
|
62
74
|
});
|
|
63
75
|
|
|
64
76
|
it('middleware disabled', async () => {
|
|
@@ -75,7 +87,7 @@ describe('i18n middleware methods', () => {
|
|
|
75
87
|
appInfo: {},
|
|
76
88
|
};
|
|
77
89
|
await middleware.middleware(req, {}, nextFunction);
|
|
78
|
-
expect(isCalled).
|
|
90
|
+
expect(isCalled).toBeTruthy();
|
|
79
91
|
expect(req.appInfo.i18n).toBeDefined();
|
|
80
92
|
expect(req.appInfo.i18n.t('aaaaa')).toBe('aaaaa');
|
|
81
93
|
expect(req.i18n.t('aaaaa')).toBe('aaaaa'); // proxy test
|
|
@@ -17,7 +17,7 @@ describe('prepareAppInfo methods', () => {
|
|
|
17
17
|
};
|
|
18
18
|
const req = {};
|
|
19
19
|
await middleware.middleware(req, {}, nextFunction);
|
|
20
|
-
expect(isCalled).
|
|
20
|
+
expect(isCalled).toBeTruthy();
|
|
21
21
|
expect(req.appInfo).toBeDefined();
|
|
22
22
|
req.appInfo.test = 5;
|
|
23
23
|
await middleware.middleware(req, {}, nextFunction);
|
|
@@ -113,7 +113,7 @@ describe('rate limiter methods', () => {
|
|
|
113
113
|
() => {},
|
|
114
114
|
);
|
|
115
115
|
expect(status).toBe(500);
|
|
116
|
-
expect(isSend).
|
|
116
|
+
expect(isSend).toBeTruthy();
|
|
117
117
|
});
|
|
118
118
|
|
|
119
119
|
const makeOneRequest = async ({ rateLimiter, driver, request }) => {
|
|
@@ -154,7 +154,7 @@ describe('rate limiter methods', () => {
|
|
|
154
154
|
rateLimiter: mongoRateLimiter,
|
|
155
155
|
request: { ip: '10.10.0.1' },
|
|
156
156
|
});
|
|
157
|
-
expect(isNextCalled).
|
|
157
|
+
expect(isNextCalled).toBeTruthy();
|
|
158
158
|
});
|
|
159
159
|
|
|
160
160
|
it('middleware should works with a memory drivers', async () => {
|
|
@@ -163,7 +163,7 @@ describe('rate limiter methods', () => {
|
|
|
163
163
|
driver: 'memory',
|
|
164
164
|
request: { ip: '10.10.0.1' },
|
|
165
165
|
});
|
|
166
|
-
expect(isNextCalled).
|
|
166
|
+
expect(isNextCalled).toBeTruthy();
|
|
167
167
|
});
|
|
168
168
|
|
|
169
169
|
it('middleware should works with a redis drivers', async () => {
|
|
@@ -172,7 +172,7 @@ describe('rate limiter methods', () => {
|
|
|
172
172
|
driver: 'redis',
|
|
173
173
|
request: { ip: '10.10.0.1' },
|
|
174
174
|
});
|
|
175
|
-
expect(isNextCalled).
|
|
175
|
+
expect(isNextCalled).toBeTruthy();
|
|
176
176
|
});
|
|
177
177
|
|
|
178
178
|
it('middleware should rate limits for us. mongo driver', async () => {
|
|
@@ -188,7 +188,7 @@ describe('rate limiter methods', () => {
|
|
|
188
188
|
const isSend = data.find((obj) => obj.isSend);
|
|
189
189
|
|
|
190
190
|
expect(status.status).toBe(429);
|
|
191
|
-
expect(isSend.isSend).
|
|
191
|
+
expect(isSend.isSend).toBeTruthy();
|
|
192
192
|
});
|
|
193
193
|
|
|
194
194
|
it('middleware should rate limits for us. memory driver', async () => {
|
|
@@ -208,7 +208,7 @@ describe('rate limiter methods', () => {
|
|
|
208
208
|
const isSend = data.find((obj) => obj.isSend);
|
|
209
209
|
|
|
210
210
|
expect(status.status).toBe(429);
|
|
211
|
-
expect(isSend.isSend).
|
|
211
|
+
expect(isSend.isSend).toBeTruthy();
|
|
212
212
|
});
|
|
213
213
|
|
|
214
214
|
it('middleware should rate limits for us. redis driver', async () => {
|
|
@@ -228,6 +228,6 @@ describe('rate limiter methods', () => {
|
|
|
228
228
|
const isSend = data.find((obj) => obj.isSend);
|
|
229
229
|
|
|
230
230
|
expect(status.status).toBe(429);
|
|
231
|
-
expect(isSend.isSend).
|
|
231
|
+
expect(isSend.isSend).toBeTruthy();
|
|
232
232
|
});
|
|
233
233
|
});
|