@seidor-cloud-produtos/orbit-backend-lib 2.0.109 → 2.0.111
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/dist/clean-arch/application/cache/cache.spec.d.ts +1 -0
- package/dist/clean-arch/application/cache/cache.spec.js +178 -0
- package/dist/clean-arch/application/consistency-event-dispatcher/consistency-event-dispatcher.d.ts +1 -1
- package/dist/clean-arch/application/logger/logger.spec.d.ts +1 -0
- package/dist/clean-arch/application/logger/logger.spec.js +204 -0
- package/dist/clean-arch/domain/entities/entity.spec.d.ts +1 -0
- package/dist/clean-arch/domain/entities/entity.spec.js +130 -0
- package/dist/clean-arch/domain/events/consistency-event/consistency-event.spec.d.ts +1 -0
- package/dist/clean-arch/domain/events/consistency-event/consistency-event.spec.js +91 -0
- package/dist/clean-arch/domain/events/consistency-event/types/{partner-service/portal-admin → portal-admin}/user/user-temporary-password-generated.d.ts +3 -3
- package/dist/clean-arch/domain/value-objects/password.spec.d.ts +1 -0
- package/dist/clean-arch/domain/value-objects/password.spec.js +90 -0
- package/dist/clean-arch/infra/adapters/http-adapters.spec.d.ts +1 -0
- package/dist/clean-arch/infra/adapters/http-adapters.spec.js +318 -0
- package/dist/clean-arch/infra/authorizations/authorizer.spec.js +43 -0
- package/dist/clean-arch/infra/cache/cache-clients.spec.d.ts +1 -0
- package/dist/clean-arch/infra/cache/cache-clients.spec.js +161 -0
- package/dist/clean-arch/infra/cache/clients/node-cache.js +3 -2
- package/dist/clean-arch/infra/http/controller.spec.js +170 -51
- package/dist/clean-arch/infra/http/helpers.spec.d.ts +1 -0
- package/dist/clean-arch/infra/http/helpers.spec.js +136 -0
- package/dist/clean-arch/infra/http/net.spec.d.ts +1 -0
- package/dist/clean-arch/infra/http/net.spec.js +46 -0
- package/dist/clean-arch/infra/logger/logger-orbit.d.ts +2 -0
- package/dist/clean-arch/infra/logger/logger-orbit.spec.d.ts +1 -0
- package/dist/clean-arch/infra/logger/logger-orbit.spec.js +122 -0
- package/dist/clean-arch/infra/orbit-http-client/orbit-axios-client/orbit-axios-client.spec.d.ts +1 -0
- package/dist/clean-arch/infra/orbit-http-client/orbit-axios-client/orbit-axios-client.spec.js +143 -0
- package/dist/clean-arch/infra/orbit-notification-client/discord-client.spec.d.ts +1 -0
- package/dist/clean-arch/infra/orbit-notification-client/discord-client.spec.js +58 -0
- package/dist/clean-arch/infra/queue/queue-utils.spec.d.ts +1 -0
- package/dist/clean-arch/infra/queue/queue-utils.spec.js +170 -0
- package/dist/clean-arch/infra/queue/rabbitmq/amqp-lib.js +4 -4
- package/dist/clean-arch/infra/queue/rabbitmq/amqp-lib.spec.js +466 -89
- package/dist/clean-arch/infra/queue/rabbitmq/types.d.ts +1 -1
- package/dist/clean-arch/infra/scaledjob/amqp/runner.d.ts +0 -3
- package/dist/clean-arch/infra/scaledjob/amqp/runner.js +5 -6
- package/dist/clean-arch/infra/scaledjob/amqp/runner.spec.js +74 -84
- package/dist/clean-arch/infra/scaledjob/sqs/runner.spec.d.ts +1 -0
- package/dist/clean-arch/infra/scaledjob/sqs/runner.spec.js +150 -0
- package/dist/clean-arch/infra/tracing/start-tracing.d.ts +10 -0
- package/dist/clean-arch/infra/tracing/start-tracing.js +78 -0
- package/dist/clean-arch/infra/validations/zod/validation-zod.spec.js +23 -0
- package/dist/clean-arch/shared/pagination/get-take-and-skip.spec.d.ts +1 -0
- package/dist/clean-arch/shared/pagination/get-take-and-skip.spec.js +16 -0
- package/dist/coverage/block-navigation.d.ts +1 -0
- package/dist/coverage/block-navigation.js +72 -0
- package/dist/coverage/prettify.d.ts +0 -0
- package/dist/coverage/prettify.js +1009 -0
- package/dist/coverage/sorter.d.ts +1 -0
- package/dist/coverage/sorter.js +178 -0
- package/dist/frameworks/express/api-gateway/mapping-model.spec.js +58 -0
- package/dist/frameworks/express/authorizations/authorization-express.spec.js +9 -0
- package/dist/frameworks/express/middleware-express.spec.d.ts +1 -0
- package/dist/frameworks/express/middleware-express.spec.js +51 -0
- package/dist/frameworks/nest/nest.spec.d.ts +1 -0
- package/dist/frameworks/nest/nest.spec.js +122 -0
- package/dist/infra/http/api-gateway/mapping-model.spec.js +42 -0
- package/package.json +5 -1
- /package/dist/clean-arch/domain/events/consistency-event/types/{partner-service/portal-admin → portal-admin}/user/user-entity-event.d.ts +0 -0
- /package/dist/clean-arch/domain/events/consistency-event/types/{partner-service/portal-admin → portal-admin}/user/user-entity-event.js +0 -0
- /package/dist/clean-arch/domain/events/consistency-event/types/{partner-service/portal-admin → portal-admin}/user/user-temporary-password-generated.js +0 -0
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const tslib_1 = require("tslib");
|
|
4
|
+
const create_password_factory_1 = tslib_1.__importDefault(require("../factories/create-password-factory"));
|
|
5
|
+
const random_password_temporary_factory_1 = tslib_1.__importDefault(require("../factories/random-password-temporary-factory"));
|
|
6
|
+
const invalid_password_algorithm_error_1 = tslib_1.__importDefault(require("../errors/invalid-password-algorithm-error"));
|
|
7
|
+
const invalid_password_length_error_1 = tslib_1.__importDefault(require("../errors/invalid-password-length-error"));
|
|
8
|
+
const password_1 = tslib_1.__importStar(require("./password"));
|
|
9
|
+
const pbkdf2_password_1 = tslib_1.__importDefault(require("./pbkdf2-password"));
|
|
10
|
+
const sha1_password_1 = tslib_1.__importDefault(require("./sha1-password"));
|
|
11
|
+
class TestPassword extends password_1.default {
|
|
12
|
+
constructor() {
|
|
13
|
+
super({ algorithm: password_1.PasswordAlgorithm.SHA1, isTemporary: true });
|
|
14
|
+
}
|
|
15
|
+
static validate(value) {
|
|
16
|
+
return this.isValid(value);
|
|
17
|
+
}
|
|
18
|
+
isEqual() {
|
|
19
|
+
return false;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
describe('Password value objects and factories', () => {
|
|
23
|
+
it('should validate the minimum password length in the base class', () => {
|
|
24
|
+
expect(TestPassword.validate('1234567')).toBe(false);
|
|
25
|
+
expect(TestPassword.validate('12345678')).toBe(true);
|
|
26
|
+
});
|
|
27
|
+
it('should create and restore SHA1 passwords', () => {
|
|
28
|
+
const password = sha1_password_1.default.create('12345678');
|
|
29
|
+
const restored = sha1_password_1.default.restore(password.value, null);
|
|
30
|
+
expect(password.algorithm).toBe(password_1.PasswordAlgorithm.SHA1);
|
|
31
|
+
expect(password.isTemporary).toBe(true);
|
|
32
|
+
expect(password.notEncryptedValue).toBe('12345678');
|
|
33
|
+
expect(password.isEqual('12345678')).toBe(true);
|
|
34
|
+
expect(password.isEqual('other')).toBe(false);
|
|
35
|
+
expect(restored.isEqual('12345678')).toBe(true);
|
|
36
|
+
});
|
|
37
|
+
it('should reject invalid SHA1 passwords', () => {
|
|
38
|
+
expect(() => sha1_password_1.default.create('short')).toThrow(invalid_password_length_error_1.default);
|
|
39
|
+
});
|
|
40
|
+
it('should create and restore PBKDF2 passwords', () => {
|
|
41
|
+
const password = pbkdf2_password_1.default.create('12345678');
|
|
42
|
+
const restored = pbkdf2_password_1.default.restore(password.value, password.salt);
|
|
43
|
+
expect(password.algorithm).toBe(password_1.PasswordAlgorithm.PBKDF2);
|
|
44
|
+
expect(password.isTemporary).toBe(false);
|
|
45
|
+
expect(password.notEncryptedValue).toBe('12345678');
|
|
46
|
+
expect(password.salt).toBeTruthy();
|
|
47
|
+
expect(password.value).toHaveLength(128);
|
|
48
|
+
expect(password.isEqual('12345678')).toBe(true);
|
|
49
|
+
expect(password.isEqual('other')).toBe(false);
|
|
50
|
+
expect(restored.isEqual('12345678')).toBe(true);
|
|
51
|
+
});
|
|
52
|
+
it('should reject invalid PBKDF2 passwords', () => {
|
|
53
|
+
expect(() => pbkdf2_password_1.default.create('short')).toThrow(invalid_password_length_error_1.default);
|
|
54
|
+
});
|
|
55
|
+
it('should create valid temporary passwords', () => {
|
|
56
|
+
const generatedPassword = random_password_temporary_factory_1.default.create();
|
|
57
|
+
expect(generatedPassword).toHaveLength(8);
|
|
58
|
+
expect(random_password_temporary_factory_1.default.isValid(generatedPassword)).toBe(true);
|
|
59
|
+
expect(random_password_temporary_factory_1.default.create('fixed-value')).toBe('fixed-value');
|
|
60
|
+
expect(random_password_temporary_factory_1.default.isValid('short')).toBe(false);
|
|
61
|
+
expect(random_password_temporary_factory_1.default.isValid('abcdefgh')).toBe(false);
|
|
62
|
+
expect(random_password_temporary_factory_1.default.isValid('Abcdefgh')).toBe(false);
|
|
63
|
+
expect(random_password_temporary_factory_1.default.isValid('!bcdefgh')).toBe(false);
|
|
64
|
+
});
|
|
65
|
+
it('should create passwords using the factory', () => {
|
|
66
|
+
const randomPassword = create_password_factory_1.default.create();
|
|
67
|
+
const sha1Password = create_password_factory_1.default.create({
|
|
68
|
+
value: 'sha1-value',
|
|
69
|
+
algorithm: password_1.PasswordAlgorithm.SHA1,
|
|
70
|
+
salt: null,
|
|
71
|
+
});
|
|
72
|
+
const pbkdf2Password = create_password_factory_1.default.create({
|
|
73
|
+
value: 'pbkdf2-value',
|
|
74
|
+
algorithm: password_1.PasswordAlgorithm.PBKDF2,
|
|
75
|
+
salt: 'salt',
|
|
76
|
+
});
|
|
77
|
+
expect(randomPassword).toBeInstanceOf(sha1_password_1.default);
|
|
78
|
+
expect(sha1Password).toBeInstanceOf(sha1_password_1.default);
|
|
79
|
+
expect(pbkdf2Password).toBeInstanceOf(pbkdf2_password_1.default);
|
|
80
|
+
expect(sha1Password.value).toBe('sha1-value');
|
|
81
|
+
expect(pbkdf2Password.salt).toBe('salt');
|
|
82
|
+
});
|
|
83
|
+
it('should throw when the factory receives an invalid algorithm', () => {
|
|
84
|
+
expect(() => create_password_factory_1.default.create({
|
|
85
|
+
value: 'value',
|
|
86
|
+
algorithm: 'other',
|
|
87
|
+
salt: null,
|
|
88
|
+
})).toThrow(invalid_password_algorithm_error_1.default);
|
|
89
|
+
});
|
|
90
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const tslib_1 = require("tslib");
|
|
4
|
+
const vitest_1 = require("vitest");
|
|
5
|
+
const expressInstance = {
|
|
6
|
+
delete: vitest_1.vi.fn(),
|
|
7
|
+
disable: vitest_1.vi.fn(),
|
|
8
|
+
get: vitest_1.vi.fn(),
|
|
9
|
+
listen: vitest_1.vi.fn(),
|
|
10
|
+
patch: vitest_1.vi.fn(),
|
|
11
|
+
post: vitest_1.vi.fn(),
|
|
12
|
+
put: vitest_1.vi.fn(),
|
|
13
|
+
use: vitest_1.vi.fn(),
|
|
14
|
+
};
|
|
15
|
+
const fastifyInstance = {
|
|
16
|
+
close: vitest_1.vi.fn().mockResolvedValue(undefined),
|
|
17
|
+
delete: vitest_1.vi.fn(),
|
|
18
|
+
get: vitest_1.vi.fn(),
|
|
19
|
+
listen: vitest_1.vi.fn(),
|
|
20
|
+
patch: vitest_1.vi.fn(),
|
|
21
|
+
post: vitest_1.vi.fn(),
|
|
22
|
+
put: vitest_1.vi.fn(),
|
|
23
|
+
ready: vitest_1.vi.fn().mockResolvedValue(undefined),
|
|
24
|
+
register: vitest_1.vi.fn(),
|
|
25
|
+
};
|
|
26
|
+
vitest_1.vi.mock('cors', () => ({
|
|
27
|
+
default: vitest_1.vi.fn(() => 'cors-middleware'),
|
|
28
|
+
}));
|
|
29
|
+
vitest_1.vi.mock('compression', () => ({
|
|
30
|
+
default: vitest_1.vi.fn(() => 'compression-middleware'),
|
|
31
|
+
}));
|
|
32
|
+
vitest_1.vi.mock('express', () => {
|
|
33
|
+
const express = vitest_1.vi.fn(() => expressInstance);
|
|
34
|
+
express.json = vitest_1.vi.fn(() => 'json-middleware');
|
|
35
|
+
express.urlencoded = vitest_1.vi.fn(() => 'urlencoded-middleware');
|
|
36
|
+
return {
|
|
37
|
+
default: express,
|
|
38
|
+
};
|
|
39
|
+
});
|
|
40
|
+
vitest_1.vi.mock('@fastify/cors', () => ({
|
|
41
|
+
default: 'fastify-cors-plugin',
|
|
42
|
+
}));
|
|
43
|
+
vitest_1.vi.mock('fastify', () => ({
|
|
44
|
+
default: vitest_1.vi.fn(() => fastifyInstance),
|
|
45
|
+
}));
|
|
46
|
+
const compression_1 = tslib_1.__importDefault(require("compression"));
|
|
47
|
+
const cors_1 = tslib_1.__importDefault(require("cors"));
|
|
48
|
+
const express_1 = tslib_1.__importDefault(require("express"));
|
|
49
|
+
const fastify_1 = tslib_1.__importDefault(require("fastify"));
|
|
50
|
+
const express_adapter_1 = tslib_1.__importDefault(require("./express-adapter"));
|
|
51
|
+
const fastify_adapter_1 = tslib_1.__importDefault(require("./fastify-adapter"));
|
|
52
|
+
describe('HTTP adapters', () => {
|
|
53
|
+
afterEach(() => {
|
|
54
|
+
vitest_1.vi.clearAllMocks();
|
|
55
|
+
vitest_1.vi.restoreAllMocks();
|
|
56
|
+
});
|
|
57
|
+
it('should configure express and route requests', async () => {
|
|
58
|
+
let routeHandler;
|
|
59
|
+
const controller = {
|
|
60
|
+
handle: vitest_1.vi.fn().mockResolvedValue({
|
|
61
|
+
code: 201,
|
|
62
|
+
data: { id: '1' },
|
|
63
|
+
}),
|
|
64
|
+
throw: vitest_1.vi.fn(),
|
|
65
|
+
};
|
|
66
|
+
const response = {
|
|
67
|
+
status: vitest_1.vi.fn().mockReturnThis(),
|
|
68
|
+
json: vitest_1.vi.fn().mockReturnThis(),
|
|
69
|
+
};
|
|
70
|
+
const consoleLog = vitest_1.vi
|
|
71
|
+
.spyOn(console, 'log')
|
|
72
|
+
.mockImplementation(() => undefined);
|
|
73
|
+
expressInstance.post.mockImplementation((_url, handler) => {
|
|
74
|
+
routeHandler = handler;
|
|
75
|
+
});
|
|
76
|
+
expressInstance.listen.mockImplementation((_port, callback) => {
|
|
77
|
+
callback();
|
|
78
|
+
return {
|
|
79
|
+
close: vitest_1.vi.fn().mockResolvedValue(undefined),
|
|
80
|
+
};
|
|
81
|
+
});
|
|
82
|
+
const adapter = new express_adapter_1.default({
|
|
83
|
+
NODE_ENV: 'production',
|
|
84
|
+
});
|
|
85
|
+
expect(express_1.default).toHaveBeenCalledTimes(1);
|
|
86
|
+
expect(expressInstance.use).toHaveBeenCalledTimes(5);
|
|
87
|
+
expect(cors_1.default).toHaveBeenCalledTimes(1);
|
|
88
|
+
expect(compression_1.default).toHaveBeenCalledTimes(1);
|
|
89
|
+
expect(expressInstance.disable).toHaveBeenCalledWith('x-powered-by');
|
|
90
|
+
adapter.on('post', '/partners', controller);
|
|
91
|
+
await routeHandler({
|
|
92
|
+
body: { id: '1' },
|
|
93
|
+
params: { partnerId: '1' },
|
|
94
|
+
headers: { authorization: 'token' },
|
|
95
|
+
query: { page: '1' },
|
|
96
|
+
}, response);
|
|
97
|
+
expect(controller.handle).toHaveBeenCalledWith({
|
|
98
|
+
body: { id: '1' },
|
|
99
|
+
params: { partnerId: '1' },
|
|
100
|
+
headers: { authorization: 'token' },
|
|
101
|
+
query: { page: '1' },
|
|
102
|
+
});
|
|
103
|
+
expect(response.status).toHaveBeenCalledWith(201);
|
|
104
|
+
expect(response.json).toHaveBeenCalledWith({ id: '1' });
|
|
105
|
+
await adapter.listen(3333);
|
|
106
|
+
expect(expressInstance.listen).toHaveBeenCalledWith(3333, expect.any(Function));
|
|
107
|
+
expect(consoleLog).toHaveBeenCalledWith('🚀 Server is running on PORT 3333');
|
|
108
|
+
await adapter.close();
|
|
109
|
+
});
|
|
110
|
+
it('should map express controller errors through callback.throw', async () => {
|
|
111
|
+
let routeHandler;
|
|
112
|
+
const controller = {
|
|
113
|
+
handle: vitest_1.vi.fn().mockRejectedValue(new Error('failed')),
|
|
114
|
+
throw: vitest_1.vi.fn().mockReturnValue({
|
|
115
|
+
code: 422,
|
|
116
|
+
data: { message: 'mapped' },
|
|
117
|
+
}),
|
|
118
|
+
};
|
|
119
|
+
const response = {
|
|
120
|
+
status: vitest_1.vi.fn().mockReturnThis(),
|
|
121
|
+
json: vitest_1.vi.fn().mockReturnThis(),
|
|
122
|
+
};
|
|
123
|
+
expressInstance.get.mockImplementation((_url, handler) => {
|
|
124
|
+
routeHandler = handler;
|
|
125
|
+
});
|
|
126
|
+
const adapter = new express_adapter_1.default({
|
|
127
|
+
NODE_ENV: 'test',
|
|
128
|
+
});
|
|
129
|
+
adapter.on('get', '/partners', controller);
|
|
130
|
+
await routeHandler({
|
|
131
|
+
body: {},
|
|
132
|
+
params: {},
|
|
133
|
+
headers: {},
|
|
134
|
+
query: {},
|
|
135
|
+
}, response);
|
|
136
|
+
expect(controller.throw).toHaveBeenCalledWith(expect.any(Error));
|
|
137
|
+
expect(response.status).toHaveBeenCalledWith(422);
|
|
138
|
+
expect(response.json).toHaveBeenCalledWith({ message: 'mapped' });
|
|
139
|
+
});
|
|
140
|
+
it('should default express success and error payloads when they are omitted', async () => {
|
|
141
|
+
let successRouteHandler;
|
|
142
|
+
let errorRouteHandler;
|
|
143
|
+
const successController = {
|
|
144
|
+
handle: vitest_1.vi.fn().mockResolvedValue({}),
|
|
145
|
+
throw: vitest_1.vi.fn(),
|
|
146
|
+
};
|
|
147
|
+
const errorController = {
|
|
148
|
+
handle: vitest_1.vi.fn().mockRejectedValue(new Error('failed')),
|
|
149
|
+
throw: vitest_1.vi.fn().mockReturnValue({
|
|
150
|
+
code: 418,
|
|
151
|
+
}),
|
|
152
|
+
};
|
|
153
|
+
const response = {
|
|
154
|
+
status: vitest_1.vi.fn().mockReturnThis(),
|
|
155
|
+
json: vitest_1.vi.fn().mockReturnThis(),
|
|
156
|
+
};
|
|
157
|
+
expressInstance.delete.mockImplementation((_url, handler) => {
|
|
158
|
+
successRouteHandler = handler;
|
|
159
|
+
});
|
|
160
|
+
expressInstance.put.mockImplementation((_url, handler) => {
|
|
161
|
+
errorRouteHandler = handler;
|
|
162
|
+
});
|
|
163
|
+
const adapter = new express_adapter_1.default({
|
|
164
|
+
NODE_ENV: 'test',
|
|
165
|
+
});
|
|
166
|
+
adapter.on('delete', '/partners', successController);
|
|
167
|
+
adapter.on('put', '/partners', errorController);
|
|
168
|
+
await successRouteHandler({
|
|
169
|
+
body: {},
|
|
170
|
+
params: {},
|
|
171
|
+
headers: {},
|
|
172
|
+
query: {},
|
|
173
|
+
}, response);
|
|
174
|
+
await errorRouteHandler({
|
|
175
|
+
body: {},
|
|
176
|
+
params: {},
|
|
177
|
+
headers: {},
|
|
178
|
+
query: {},
|
|
179
|
+
}, response);
|
|
180
|
+
expect(response.status).toHaveBeenNthCalledWith(1, 200);
|
|
181
|
+
expect(response.json).toHaveBeenNthCalledWith(1, {});
|
|
182
|
+
expect(response.status).toHaveBeenNthCalledWith(2, 418);
|
|
183
|
+
expect(response.json).toHaveBeenNthCalledWith(2, {});
|
|
184
|
+
});
|
|
185
|
+
it('should configure fastify and route requests', async () => {
|
|
186
|
+
let routeHandler;
|
|
187
|
+
const controller = {
|
|
188
|
+
handle: vitest_1.vi.fn().mockResolvedValue({
|
|
189
|
+
code: 200,
|
|
190
|
+
data: { id: '1' },
|
|
191
|
+
}),
|
|
192
|
+
throw: vitest_1.vi.fn(),
|
|
193
|
+
};
|
|
194
|
+
const reply = {
|
|
195
|
+
status: vitest_1.vi.fn().mockReturnThis(),
|
|
196
|
+
send: vitest_1.vi.fn().mockReturnThis(),
|
|
197
|
+
};
|
|
198
|
+
const consoleLog = vitest_1.vi
|
|
199
|
+
.spyOn(console, 'log')
|
|
200
|
+
.mockImplementation(() => undefined);
|
|
201
|
+
fastifyInstance.get.mockImplementation((_url, handler) => {
|
|
202
|
+
routeHandler = handler;
|
|
203
|
+
});
|
|
204
|
+
fastifyInstance.listen.mockImplementation((_options, callback) => {
|
|
205
|
+
callback(null, undefined);
|
|
206
|
+
});
|
|
207
|
+
const adapter = new fastify_adapter_1.default({
|
|
208
|
+
NODE_ENV: 'production',
|
|
209
|
+
});
|
|
210
|
+
expect(fastify_1.default).toHaveBeenCalledTimes(1);
|
|
211
|
+
expect(fastifyInstance.register).toHaveBeenCalledTimes(1);
|
|
212
|
+
adapter.on('get', '/partners', controller);
|
|
213
|
+
await routeHandler({
|
|
214
|
+
body: { id: '1' },
|
|
215
|
+
params: { partnerId: '1' },
|
|
216
|
+
headers: { authorization: 'token' },
|
|
217
|
+
query: { page: '1' },
|
|
218
|
+
}, reply);
|
|
219
|
+
expect(controller.handle).toHaveBeenCalledWith({
|
|
220
|
+
body: { id: '1' },
|
|
221
|
+
params: { partnerId: '1' },
|
|
222
|
+
headers: { authorization: 'token' },
|
|
223
|
+
query: { page: '1' },
|
|
224
|
+
});
|
|
225
|
+
expect(reply.status).toHaveBeenCalledWith(200);
|
|
226
|
+
expect(reply.send).toHaveBeenCalledWith({ id: '1' });
|
|
227
|
+
await adapter.listen(3333);
|
|
228
|
+
expect(fastifyInstance.ready).toHaveBeenCalledTimes(1);
|
|
229
|
+
expect(consoleLog).toHaveBeenCalledWith('🚀 Server is running on PORT 3333');
|
|
230
|
+
await adapter.close();
|
|
231
|
+
expect(fastifyInstance.close).toHaveBeenCalledTimes(1);
|
|
232
|
+
});
|
|
233
|
+
it('should map fastify controller errors and handle listen failures', async () => {
|
|
234
|
+
let routeHandler;
|
|
235
|
+
const controller = {
|
|
236
|
+
handle: vitest_1.vi.fn().mockRejectedValue(new Error('failed')),
|
|
237
|
+
throw: vitest_1.vi.fn().mockReturnValue({
|
|
238
|
+
code: 400,
|
|
239
|
+
data: { message: 'mapped' },
|
|
240
|
+
}),
|
|
241
|
+
};
|
|
242
|
+
const reply = {
|
|
243
|
+
status: vitest_1.vi.fn().mockReturnThis(),
|
|
244
|
+
send: vitest_1.vi.fn().mockReturnThis(),
|
|
245
|
+
};
|
|
246
|
+
const consoleError = vitest_1.vi
|
|
247
|
+
.spyOn(console, 'error')
|
|
248
|
+
.mockImplementation(() => undefined);
|
|
249
|
+
const exitSpy = vitest_1.vi
|
|
250
|
+
.spyOn(process, 'exit')
|
|
251
|
+
.mockImplementation((() => undefined));
|
|
252
|
+
fastifyInstance.post.mockImplementation((_url, handler) => {
|
|
253
|
+
routeHandler = handler;
|
|
254
|
+
});
|
|
255
|
+
fastifyInstance.listen.mockImplementation((_options, callback) => {
|
|
256
|
+
callback(new Error('listen failed'), undefined);
|
|
257
|
+
});
|
|
258
|
+
const adapter = new fastify_adapter_1.default({
|
|
259
|
+
NODE_ENV: 'test',
|
|
260
|
+
});
|
|
261
|
+
adapter.on('post', '/partners', controller);
|
|
262
|
+
await routeHandler({
|
|
263
|
+
body: {},
|
|
264
|
+
params: {},
|
|
265
|
+
headers: {},
|
|
266
|
+
query: {},
|
|
267
|
+
}, reply);
|
|
268
|
+
expect(controller.throw).toHaveBeenCalledWith(expect.any(Error));
|
|
269
|
+
expect(reply.status).toHaveBeenCalledWith(400);
|
|
270
|
+
expect(reply.send).toHaveBeenCalledWith({ message: 'mapped' });
|
|
271
|
+
await adapter.listen(3333);
|
|
272
|
+
expect(consoleError).toHaveBeenCalledWith(expect.any(Error));
|
|
273
|
+
expect(exitSpy).toHaveBeenCalledTimes(1);
|
|
274
|
+
});
|
|
275
|
+
it('should default fastify success and error payloads when they are omitted', async () => {
|
|
276
|
+
let successRouteHandler;
|
|
277
|
+
let errorRouteHandler;
|
|
278
|
+
const successController = {
|
|
279
|
+
handle: vitest_1.vi.fn().mockResolvedValue({}),
|
|
280
|
+
throw: vitest_1.vi.fn(),
|
|
281
|
+
};
|
|
282
|
+
const errorController = {
|
|
283
|
+
handle: vitest_1.vi.fn().mockRejectedValue(new Error('failed')),
|
|
284
|
+
throw: vitest_1.vi.fn().mockReturnValue({}),
|
|
285
|
+
};
|
|
286
|
+
const reply = {
|
|
287
|
+
status: vitest_1.vi.fn().mockReturnThis(),
|
|
288
|
+
send: vitest_1.vi.fn().mockReturnThis(),
|
|
289
|
+
};
|
|
290
|
+
fastifyInstance.delete.mockImplementation((_url, handler) => {
|
|
291
|
+
successRouteHandler = handler;
|
|
292
|
+
});
|
|
293
|
+
fastifyInstance.put.mockImplementation((_url, handler) => {
|
|
294
|
+
errorRouteHandler = handler;
|
|
295
|
+
});
|
|
296
|
+
const adapter = new fastify_adapter_1.default({
|
|
297
|
+
NODE_ENV: 'test',
|
|
298
|
+
});
|
|
299
|
+
adapter.on('delete', '/partners', successController);
|
|
300
|
+
adapter.on('put', '/partners', errorController);
|
|
301
|
+
await successRouteHandler({
|
|
302
|
+
body: {},
|
|
303
|
+
params: {},
|
|
304
|
+
headers: {},
|
|
305
|
+
query: {},
|
|
306
|
+
}, reply);
|
|
307
|
+
await errorRouteHandler({
|
|
308
|
+
body: {},
|
|
309
|
+
params: {},
|
|
310
|
+
headers: {},
|
|
311
|
+
query: {},
|
|
312
|
+
}, reply);
|
|
313
|
+
expect(reply.status).toHaveBeenNthCalledWith(1, 200);
|
|
314
|
+
expect(reply.send).toHaveBeenNthCalledWith(1, {});
|
|
315
|
+
expect(reply.status).toHaveBeenNthCalledWith(2, 200);
|
|
316
|
+
expect(reply.send).toHaveBeenNthCalledWith(2, {});
|
|
317
|
+
});
|
|
318
|
+
});
|
|
@@ -142,4 +142,47 @@ describe('Authorizer', () => {
|
|
|
142
142
|
});
|
|
143
143
|
expect(response.data).toEqual({ message: 'ok' });
|
|
144
144
|
});
|
|
145
|
+
it('should be able to fallback to auths header', async () => {
|
|
146
|
+
let Test = class Test {
|
|
147
|
+
async handle(_) {
|
|
148
|
+
return {
|
|
149
|
+
data: { message: 'ok' },
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
};
|
|
153
|
+
Test = tslib_1.__decorate([
|
|
154
|
+
(0, authorizer_1.default)({ $and: ['arch.user.create'] })
|
|
155
|
+
], Test);
|
|
156
|
+
const controller = new Test();
|
|
157
|
+
const response = await controller.handle({
|
|
158
|
+
headers: {
|
|
159
|
+
auths: JSON.stringify(['arch.user.create']),
|
|
160
|
+
},
|
|
161
|
+
body: {},
|
|
162
|
+
params: {},
|
|
163
|
+
query: {},
|
|
164
|
+
});
|
|
165
|
+
expect(response.data).toEqual({ message: 'ok' });
|
|
166
|
+
});
|
|
167
|
+
it('should return error when authorizations header is invalid JSON', async () => {
|
|
168
|
+
let Test = class Test {
|
|
169
|
+
async handle(_) {
|
|
170
|
+
return {
|
|
171
|
+
data: { message: 'ok' },
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
};
|
|
175
|
+
Test = tslib_1.__decorate([
|
|
176
|
+
(0, authorizer_1.default)({ $and: ['arch.user.create'] })
|
|
177
|
+
], Test);
|
|
178
|
+
const controller = new Test();
|
|
179
|
+
await expect(() => controller.handle({
|
|
180
|
+
headers: {
|
|
181
|
+
authorizations: 'invalid-json',
|
|
182
|
+
},
|
|
183
|
+
body: {},
|
|
184
|
+
params: {},
|
|
185
|
+
query: {},
|
|
186
|
+
})).rejects.toBeInstanceOf(Error);
|
|
187
|
+
});
|
|
145
188
|
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
+
const vitest_1 = require("vitest");
|
|
27
|
+
const fakeNodeCache = {
|
|
28
|
+
del: vitest_1.vi.fn(),
|
|
29
|
+
flushAll: vitest_1.vi.fn(),
|
|
30
|
+
get: vitest_1.vi.fn(),
|
|
31
|
+
getStats: vitest_1.vi.fn(),
|
|
32
|
+
keys: vitest_1.vi.fn(),
|
|
33
|
+
set: vitest_1.vi.fn(),
|
|
34
|
+
};
|
|
35
|
+
const redisState = {
|
|
36
|
+
instance: null,
|
|
37
|
+
};
|
|
38
|
+
vitest_1.vi.mock('node-cache', () => ({
|
|
39
|
+
default: vitest_1.vi.fn(() => fakeNodeCache),
|
|
40
|
+
}));
|
|
41
|
+
vitest_1.vi.mock('ioredis', () => ({
|
|
42
|
+
default: vitest_1.vi.fn((connection) => {
|
|
43
|
+
redisState.instance = {
|
|
44
|
+
connection,
|
|
45
|
+
del: vitest_1.vi.fn().mockResolvedValue(undefined),
|
|
46
|
+
flushdb: vitest_1.vi.fn().mockResolvedValue(undefined),
|
|
47
|
+
get: vitest_1.vi.fn().mockResolvedValue(null),
|
|
48
|
+
keys: vitest_1.vi.fn().mockResolvedValue([]),
|
|
49
|
+
pipeline: vitest_1.vi.fn(() => {
|
|
50
|
+
const pipeline = {
|
|
51
|
+
del: vitest_1.vi.fn().mockReturnThis(),
|
|
52
|
+
exec: vitest_1.vi.fn().mockResolvedValue(undefined),
|
|
53
|
+
};
|
|
54
|
+
return pipeline;
|
|
55
|
+
}),
|
|
56
|
+
quit: vitest_1.vi.fn().mockResolvedValue(undefined),
|
|
57
|
+
set: vitest_1.vi.fn().mockResolvedValue(undefined),
|
|
58
|
+
};
|
|
59
|
+
return redisState.instance;
|
|
60
|
+
}),
|
|
61
|
+
}));
|
|
62
|
+
const node_cache_1 = require("./clients/node-cache");
|
|
63
|
+
const redis_1 = require("./clients/redis");
|
|
64
|
+
(0, vitest_1.describe)('Cache clients', () => {
|
|
65
|
+
(0, vitest_1.afterEach)(() => {
|
|
66
|
+
vitest_1.vi.clearAllMocks();
|
|
67
|
+
vitest_1.vi.useRealTimers();
|
|
68
|
+
vitest_1.vi.resetModules();
|
|
69
|
+
});
|
|
70
|
+
(0, vitest_1.it)('should start, query and manage the in-memory node cache client', async () => {
|
|
71
|
+
const client = new node_cache_1.NodeCache();
|
|
72
|
+
fakeNodeCache.get.mockResolvedValueOnce(JSON.stringify({ id: '1' }));
|
|
73
|
+
fakeNodeCache.get.mockResolvedValueOnce(undefined);
|
|
74
|
+
fakeNodeCache.getStats.mockReturnValue({ vsize: 1, ksize: 1 });
|
|
75
|
+
fakeNodeCache.keys.mockReturnValue(['cache:1', 'cache:2', 'other']);
|
|
76
|
+
await client.start();
|
|
77
|
+
await (0, vitest_1.expect)(client.get('cache:1')).resolves.toEqual({ id: '1' });
|
|
78
|
+
await (0, vitest_1.expect)(client.get('cache:2')).resolves.toBeNull();
|
|
79
|
+
await (0, vitest_1.expect)(client.set('cache:1', '{"id":"1"}', 10)).resolves.toBeUndefined();
|
|
80
|
+
await (0, vitest_1.expect)(client.getKeys()).resolves.toEqual([
|
|
81
|
+
'cache:1',
|
|
82
|
+
'cache:2',
|
|
83
|
+
'other',
|
|
84
|
+
]);
|
|
85
|
+
await (0, vitest_1.expect)(client.getKeys('^cache')).resolves.toEqual([
|
|
86
|
+
'cache:1',
|
|
87
|
+
'cache:2',
|
|
88
|
+
]);
|
|
89
|
+
await (0, vitest_1.expect)(client.del('cache:1')).resolves.toBeUndefined();
|
|
90
|
+
await (0, vitest_1.expect)(client.delBatch(['cache:1', 'cache:2'])).resolves.toBeUndefined();
|
|
91
|
+
await (0, vitest_1.expect)(client.flush()).resolves.toBeUndefined();
|
|
92
|
+
await (0, vitest_1.expect)(client.close()).resolves.toBeUndefined();
|
|
93
|
+
(0, vitest_1.expect)(fakeNodeCache.set).toHaveBeenCalledWith('cache:1', '{"id":"1"}', 10);
|
|
94
|
+
(0, vitest_1.expect)(fakeNodeCache.del).toHaveBeenNthCalledWith(1, 'cache:1');
|
|
95
|
+
(0, vitest_1.expect)(fakeNodeCache.del).toHaveBeenNthCalledWith(2, 'cache:1');
|
|
96
|
+
(0, vitest_1.expect)(fakeNodeCache.del).toHaveBeenNthCalledWith(3, 'cache:2');
|
|
97
|
+
(0, vitest_1.expect)(fakeNodeCache.flushAll).toHaveBeenCalledTimes(2);
|
|
98
|
+
});
|
|
99
|
+
(0, vitest_1.it)('should skip writes when the in-memory cache is full', async () => {
|
|
100
|
+
const client = new node_cache_1.NodeCache();
|
|
101
|
+
fakeNodeCache.getStats.mockReturnValue({
|
|
102
|
+
vsize: 50000000,
|
|
103
|
+
ksize: 0,
|
|
104
|
+
});
|
|
105
|
+
await client.start();
|
|
106
|
+
await client.set('cache:1', '{"id":"1"}', 10);
|
|
107
|
+
(0, vitest_1.expect)(fakeNodeCache.set).not.toHaveBeenCalled();
|
|
108
|
+
});
|
|
109
|
+
(0, vitest_1.it)('should start the default in-memory cache on import', async () => {
|
|
110
|
+
vitest_1.vi.resetModules();
|
|
111
|
+
const { NodeCache: DynamicNodeCache } = await Promise.resolve().then(() => __importStar(require('./clients/node-cache')));
|
|
112
|
+
const startSpy = vitest_1.vi
|
|
113
|
+
.spyOn(DynamicNodeCache.prototype, 'start')
|
|
114
|
+
.mockResolvedValue(undefined);
|
|
115
|
+
await Promise.resolve().then(() => __importStar(require('./cache-in-memory')));
|
|
116
|
+
await Promise.resolve();
|
|
117
|
+
(0, vitest_1.expect)(startSpy).toHaveBeenCalledTimes(1);
|
|
118
|
+
});
|
|
119
|
+
(0, vitest_1.it)('should operate the Redis client through time-bounded calls', async () => {
|
|
120
|
+
vitest_1.vi.useFakeTimers();
|
|
121
|
+
const client = new redis_1.Redis({
|
|
122
|
+
host: 'localhost',
|
|
123
|
+
timeout: 1,
|
|
124
|
+
});
|
|
125
|
+
await client.start();
|
|
126
|
+
redisState.instance.get.mockResolvedValueOnce(JSON.stringify({ id: '1' }));
|
|
127
|
+
redisState.instance.get.mockResolvedValueOnce(null);
|
|
128
|
+
await (0, vitest_1.expect)(client.get('cache:1')).resolves.toEqual({ id: '1' });
|
|
129
|
+
await (0, vitest_1.expect)(client.get('cache:2')).resolves.toBeNull();
|
|
130
|
+
await (0, vitest_1.expect)(client.set('cache:1', '{"id":"1"}', 10)).resolves.toBeUndefined();
|
|
131
|
+
await (0, vitest_1.expect)(client.set('cache:2', '{"id":"2"}')).resolves.toBeUndefined();
|
|
132
|
+
await (0, vitest_1.expect)(client.del('cache:1')).resolves.toBeUndefined();
|
|
133
|
+
await (0, vitest_1.expect)(client.getKeys('cache:*')).resolves.toEqual([]);
|
|
134
|
+
await (0, vitest_1.expect)(client.flush()).resolves.toBeUndefined();
|
|
135
|
+
await (0, vitest_1.expect)(client.close()).resolves.toBeUndefined();
|
|
136
|
+
(0, vitest_1.expect)(redisState.instance.set).toHaveBeenNthCalledWith(1, 'cache:1', '{"id":"1"}', 'EX', 10);
|
|
137
|
+
(0, vitest_1.expect)(redisState.instance.set).toHaveBeenNthCalledWith(2, 'cache:2', '{"id":"2"}');
|
|
138
|
+
(0, vitest_1.expect)(redisState.instance.del).toHaveBeenCalledWith('cache:1');
|
|
139
|
+
(0, vitest_1.expect)(redisState.instance.keys).toHaveBeenCalledWith('cache:*');
|
|
140
|
+
(0, vitest_1.expect)(redisState.instance.flushdb).toHaveBeenCalledTimes(1);
|
|
141
|
+
(0, vitest_1.expect)(redisState.instance.quit).toHaveBeenCalledTimes(1);
|
|
142
|
+
});
|
|
143
|
+
(0, vitest_1.it)('should delete Redis keys in batch and fallback to timeout when needed', async () => {
|
|
144
|
+
vitest_1.vi.useFakeTimers();
|
|
145
|
+
const client = new redis_1.Redis({
|
|
146
|
+
host: 'localhost',
|
|
147
|
+
timeout: 1,
|
|
148
|
+
});
|
|
149
|
+
await client.start();
|
|
150
|
+
const pendingGet = new Promise(() => undefined);
|
|
151
|
+
redisState.instance.get.mockReturnValueOnce(pendingGet);
|
|
152
|
+
const getPromise = client.get('cache:1');
|
|
153
|
+
await vitest_1.vi.advanceTimersByTimeAsync(1000);
|
|
154
|
+
await (0, vitest_1.expect)(getPromise).resolves.toBeNull();
|
|
155
|
+
await client.delBatch(['cache:1', 'cache:2']);
|
|
156
|
+
const pipeline = redisState.instance.pipeline.mock.results[0].value;
|
|
157
|
+
(0, vitest_1.expect)(pipeline.del).toHaveBeenNthCalledWith(1, 'cache:1');
|
|
158
|
+
(0, vitest_1.expect)(pipeline.del).toHaveBeenNthCalledWith(2, 'cache:2');
|
|
159
|
+
(0, vitest_1.expect)(pipeline.exec).toHaveBeenCalledTimes(1);
|
|
160
|
+
});
|
|
161
|
+
});
|
|
@@ -44,14 +44,15 @@ class NodeCache extends client_1.CacheClient {
|
|
|
44
44
|
}
|
|
45
45
|
/** Remove varias chaves. */
|
|
46
46
|
async delBatch(keyCache) {
|
|
47
|
-
await Promise.all(keyCache.map(this.del));
|
|
47
|
+
await Promise.all(keyCache.map(key => this.del(key)));
|
|
48
48
|
}
|
|
49
49
|
/** Lista chaves; se pattern existir, filtra via RegExp. */
|
|
50
50
|
async getKeys(pattern) {
|
|
51
51
|
const keys = this.client.keys();
|
|
52
52
|
if (!pattern)
|
|
53
53
|
return keys;
|
|
54
|
-
|
|
54
|
+
const regex = new RegExp(pattern);
|
|
55
|
+
return keys.filter(key => regex.test(key));
|
|
55
56
|
}
|
|
56
57
|
/** Encerra e limpa a instancia. */
|
|
57
58
|
async close() {
|