@seidor-cloud-produtos/orbit-backend-lib 2.0.110 → 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/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
|
@@ -5,123 +5,113 @@ const runner_1 = require("./runner");
|
|
|
5
5
|
(0, vitest_1.describe)('RabbitMQScaledJobRunner', () => {
|
|
6
6
|
let amqpQueue;
|
|
7
7
|
let handler;
|
|
8
|
-
let
|
|
9
|
-
let onFinally;
|
|
10
|
-
let runner;
|
|
8
|
+
let logger;
|
|
11
9
|
(0, vitest_1.beforeEach)(() => {
|
|
12
10
|
amqpQueue = {
|
|
13
|
-
|
|
14
|
-
get: vitest_1.vi.fn().mockResolvedValue(null),
|
|
11
|
+
get: vitest_1.vi.fn(),
|
|
15
12
|
ack: vitest_1.vi.fn().mockResolvedValue(undefined),
|
|
16
13
|
nack: vitest_1.vi.fn().mockResolvedValue(undefined),
|
|
17
14
|
close: vitest_1.vi.fn().mockResolvedValue(undefined),
|
|
18
15
|
};
|
|
19
|
-
handler = {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
errorStrategy: 'nack-dlq',
|
|
24
|
-
parse: vitest_1.vi.fn((raw) => ({ ok: true, msg: 'parsed' })),
|
|
16
|
+
handler = {
|
|
17
|
+
handle: vitest_1.vi.fn().mockResolvedValue(undefined),
|
|
18
|
+
getSimultaneity: vitest_1.vi.fn().mockReturnValue(1),
|
|
19
|
+
getTimeoutPerMessageSeconds: vitest_1.vi.fn().mockReturnValue(undefined),
|
|
25
20
|
};
|
|
26
|
-
|
|
27
|
-
|
|
21
|
+
logger = {
|
|
22
|
+
info: vitest_1.vi.fn(),
|
|
23
|
+
warn: vitest_1.vi.fn(),
|
|
24
|
+
error: vitest_1.vi.fn(),
|
|
25
|
+
debug: vitest_1.vi.fn(),
|
|
26
|
+
};
|
|
27
|
+
vitest_1.vi.spyOn(process, 'exit').mockImplementation((() => undefined));
|
|
28
|
+
});
|
|
29
|
+
(0, vitest_1.afterEach)(() => {
|
|
30
|
+
vitest_1.vi.useRealTimers();
|
|
31
|
+
vitest_1.vi.restoreAllMocks();
|
|
28
32
|
});
|
|
29
|
-
(
|
|
30
|
-
|
|
33
|
+
const makeRunner = (options) => new runner_1.RabbitMQScaledJobRunner(amqpQueue, 'queue', handler, options, logger);
|
|
34
|
+
(0, vitest_1.it)('should connect the polling flow, parse the message, ack and close', async () => {
|
|
35
|
+
const rawMessage = { content: Buffer.from(JSON.stringify({ id: '1' })) };
|
|
31
36
|
const channel = {};
|
|
37
|
+
const runner = makeRunner();
|
|
32
38
|
amqpQueue.get.mockResolvedValue({ channel, rawMessage });
|
|
33
39
|
await runner.run();
|
|
34
|
-
(0, vitest_1.expect)(amqpQueue.connect).toHaveBeenCalledWith('vhost');
|
|
35
40
|
(0, vitest_1.expect)(amqpQueue.get).toHaveBeenCalledWith('queue', { noAck: false });
|
|
36
|
-
(0, vitest_1.expect)(
|
|
37
|
-
(0, vitest_1.expect)(handler.handle).toHaveBeenCalledWith({ ok: true, msg: 'parsed' });
|
|
41
|
+
(0, vitest_1.expect)(handler.handle).toHaveBeenCalledWith({ id: '1' });
|
|
38
42
|
(0, vitest_1.expect)(amqpQueue.ack).toHaveBeenCalledWith(channel, rawMessage);
|
|
39
|
-
(0, vitest_1.expect)(amqpQueue.close).
|
|
43
|
+
(0, vitest_1.expect)(amqpQueue.close).toHaveBeenCalledTimes(1);
|
|
44
|
+
(0, vitest_1.expect)(process.exit).toHaveBeenCalledWith(0);
|
|
40
45
|
});
|
|
41
|
-
(0, vitest_1.it)('should
|
|
42
|
-
|
|
43
|
-
const
|
|
44
|
-
|
|
45
|
-
amqpQueue.get.mockResolvedValue({ channel, rawMessage });
|
|
46
|
+
(0, vitest_1.it)('should skip ack when manualAck is disabled', async () => {
|
|
47
|
+
const rawMessage = { content: Buffer.from(JSON.stringify({ id: '1' })) };
|
|
48
|
+
const runner = makeRunner({ manualAck: false });
|
|
49
|
+
amqpQueue.get.mockResolvedValue({ channel: {}, rawMessage });
|
|
46
50
|
await runner.run();
|
|
51
|
+
(0, vitest_1.expect)(amqpQueue.get).toHaveBeenCalledWith('queue', { noAck: true });
|
|
47
52
|
(0, vitest_1.expect)(amqpQueue.ack).not.toHaveBeenCalled();
|
|
53
|
+
(0, vitest_1.expect)(amqpQueue.nack).not.toHaveBeenCalled();
|
|
48
54
|
});
|
|
49
|
-
(0, vitest_1.it)('should nack
|
|
50
|
-
|
|
51
|
-
const rawMessage = { content: Buffer.from('msg') };
|
|
55
|
+
(0, vitest_1.it)('should apply nack-requeue when handler fails', async () => {
|
|
56
|
+
const rawMessage = { content: Buffer.from(JSON.stringify({ id: '1' })) };
|
|
52
57
|
const channel = {};
|
|
58
|
+
const runner = makeRunner({ errorStrategy: 'nack-requeue' });
|
|
53
59
|
amqpQueue.get.mockResolvedValue({ channel, rawMessage });
|
|
54
|
-
handler.handle
|
|
55
|
-
throw new Error('fail');
|
|
56
|
-
});
|
|
60
|
+
handler.handle.mockRejectedValue(new Error('fail'));
|
|
57
61
|
await runner.run();
|
|
58
62
|
(0, vitest_1.expect)(amqpQueue.nack).toHaveBeenCalledWith(channel, rawMessage, true);
|
|
63
|
+
(0, vitest_1.expect)(amqpQueue.ack).not.toHaveBeenCalled();
|
|
59
64
|
});
|
|
60
|
-
(0, vitest_1.it)('should
|
|
61
|
-
|
|
62
|
-
const rawMessage = { content: Buffer.from('msg') };
|
|
63
|
-
const channel = {};
|
|
64
|
-
amqpQueue.get.mockResolvedValue({ channel, rawMessage });
|
|
65
|
-
handler.handle = vitest_1.vi.fn(() => {
|
|
66
|
-
throw new Error('fail');
|
|
67
|
-
});
|
|
68
|
-
await runner.run();
|
|
69
|
-
(0, vitest_1.expect)(amqpQueue.nack).toHaveBeenCalledWith(channel, rawMessage, false);
|
|
70
|
-
});
|
|
71
|
-
(0, vitest_1.it)('should log and return if no message is available', async () => {
|
|
65
|
+
(0, vitest_1.it)('should stop when there is no message available', async () => {
|
|
66
|
+
const runner = makeRunner();
|
|
72
67
|
amqpQueue.get.mockResolvedValue(null);
|
|
73
68
|
await runner.run();
|
|
74
69
|
(0, vitest_1.expect)(handler.handle).not.toHaveBeenCalled();
|
|
70
|
+
(0, vitest_1.expect)(logger.info).toHaveBeenCalledWith('[RabbitMQScaledJobRunner] Nenhuma mensagem disponível.');
|
|
75
71
|
});
|
|
76
|
-
(0, vitest_1.it)('should
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
(0, vitest_1.expect)(amqpQueue.connect).toHaveBeenCalledWith('vhost');
|
|
80
|
-
});
|
|
81
|
-
(0, vitest_1.it)('should log error if amqpQueue.close throws', async () => {
|
|
82
|
-
amqpQueue.close.mockRejectedValue(new Error('fail'));
|
|
83
|
-
const rawMessage = { content: Buffer.from('msg') };
|
|
72
|
+
(0, vitest_1.it)('should handle timeout and nack the message', async () => {
|
|
73
|
+
vitest_1.vi.useFakeTimers();
|
|
74
|
+
const rawMessage = { content: Buffer.from(JSON.stringify({ id: '1' })) };
|
|
84
75
|
const channel = {};
|
|
76
|
+
const runner = makeRunner();
|
|
85
77
|
amqpQueue.get.mockResolvedValue({ channel, rawMessage });
|
|
86
|
-
|
|
87
|
-
|
|
78
|
+
handler.handle.mockImplementation(() => new Promise(() => undefined));
|
|
79
|
+
handler.getTimeoutPerMessageSeconds.mockReturnValue(1);
|
|
80
|
+
const runPromise = runner.run();
|
|
81
|
+
await vitest_1.vi.advanceTimersByTimeAsync(1000);
|
|
82
|
+
await runPromise;
|
|
83
|
+
(0, vitest_1.expect)(amqpQueue.nack).toHaveBeenCalledWith(channel, rawMessage, false);
|
|
84
|
+
(0, vitest_1.expect)(logger.info).toHaveBeenCalledWith('[RabbitMQScaledJobRunner] Erro: Timeout');
|
|
88
85
|
});
|
|
89
|
-
(0, vitest_1.it)('should
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
86
|
+
(0, vitest_1.it)('should ignore errors when nack strategy fails', async () => {
|
|
87
|
+
const runner = makeRunner({ errorStrategy: 'nack-dlq' });
|
|
88
|
+
amqpQueue.nack.mockRejectedValue(new Error('nack failed'));
|
|
89
|
+
await (0, vitest_1.expect)(runner['errorStrategy']({
|
|
90
|
+
channel: {},
|
|
91
|
+
rawMessage: { content: Buffer.from('{}') },
|
|
92
|
+
})).resolves.toBeUndefined();
|
|
93
|
+
(0, vitest_1.expect)(logger.info).toHaveBeenCalledWith('[RabbitMQScaledJobRunner] Falha ao aplicar estratégia de erro');
|
|
97
94
|
});
|
|
98
|
-
(0, vitest_1.it)('should handle
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
const channel = {};
|
|
103
|
-
amqpQueue.get.mockResolvedValue({ channel, rawMessage });
|
|
104
|
-
await runner.run();
|
|
105
|
-
(0, vitest_1.expect)(amqpQueue.nack).toHaveBeenCalledWith(channel, rawMessage, false);
|
|
95
|
+
(0, vitest_1.it)('should return early when there is no message to handle as error context', async () => {
|
|
96
|
+
const runner = makeRunner();
|
|
97
|
+
await (0, vitest_1.expect)(runner['handleError'](new Error('fail'), null)).resolves.toBeUndefined();
|
|
98
|
+
(0, vitest_1.expect)(amqpQueue.nack).not.toHaveBeenCalled();
|
|
106
99
|
});
|
|
107
|
-
(0, vitest_1.it)('should
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
const channel = {};
|
|
112
|
-
amqpQueue.get.mockResolvedValue({ channel, rawMessage });
|
|
113
|
-
handler.handle = vitest_1.vi.fn(() => {
|
|
114
|
-
throw new Error('fail');
|
|
115
|
-
});
|
|
100
|
+
(0, vitest_1.it)('should log close errors and still finish the process', async () => {
|
|
101
|
+
const runner = makeRunner();
|
|
102
|
+
amqpQueue.get.mockResolvedValue(null);
|
|
103
|
+
amqpQueue.close.mockRejectedValue(new Error('close failed'));
|
|
116
104
|
await runner.run();
|
|
117
|
-
(0, vitest_1.expect)(
|
|
105
|
+
(0, vitest_1.expect)(logger.info).toHaveBeenCalledWith('[RabbitMQScaledJobRunner] Erro ao fechar conexão', vitest_1.expect.any(Error));
|
|
106
|
+
(0, vitest_1.expect)(process.exit).toHaveBeenCalledWith(0);
|
|
118
107
|
});
|
|
119
|
-
(0, vitest_1.it)('should handle
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
108
|
+
(0, vitest_1.it)('should handle unexpected outer errors and still close', async () => {
|
|
109
|
+
const runner = makeRunner();
|
|
110
|
+
handler.getSimultaneity.mockImplementation(() => {
|
|
111
|
+
throw new Error('outer failure');
|
|
112
|
+
});
|
|
124
113
|
await runner.run();
|
|
125
|
-
(0, vitest_1.expect)(
|
|
114
|
+
(0, vitest_1.expect)(logger.info).toHaveBeenCalledWith('[RabbitMQScaledJobRunner] Erro: {}');
|
|
115
|
+
(0, vitest_1.expect)(amqpQueue.close).toHaveBeenCalledTimes(1);
|
|
126
116
|
});
|
|
127
117
|
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const tslib_1 = require("tslib");
|
|
4
|
+
const vitest_1 = require("vitest");
|
|
5
|
+
const { sendMock } = vitest_1.vi.hoisted(() => ({
|
|
6
|
+
sendMock: vitest_1.vi.fn(),
|
|
7
|
+
}));
|
|
8
|
+
vitest_1.vi.mock('@aws-sdk/client-sqs', () => ({
|
|
9
|
+
ReceiveMessageCommand: class ReceiveMessageCommand {
|
|
10
|
+
input;
|
|
11
|
+
constructor(input) {
|
|
12
|
+
this.input = input;
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
DeleteMessageCommand: class DeleteMessageCommand {
|
|
16
|
+
input;
|
|
17
|
+
constructor(input) {
|
|
18
|
+
this.input = input;
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
SQSClient: class SQSClient {
|
|
22
|
+
config;
|
|
23
|
+
send = sendMock;
|
|
24
|
+
constructor(config) {
|
|
25
|
+
this.config = config;
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
}));
|
|
29
|
+
const client_sqs_1 = require("@aws-sdk/client-sqs");
|
|
30
|
+
const handler_1 = tslib_1.__importDefault(require("../../../application/queue/handler"));
|
|
31
|
+
const runner_1 = require("./runner");
|
|
32
|
+
class TestHandler extends handler_1.default {
|
|
33
|
+
handleMock = vitest_1.vi.fn().mockResolvedValue(undefined);
|
|
34
|
+
constructor(simultaneity = 1, timeoutPerMessageSeconds) {
|
|
35
|
+
super();
|
|
36
|
+
this.simultaneity = simultaneity;
|
|
37
|
+
this.timeoutPerMessageSeconds = timeoutPerMessageSeconds;
|
|
38
|
+
}
|
|
39
|
+
async handle(message) {
|
|
40
|
+
await this.handleMock(message);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
const createLogger = () => ({
|
|
44
|
+
info: vitest_1.vi.fn(),
|
|
45
|
+
warn: vitest_1.vi.fn(),
|
|
46
|
+
error: vitest_1.vi.fn(),
|
|
47
|
+
debug: vitest_1.vi.fn(),
|
|
48
|
+
});
|
|
49
|
+
(0, vitest_1.describe)('SQSScaledJobRunner', () => {
|
|
50
|
+
(0, vitest_1.beforeEach)(() => {
|
|
51
|
+
sendMock.mockReset();
|
|
52
|
+
});
|
|
53
|
+
(0, vitest_1.afterEach)(() => {
|
|
54
|
+
vitest_1.vi.useRealTimers();
|
|
55
|
+
vitest_1.vi.restoreAllMocks();
|
|
56
|
+
});
|
|
57
|
+
(0, vitest_1.it)('should receive, process and delete messages from SQS', async () => {
|
|
58
|
+
vitest_1.vi.useFakeTimers();
|
|
59
|
+
const handler = new TestHandler(1, 1);
|
|
60
|
+
const logger = createLogger();
|
|
61
|
+
const runner = new runner_1.SQSScaledJobRunner(handler, 'queue-url', {
|
|
62
|
+
sqsRegion: 'us-east-1',
|
|
63
|
+
waitMessagesTimeSeconds: 5,
|
|
64
|
+
}, logger);
|
|
65
|
+
sendMock
|
|
66
|
+
.mockResolvedValueOnce({
|
|
67
|
+
Messages: [
|
|
68
|
+
{
|
|
69
|
+
Body: JSON.stringify({ id: '1' }),
|
|
70
|
+
ReceiptHandle: 'receipt-handle',
|
|
71
|
+
},
|
|
72
|
+
],
|
|
73
|
+
})
|
|
74
|
+
.mockResolvedValueOnce({});
|
|
75
|
+
const processPromise = runner.process();
|
|
76
|
+
await vitest_1.vi.runAllTimersAsync();
|
|
77
|
+
await processPromise;
|
|
78
|
+
(0, vitest_1.expect)(sendMock).toHaveBeenNthCalledWith(1, vitest_1.expect.any(client_sqs_1.ReceiveMessageCommand));
|
|
79
|
+
(0, vitest_1.expect)(sendMock.mock.calls[0][0].input).toEqual({
|
|
80
|
+
QueueUrl: 'queue-url',
|
|
81
|
+
MaxNumberOfMessages: 1,
|
|
82
|
+
WaitTimeSeconds: 5,
|
|
83
|
+
});
|
|
84
|
+
(0, vitest_1.expect)(handler.handleMock).toHaveBeenCalledWith({ id: '1' });
|
|
85
|
+
(0, vitest_1.expect)(sendMock).toHaveBeenNthCalledWith(2, vitest_1.expect.any(client_sqs_1.DeleteMessageCommand));
|
|
86
|
+
(0, vitest_1.expect)(sendMock.mock.calls[1][0].input).toEqual({
|
|
87
|
+
QueueUrl: 'queue-url',
|
|
88
|
+
ReceiptHandle: 'receipt-handle',
|
|
89
|
+
});
|
|
90
|
+
(0, vitest_1.expect)(logger.info).toHaveBeenCalledWith('[SQSScaledJobRunner] Mensagem processada com sucesso');
|
|
91
|
+
(0, vitest_1.expect)(logger.info).toHaveBeenCalledWith('[SQSScaledJobRunner] Mensagem deletada');
|
|
92
|
+
});
|
|
93
|
+
(0, vitest_1.it)('should keep polling until simultaneity is reached when there are no messages', async () => {
|
|
94
|
+
const handler = new TestHandler(2);
|
|
95
|
+
const logger = createLogger();
|
|
96
|
+
const runner = new runner_1.SQSScaledJobRunner(handler, 'queue-url', {
|
|
97
|
+
sqsRegion: 'us-east-1',
|
|
98
|
+
}, logger);
|
|
99
|
+
sendMock.mockResolvedValue({
|
|
100
|
+
Messages: [],
|
|
101
|
+
});
|
|
102
|
+
await runner.process();
|
|
103
|
+
(0, vitest_1.expect)(sendMock).toHaveBeenCalledTimes(2);
|
|
104
|
+
(0, vitest_1.expect)(logger.info).toHaveBeenCalledWith('[SQSScaledJobRunner] Nenhuma mensagem disponível.');
|
|
105
|
+
(0, vitest_1.expect)(handler.handleMock).not.toHaveBeenCalled();
|
|
106
|
+
});
|
|
107
|
+
(0, vitest_1.it)('should log invalid messages and guard the parser against unsupported inputs', async () => {
|
|
108
|
+
const handler = new TestHandler();
|
|
109
|
+
const logger = createLogger();
|
|
110
|
+
const runner = new runner_1.SQSScaledJobRunner(handler, 'queue-url', {
|
|
111
|
+
sqsRegion: 'us-east-1',
|
|
112
|
+
}, logger);
|
|
113
|
+
sendMock.mockResolvedValueOnce({
|
|
114
|
+
Messages: [
|
|
115
|
+
{
|
|
116
|
+
Body: null,
|
|
117
|
+
ReceiptHandle: 'receipt-handle',
|
|
118
|
+
},
|
|
119
|
+
],
|
|
120
|
+
});
|
|
121
|
+
await runner.process();
|
|
122
|
+
(0, vitest_1.expect)(logger.info).toHaveBeenCalledWith(vitest_1.expect.stringContaining('[SQSScaledJobRunner] Erro:'));
|
|
123
|
+
(0, vitest_1.expect)(handler.handleMock).not.toHaveBeenCalled();
|
|
124
|
+
(0, vitest_1.expect)(() => runner_1.SQSScaledJobRunner.parseMessage(undefined)).toThrow('[SQSScaledJobRunner] Mensagem inválida.');
|
|
125
|
+
(0, vitest_1.expect)(() => runner_1.SQSScaledJobRunner.parseMessage(123)).toThrow('[SQSScaledJobRunner] Mensagem deve ser uma string.');
|
|
126
|
+
});
|
|
127
|
+
(0, vitest_1.it)('should race processing with the global timeout when configured', async () => {
|
|
128
|
+
const runner = new runner_1.SQSScaledJobRunner(new TestHandler(), 'queue-url', {
|
|
129
|
+
sqsRegion: 'us-east-1',
|
|
130
|
+
processTimeoutSeconds: 3,
|
|
131
|
+
}, createLogger());
|
|
132
|
+
const processSpy = vitest_1.vi
|
|
133
|
+
.spyOn(runner, 'process')
|
|
134
|
+
.mockImplementation(() => new Promise(() => undefined));
|
|
135
|
+
const timeoutSpy = vitest_1.vi
|
|
136
|
+
.spyOn(runner, 'timeout')
|
|
137
|
+
.mockResolvedValue(undefined);
|
|
138
|
+
await runner.run();
|
|
139
|
+
(0, vitest_1.expect)(processSpy).toHaveBeenCalledTimes(1);
|
|
140
|
+
(0, vitest_1.expect)(timeoutSpy).toHaveBeenCalledWith(3);
|
|
141
|
+
});
|
|
142
|
+
(0, vitest_1.it)('should run processing directly when no global timeout is configured', async () => {
|
|
143
|
+
const runner = new runner_1.SQSScaledJobRunner(new TestHandler(), 'queue-url', {
|
|
144
|
+
sqsRegion: 'us-east-1',
|
|
145
|
+
}, createLogger());
|
|
146
|
+
const processSpy = vitest_1.vi.spyOn(runner, 'process').mockResolvedValue(undefined);
|
|
147
|
+
await runner.run();
|
|
148
|
+
(0, vitest_1.expect)(processSpy).toHaveBeenCalledTimes(1);
|
|
149
|
+
});
|
|
150
|
+
});
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
type TracingResourceAttribute = string | number | boolean | undefined;
|
|
2
|
+
interface IStartTracingOptions {
|
|
3
|
+
serviceName?: string;
|
|
4
|
+
serviceVersion?: string;
|
|
5
|
+
disabledInstrumentations?: string[];
|
|
6
|
+
extraResourceAttributes?: Record<string, TracingResourceAttribute>;
|
|
7
|
+
}
|
|
8
|
+
export declare function shutdownTracing(): Promise<void>;
|
|
9
|
+
export declare function startTracing(options?: IStartTracingOptions): void;
|
|
10
|
+
export {};
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.startTracing = exports.shutdownTracing = void 0;
|
|
4
|
+
const auto_instrumentations_node_1 = require("@opentelemetry/auto-instrumentations-node");
|
|
5
|
+
const resources_1 = require("@opentelemetry/resources");
|
|
6
|
+
const sdk_node_1 = require("@opentelemetry/sdk-node");
|
|
7
|
+
const semantic_conventions_1 = require("@opentelemetry/semantic-conventions");
|
|
8
|
+
const DEFAULT_DISABLED_INSTRUMENTATIONS = ['@opentelemetry/instrumentation-fs'];
|
|
9
|
+
let sdk = null;
|
|
10
|
+
let isShutdownHookRegistered = false;
|
|
11
|
+
let shutdownPromise = null;
|
|
12
|
+
function makeDisabledInstrumentationMap(disabledInstrumentations) {
|
|
13
|
+
return disabledInstrumentations.reduce((accumulator, instrumentationName) => {
|
|
14
|
+
accumulator[instrumentationName] = { enabled: false };
|
|
15
|
+
return accumulator;
|
|
16
|
+
}, {});
|
|
17
|
+
}
|
|
18
|
+
function shutdownTracing() {
|
|
19
|
+
if (sdk === null) {
|
|
20
|
+
return Promise.resolve();
|
|
21
|
+
}
|
|
22
|
+
if (shutdownPromise !== null) {
|
|
23
|
+
return shutdownPromise;
|
|
24
|
+
}
|
|
25
|
+
const currentShutdownPromise = sdk
|
|
26
|
+
.shutdown()
|
|
27
|
+
.then(() => {
|
|
28
|
+
console.log('Tracing terminated');
|
|
29
|
+
sdk = null;
|
|
30
|
+
})
|
|
31
|
+
.catch((error) => {
|
|
32
|
+
console.log('Error terminating tracing', error);
|
|
33
|
+
throw error;
|
|
34
|
+
})
|
|
35
|
+
.finally(() => {
|
|
36
|
+
shutdownPromise = null;
|
|
37
|
+
});
|
|
38
|
+
shutdownPromise = currentShutdownPromise;
|
|
39
|
+
return currentShutdownPromise;
|
|
40
|
+
}
|
|
41
|
+
exports.shutdownTracing = shutdownTracing;
|
|
42
|
+
function registerShutdownHook() {
|
|
43
|
+
if (isShutdownHookRegistered) {
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
process.on('SIGTERM', () => {
|
|
47
|
+
void shutdownTracing();
|
|
48
|
+
});
|
|
49
|
+
isShutdownHookRegistered = true;
|
|
50
|
+
}
|
|
51
|
+
function startTracing(options = {}) {
|
|
52
|
+
if (sdk !== null) {
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
const serviceName = options.serviceName;
|
|
56
|
+
const serviceVersion = options.serviceVersion;
|
|
57
|
+
const disabledInstrumentations = [
|
|
58
|
+
...new Set([
|
|
59
|
+
...DEFAULT_DISABLED_INSTRUMENTATIONS,
|
|
60
|
+
...(options.disabledInstrumentations ?? []),
|
|
61
|
+
]),
|
|
62
|
+
];
|
|
63
|
+
const resourceAttributes = {
|
|
64
|
+
[semantic_conventions_1.ATTR_SERVICE_NAME]: serviceName,
|
|
65
|
+
[semantic_conventions_1.ATTR_SERVICE_VERSION]: serviceVersion,
|
|
66
|
+
...(options.extraResourceAttributes ?? {}),
|
|
67
|
+
};
|
|
68
|
+
sdk = new sdk_node_1.NodeSDK({
|
|
69
|
+
resource: (0, resources_1.resourceFromAttributes)(resourceAttributes),
|
|
70
|
+
instrumentations: [
|
|
71
|
+
(0, auto_instrumentations_node_1.getNodeAutoInstrumentations)(makeDisabledInstrumentationMap(disabledInstrumentations)),
|
|
72
|
+
],
|
|
73
|
+
});
|
|
74
|
+
sdk.start();
|
|
75
|
+
console.log('OpenTelemetry tracing started');
|
|
76
|
+
registerShutdownHook();
|
|
77
|
+
}
|
|
78
|
+
exports.startTracing = startTracing;
|
|
@@ -433,4 +433,27 @@ describe('Validation zod', () => {
|
|
|
433
433
|
}));
|
|
434
434
|
}
|
|
435
435
|
});
|
|
436
|
+
test('should return empty sections when the request omits them', async () => {
|
|
437
|
+
const schema = zod_1.z.object({
|
|
438
|
+
body: zod_1.z.object({
|
|
439
|
+
name: zod_1.z.string().optional(),
|
|
440
|
+
}),
|
|
441
|
+
headers: zod_1.z.object({
|
|
442
|
+
tenantid: zod_1.z.string().optional(),
|
|
443
|
+
}),
|
|
444
|
+
query: zod_1.z.object({
|
|
445
|
+
page: zod_1.z.string().optional(),
|
|
446
|
+
}),
|
|
447
|
+
params: zod_1.z.object({
|
|
448
|
+
id: zod_1.z.string().optional(),
|
|
449
|
+
}),
|
|
450
|
+
});
|
|
451
|
+
const validation = new validation_zod_1.default(schema);
|
|
452
|
+
await expect(validation.validate({})).resolves.toEqual({
|
|
453
|
+
body: {},
|
|
454
|
+
headers: {},
|
|
455
|
+
params: {},
|
|
456
|
+
query: {},
|
|
457
|
+
});
|
|
458
|
+
});
|
|
436
459
|
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const vitest_1 = require("vitest");
|
|
4
|
+
const get_take_and_skip_1 = require("./get-take-and-skip");
|
|
5
|
+
(0, vitest_1.describe)('getTakeAndSkip', () => {
|
|
6
|
+
(0, vitest_1.it)('should parse pagination values and apply defaults', () => {
|
|
7
|
+
(0, vitest_1.expect)((0, get_take_and_skip_1.getTakeAndSkip)('10', '2')).toEqual({
|
|
8
|
+
take: 10,
|
|
9
|
+
skip: 2,
|
|
10
|
+
});
|
|
11
|
+
(0, vitest_1.expect)((0, get_take_and_skip_1.getTakeAndSkip)('', '')).toEqual({
|
|
12
|
+
take: 20,
|
|
13
|
+
skip: 1,
|
|
14
|
+
});
|
|
15
|
+
});
|
|
16
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
declare function jumpToCode(event: any): void;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
/* eslint-disable */
|
|
3
|
+
var jumpToCode = (function init() {
|
|
4
|
+
// Classes of code we would like to highlight in the file view
|
|
5
|
+
var missingCoverageClasses = ['.cbranch-no', '.cstat-no', '.fstat-no'];
|
|
6
|
+
// Elements to highlight in the file listing view
|
|
7
|
+
var fileListingElements = ['td.pct.low'];
|
|
8
|
+
// We don't want to select elements that are direct descendants of another match
|
|
9
|
+
var notSelector = ':not(' + missingCoverageClasses.join('):not(') + ') > '; // becomes `:not(a):not(b) > `
|
|
10
|
+
// Selecter that finds elements on the page to which we can jump
|
|
11
|
+
var selector =
|
|
12
|
+
fileListingElements.join(', ') +
|
|
13
|
+
', ' +
|
|
14
|
+
notSelector +
|
|
15
|
+
missingCoverageClasses.join(', ' + notSelector); // becomes `:not(a):not(b) > a, :not(a):not(b) > b`
|
|
16
|
+
// The NodeList of matching elements
|
|
17
|
+
var missingCoverageElements = document.querySelectorAll(selector);
|
|
18
|
+
var currentIndex;
|
|
19
|
+
function toggleClass(index) {
|
|
20
|
+
missingCoverageElements.item(currentIndex).classList.remove('highlighted');
|
|
21
|
+
missingCoverageElements.item(index).classList.add('highlighted');
|
|
22
|
+
}
|
|
23
|
+
function makeCurrent(index) {
|
|
24
|
+
toggleClass(index);
|
|
25
|
+
currentIndex = index;
|
|
26
|
+
missingCoverageElements.item(index).scrollIntoView({
|
|
27
|
+
behavior: 'smooth',
|
|
28
|
+
block: 'center',
|
|
29
|
+
inline: 'center',
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
function goToPrevious() {
|
|
33
|
+
var nextIndex = 0;
|
|
34
|
+
if (typeof currentIndex !== 'number' || currentIndex === 0) {
|
|
35
|
+
nextIndex = missingCoverageElements.length - 1;
|
|
36
|
+
} else if (missingCoverageElements.length > 1) {
|
|
37
|
+
nextIndex = currentIndex - 1;
|
|
38
|
+
}
|
|
39
|
+
makeCurrent(nextIndex);
|
|
40
|
+
}
|
|
41
|
+
function goToNext() {
|
|
42
|
+
var nextIndex = 0;
|
|
43
|
+
if (
|
|
44
|
+
typeof currentIndex === 'number' &&
|
|
45
|
+
currentIndex < missingCoverageElements.length - 1
|
|
46
|
+
) {
|
|
47
|
+
nextIndex = currentIndex + 1;
|
|
48
|
+
}
|
|
49
|
+
makeCurrent(nextIndex);
|
|
50
|
+
}
|
|
51
|
+
return function jump(event) {
|
|
52
|
+
if (
|
|
53
|
+
document.getElementById('fileSearch') === document.activeElement &&
|
|
54
|
+
document.activeElement != null
|
|
55
|
+
) {
|
|
56
|
+
// if we're currently focused on the search input, we don't want to navigate
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
switch (event.which) {
|
|
60
|
+
case 78: // n
|
|
61
|
+
case 74: // j
|
|
62
|
+
goToNext();
|
|
63
|
+
break;
|
|
64
|
+
case 66: // b
|
|
65
|
+
case 75: // k
|
|
66
|
+
case 80: // p
|
|
67
|
+
goToPrevious();
|
|
68
|
+
break;
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
})();
|
|
72
|
+
window.addEventListener('keydown', jumpToCode);
|
|
File without changes
|