@quatrain/queue-amqp 1.3.3 → 1.3.4

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.
@@ -8,36 +8,37 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
8
8
  step((generator = generator.apply(thisArg, _arguments || [])).next());
9
9
  });
10
10
  };
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
11
14
  Object.defineProperty(exports, "__esModule", { value: true });
12
15
  const AmqpQueueAdapter_1 = require("./AmqpQueueAdapter");
13
- const amqp_client_1 = require("@cloudamqp/amqp-client");
16
+ const amqplib_1 = __importDefault(require("amqplib"));
14
17
  const queue_1 = require("@quatrain/queue");
15
- // Mock the @cloudamqp/amqp-client library
16
- jest.mock('@cloudamqp/amqp-client');
17
- // Mock @quatrain/queue to spy on Queue.info
18
- jest.mock('@quatrain/queue', () => (Object.assign(Object.assign({}, jest.requireActual('@quatrain/queue')), { Queue: {
19
- info: jest.fn(),
20
- } })));
21
- const mockPublish = jest
22
- .fn()
23
- .mockResolvedValue({ confirmId: 'mock-confirm-id' });
24
- const mockSubscribe = jest.fn();
25
- const mockQueue = jest.fn().mockResolvedValue({
26
- publish: mockPublish,
27
- subscribe: mockSubscribe,
28
- });
29
- const mockChannel = jest.fn().mockResolvedValue({
30
- queue: mockQueue,
18
+ // Mock the amqplib library
19
+ jest.mock('amqplib');
20
+ const mockSendToQueue = jest.fn();
21
+ const mockAck = jest.fn();
22
+ const mockNack = jest.fn();
23
+ const mockAssertQueue = jest.fn().mockResolvedValue({});
24
+ const mockPrefetch = jest.fn().mockResolvedValue({});
25
+ const mockConsume = jest.fn().mockResolvedValue({});
26
+ const mockCloseChannel = jest.fn().mockResolvedValue({});
27
+ const mockCreateChannel = jest.fn().mockResolvedValue({
28
+ sendToQueue: mockSendToQueue,
29
+ assertQueue: mockAssertQueue,
30
+ prefetch: mockPrefetch,
31
+ consume: mockConsume,
32
+ ack: mockAck,
33
+ nack: mockNack,
34
+ close: mockCloseChannel,
31
35
  });
36
+ const mockCloseConnection = jest.fn().mockResolvedValue({});
32
37
  const mockConnect = jest.fn().mockResolvedValue({
33
- channel: mockChannel,
34
- });
35
- const AMQPClientMock = amqp_client_1.AMQPClient;
36
- AMQPClientMock.mockImplementation(() => {
37
- return {
38
- connect: mockConnect,
39
- };
38
+ createChannel: mockCreateChannel,
39
+ close: mockCloseConnection,
40
40
  });
41
+ amqplib_1.default.connect.mockImplementation(mockConnect);
41
42
  describe('AmqpQueueAdapter', () => {
42
43
  const params = {
43
44
  config: {
@@ -48,21 +49,48 @@ describe('AmqpQueueAdapter', () => {
48
49
  },
49
50
  topic: 'default-topic',
50
51
  };
52
+ let mockProcessExit;
53
+ let mockLogger;
54
+ beforeAll(() => {
55
+ mockLogger = {
56
+ info: jest.fn(),
57
+ debug: jest.fn(),
58
+ warn: jest.fn(),
59
+ error: jest.fn(),
60
+ };
61
+ jest.spyOn(queue_1.Queue.logger, 'clone').mockReturnValue(mockLogger);
62
+ });
51
63
  beforeEach(() => {
52
- // Clear all instances and calls to constructor and all methods:
53
- AMQPClientMock.mockClear();
64
+ mockProcessExit = jest.spyOn(process, 'exit').mockImplementation(() => undefined);
54
65
  mockConnect.mockClear();
55
- mockChannel.mockClear();
56
- mockQueue.mockClear();
57
- mockPublish.mockClear();
58
- mockSubscribe.mockClear();
59
- queue_1.Queue.info.mockClear();
66
+ mockCreateChannel.mockClear();
67
+ mockCloseConnection.mockClear();
68
+ mockSendToQueue.mockClear();
69
+ mockAssertQueue.mockClear();
70
+ mockPrefetch.mockClear();
71
+ mockConsume.mockClear();
72
+ mockAck.mockClear();
73
+ mockNack.mockClear();
74
+ mockCloseChannel.mockClear();
75
+ mockLogger.info.mockClear();
76
+ mockLogger.debug.mockClear();
77
+ mockLogger.warn.mockClear();
78
+ mockLogger.error.mockClear();
60
79
  });
61
- it('should construct with default and custom parameters', () => {
62
- new AmqpQueueAdapter_1.AmqpQueueAdapter({ config: {} });
63
- expect(AMQPClientMock).toHaveBeenCalledWith('amqp://guest:guest@localhost:5672?frameMax=0');
64
- new AmqpQueueAdapter_1.AmqpQueueAdapter(params);
65
- expect(AMQPClientMock).toHaveBeenCalledWith('amqp://test-user:test-password@test-host:1234?frameMax=0');
80
+ afterEach(() => {
81
+ mockProcessExit.mockRestore();
82
+ });
83
+ describe('connection parameters', () => {
84
+ it('should connect with default parameters', () => __awaiter(void 0, void 0, void 0, function* () {
85
+ const adapter = new AmqpQueueAdapter_1.AmqpQueueAdapter({ config: {} });
86
+ yield adapter._connect();
87
+ expect(mockConnect).toHaveBeenCalledWith('amqp://guest:guest@localhost:5672');
88
+ }));
89
+ it('should connect with custom parameters', () => __awaiter(void 0, void 0, void 0, function* () {
90
+ const adapter = new AmqpQueueAdapter_1.AmqpQueueAdapter(params);
91
+ yield adapter._connect();
92
+ expect(mockConnect).toHaveBeenCalledWith('amqp://test-user:test-password@test-host:1234');
93
+ }));
66
94
  });
67
95
  describe('send', () => {
68
96
  it('should send a message to the specified topic', () => __awaiter(void 0, void 0, void 0, function* () {
@@ -71,12 +99,11 @@ describe('AmqpQueueAdapter', () => {
71
99
  const topic = 'test-topic';
72
100
  const confirmId = yield adapter.send(data, topic);
73
101
  expect(mockConnect).toHaveBeenCalledTimes(1);
74
- expect(mockChannel).toHaveBeenCalledTimes(1);
75
- expect(mockQueue).toHaveBeenCalledWith(topic);
76
- expect(mockPublish).toHaveBeenCalledWith(Buffer.from(JSON.stringify(data)), { deliveryMode: 2 });
77
- expect(queue_1.Queue.info).toHaveBeenCalledWith(`[AMQP] Sending message to ${topic}`);
78
- expect(queue_1.Queue.info).toHaveBeenCalledWith(`[AMQP] Message send with id mock-confirm-id`);
79
- expect(confirmId).toBe('mock-confirm-id');
102
+ expect(mockCreateChannel).toHaveBeenCalledTimes(1);
103
+ expect(mockSendToQueue).toHaveBeenCalledWith(topic, Buffer.from(JSON.stringify(data)));
104
+ expect(mockCloseChannel).toHaveBeenCalledTimes(1);
105
+ expect(mockLogger.info).toHaveBeenCalledWith(`Sending message to ${topic}`);
106
+ expect(confirmId).toBeDefined();
80
107
  }));
81
108
  });
82
109
  describe('listen', () => {
@@ -85,16 +112,17 @@ describe('AmqpQueueAdapter', () => {
85
112
  const handler = jest.fn();
86
113
  yield adapter.listen(undefined, handler);
87
114
  expect(mockConnect).toHaveBeenCalledTimes(1);
88
- expect(mockChannel).toHaveBeenCalledTimes(1);
89
- expect(mockQueue).toHaveBeenCalledWith(params.topic);
90
- expect(mockSubscribe).toHaveBeenCalledWith({ noAck: true }, expect.any(Function));
115
+ expect(mockCreateChannel).toHaveBeenCalledTimes(1);
116
+ expect(mockAssertQueue).toHaveBeenCalledWith(params.topic, { durable: true, autoDelete: false });
117
+ expect(mockPrefetch).toHaveBeenCalledWith(0);
118
+ expect(mockConsume).toHaveBeenCalledWith(params.topic, expect.any(Function), { noAck: false });
91
119
  }));
92
120
  it('should listen to a specific topic', () => __awaiter(void 0, void 0, void 0, function* () {
93
121
  const adapter = new AmqpQueueAdapter_1.AmqpQueueAdapter(params);
94
122
  const handler = jest.fn();
95
123
  const topic = 'specific-topic';
96
124
  yield adapter.listen(topic, handler);
97
- expect(mockQueue).toHaveBeenCalledWith(topic);
125
+ expect(mockAssertQueue).toHaveBeenCalledWith(topic, { durable: true, autoDelete: false });
98
126
  }));
99
127
  it('should throw an error if no topic is available', () => __awaiter(void 0, void 0, void 0, function* () {
100
128
  const adapter = new AmqpQueueAdapter_1.AmqpQueueAdapter({ config: {} });
@@ -106,13 +134,14 @@ describe('AmqpQueueAdapter', () => {
106
134
  const handler = jest.fn();
107
135
  const messageContent = { data: 'test message' };
108
136
  const message = {
109
- bodyToString: () => JSON.stringify(messageContent),
137
+ content: Buffer.from(JSON.stringify(messageContent)),
110
138
  };
111
- mockSubscribe.mockImplementation((options, callback) => __awaiter(void 0, void 0, void 0, function* () {
139
+ mockConsume.mockImplementation((topic, callback, options) => __awaiter(void 0, void 0, void 0, function* () {
112
140
  yield callback(message);
113
141
  }));
114
142
  yield adapter.listen('any-topic', handler);
115
- expect(handler).toHaveBeenCalledWith(JSON.stringify(messageContent));
143
+ expect(handler).toHaveBeenCalledWith(JSON.stringify(messageContent), undefined);
144
+ expect(mockAck).toHaveBeenCalledWith(message);
116
145
  }));
117
146
  });
118
147
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@quatrain/queue-amqp",
3
- "version": "1.3.3",
3
+ "version": "1.3.4",
4
4
  "description": "Queue adapter for AMQP compatible queue",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -35,7 +35,7 @@
35
35
  },
36
36
  "dependencies": {
37
37
  "@cloudamqp/amqp-client": "^3.4.1",
38
- "@quatrain/core": "^1.2.6",
38
+ "@quatrain/core": "^1.2.9",
39
39
  "@quatrain/queue": "^1.2.3",
40
40
  "amqplib": "^0.10.9"
41
41
  },
@@ -1,41 +1,37 @@
1
1
  import { AmqpQueueAdapter } from './AmqpQueueAdapter'
2
- import { AMQPClient, AMQPMessage } from '@cloudamqp/amqp-client'
2
+ import amqplib from 'amqplib'
3
3
  import { Queue } from '@quatrain/queue'
4
4
 
5
- // Mock the @cloudamqp/amqp-client library
6
- jest.mock('@cloudamqp/amqp-client')
7
-
8
- // Mock @quatrain/queue to spy on Queue.info
9
- jest.mock('@quatrain/queue', () => ({
10
- ...jest.requireActual('@quatrain/queue'),
11
- Queue: {
12
- info: jest.fn(),
13
- },
14
- }))
15
-
16
- const mockPublish = jest
17
- .fn()
18
- .mockResolvedValue({ confirmId: 'mock-confirm-id' })
19
- const mockSubscribe = jest.fn()
20
- const mockQueue = jest.fn().mockResolvedValue({
21
- publish: mockPublish,
22
- subscribe: mockSubscribe,
23
- })
24
- const mockChannel = jest.fn().mockResolvedValue({
25
- queue: mockQueue,
26
- })
27
- const mockConnect = jest.fn().mockResolvedValue({
28
- channel: mockChannel,
5
+ // Mock the amqplib library
6
+ jest.mock('amqplib')
7
+
8
+ const mockSendToQueue = jest.fn()
9
+ const mockAck = jest.fn()
10
+ const mockNack = jest.fn()
11
+ const mockAssertQueue = jest.fn().mockResolvedValue({})
12
+ const mockPrefetch = jest.fn().mockResolvedValue({})
13
+ const mockConsume = jest.fn().mockResolvedValue({})
14
+ const mockCloseChannel = jest.fn().mockResolvedValue({})
15
+
16
+ const mockCreateChannel = jest.fn().mockResolvedValue({
17
+ sendToQueue: mockSendToQueue,
18
+ assertQueue: mockAssertQueue,
19
+ prefetch: mockPrefetch,
20
+ consume: mockConsume,
21
+ ack: mockAck,
22
+ nack: mockNack,
23
+ close: mockCloseChannel,
29
24
  })
30
25
 
31
- const AMQPClientMock = AMQPClient as jest.Mock
26
+ const mockCloseConnection = jest.fn().mockResolvedValue({})
32
27
 
33
- AMQPClientMock.mockImplementation(() => {
34
- return {
35
- connect: mockConnect,
36
- }
28
+ const mockConnect = jest.fn().mockResolvedValue({
29
+ createChannel: mockCreateChannel,
30
+ close: mockCloseConnection,
37
31
  })
38
32
 
33
+ ;(amqplib.connect as jest.Mock).mockImplementation(mockConnect)
34
+
39
35
  describe('AmqpQueueAdapter', () => {
40
36
  const params = {
41
37
  config: {
@@ -47,27 +43,53 @@ describe('AmqpQueueAdapter', () => {
47
43
  topic: 'default-topic',
48
44
  }
49
45
 
46
+ let mockProcessExit: jest.SpyInstance
47
+ let mockLogger: any
48
+
49
+ beforeAll(() => {
50
+ mockLogger = {
51
+ info: jest.fn(),
52
+ debug: jest.fn(),
53
+ warn: jest.fn(),
54
+ error: jest.fn(),
55
+ }
56
+ jest.spyOn(Queue.logger, 'clone').mockReturnValue(mockLogger)
57
+ })
58
+
50
59
  beforeEach(() => {
51
- // Clear all instances and calls to constructor and all methods:
52
- AMQPClientMock.mockClear()
60
+ mockProcessExit = jest.spyOn(process, 'exit').mockImplementation(() => undefined as never)
53
61
  mockConnect.mockClear()
54
- mockChannel.mockClear()
55
- mockQueue.mockClear()
56
- mockPublish.mockClear()
57
- mockSubscribe.mockClear()
58
- ;(Queue.info as jest.Mock).mockClear()
62
+ mockCreateChannel.mockClear()
63
+ mockCloseConnection.mockClear()
64
+ mockSendToQueue.mockClear()
65
+ mockAssertQueue.mockClear()
66
+ mockPrefetch.mockClear()
67
+ mockConsume.mockClear()
68
+ mockAck.mockClear()
69
+ mockNack.mockClear()
70
+ mockCloseChannel.mockClear()
71
+ mockLogger.info.mockClear()
72
+ mockLogger.debug.mockClear()
73
+ mockLogger.warn.mockClear()
74
+ mockLogger.error.mockClear()
59
75
  })
60
76
 
61
- it('should construct with default and custom parameters', () => {
62
- new AmqpQueueAdapter({ config: {} })
63
- expect(AMQPClientMock).toHaveBeenCalledWith(
64
- 'amqp://guest:guest@localhost:5672?frameMax=0'
65
- )
77
+ afterEach(() => {
78
+ mockProcessExit.mockRestore()
79
+ })
80
+
81
+ describe('connection parameters', () => {
82
+ it('should connect with default parameters', async () => {
83
+ const adapter = new AmqpQueueAdapter({ config: {} })
84
+ await (adapter as any)._connect()
85
+ expect(mockConnect).toHaveBeenCalledWith('amqp://guest:guest@localhost:5672')
86
+ })
66
87
 
67
- new AmqpQueueAdapter(params)
68
- expect(AMQPClientMock).toHaveBeenCalledWith(
69
- 'amqp://test-user:test-password@test-host:1234?frameMax=0'
70
- )
88
+ it('should connect with custom parameters', async () => {
89
+ const adapter = new AmqpQueueAdapter(params)
90
+ await (adapter as any)._connect()
91
+ expect(mockConnect).toHaveBeenCalledWith('amqp://test-user:test-password@test-host:1234')
92
+ })
71
93
  })
72
94
 
73
95
  describe('send', () => {
@@ -79,19 +101,16 @@ describe('AmqpQueueAdapter', () => {
79
101
  const confirmId = await adapter.send(data, topic)
80
102
 
81
103
  expect(mockConnect).toHaveBeenCalledTimes(1)
82
- expect(mockChannel).toHaveBeenCalledTimes(1)
83
- expect(mockQueue).toHaveBeenCalledWith(topic)
84
- expect(mockPublish).toHaveBeenCalledWith(
85
- Buffer.from(JSON.stringify(data)),
86
- { deliveryMode: 2 }
104
+ expect(mockCreateChannel).toHaveBeenCalledTimes(1)
105
+ expect(mockSendToQueue).toHaveBeenCalledWith(
106
+ topic,
107
+ Buffer.from(JSON.stringify(data))
87
108
  )
88
- expect(Queue.info).toHaveBeenCalledWith(
89
- `[AMQP] Sending message to ${topic}`
109
+ expect(mockCloseChannel).toHaveBeenCalledTimes(1)
110
+ expect(mockLogger.info).toHaveBeenCalledWith(
111
+ `Sending message to ${topic}`
90
112
  )
91
- expect(Queue.info).toHaveBeenCalledWith(
92
- `[AMQP] Message send with id mock-confirm-id`
93
- )
94
- expect(confirmId).toBe('mock-confirm-id')
113
+ expect(confirmId).toBeDefined()
95
114
  })
96
115
  })
97
116
 
@@ -103,11 +122,13 @@ describe('AmqpQueueAdapter', () => {
103
122
  await adapter.listen(undefined, handler)
104
123
 
105
124
  expect(mockConnect).toHaveBeenCalledTimes(1)
106
- expect(mockChannel).toHaveBeenCalledTimes(1)
107
- expect(mockQueue).toHaveBeenCalledWith(params.topic)
108
- expect(mockSubscribe).toHaveBeenCalledWith(
109
- { noAck: true },
110
- expect.any(Function)
125
+ expect(mockCreateChannel).toHaveBeenCalledTimes(1)
126
+ expect(mockAssertQueue).toHaveBeenCalledWith(params.topic, { durable: true, autoDelete: false })
127
+ expect(mockPrefetch).toHaveBeenCalledWith(0)
128
+ expect(mockConsume).toHaveBeenCalledWith(
129
+ params.topic,
130
+ expect.any(Function),
131
+ { noAck: false }
111
132
  )
112
133
  })
113
134
 
@@ -118,7 +139,7 @@ describe('AmqpQueueAdapter', () => {
118
139
 
119
140
  await adapter.listen(topic, handler)
120
141
 
121
- expect(mockQueue).toHaveBeenCalledWith(topic)
142
+ expect(mockAssertQueue).toHaveBeenCalledWith(topic, { durable: true, autoDelete: false })
122
143
  })
123
144
 
124
145
  it('should throw an error if no topic is available', async () => {
@@ -135,16 +156,20 @@ describe('AmqpQueueAdapter', () => {
135
156
  const handler = jest.fn()
136
157
  const messageContent = { data: 'test message' }
137
158
  const message = {
138
- bodyToString: () => JSON.stringify(messageContent),
139
- } as AMQPMessage
159
+ content: Buffer.from(JSON.stringify(messageContent)),
160
+ } as any
140
161
 
141
- mockSubscribe.mockImplementation(async (options, callback) => {
162
+ mockConsume.mockImplementation(async (topic, callback, options) => {
142
163
  await callback(message)
143
164
  })
144
165
 
145
166
  await adapter.listen('any-topic', handler)
146
167
 
147
- expect(handler).toHaveBeenCalledWith(JSON.stringify(messageContent))
168
+ expect(handler).toHaveBeenCalledWith(
169
+ JSON.stringify(messageContent),
170
+ undefined
171
+ )
172
+ expect(mockAck).toHaveBeenCalledWith(message)
148
173
  })
149
174
  })
150
175
  })