amqplib 2.1.0 → 2.2.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.
@@ -1,171 +0,0 @@
1
- const { describe, it } = require('node:test');
2
- const assert = require('node:assert');
3
- const { forAll } = require('claire');
4
- const codec = require('../lib/codec');
5
- const defs = require('../lib/defs');
6
- const amqp = require('./lib/data');
7
- const { removeExplicitTypes, assertEqualModuloDefaults } = require('./lib/util');
8
-
9
- // These just test known encodings; to generate the answers I used RabbitMQ's binary generator module.
10
- const testCases = [
11
- // integers
12
- ['byte', { byte: 112 }, [4, 98, 121, 116, 101, 98, 112]],
13
- ['byte max value', { byte: 127 }, [4, 98, 121, 116, 101, 98, 127]],
14
- ['byte min value', { byte: -128 }, [4, 98, 121, 116, 101, 98, 128]],
15
- ['< -128 promoted to signed short', { short: -129 }, [5, 115, 104, 111, 114, 116, 115, 255, 127]],
16
- ['> 127 promoted to short', { short: 128 }, [5, 115, 104, 111, 114, 116, 115, 0, 128]],
17
- ['< 2^15 still a short', { short: 0x7fff }, [5, 115, 104, 111, 114, 116, 115, 127, 255]],
18
- ['-2^15 still a short', { short: -0x8000 }, [5, 115, 104, 111, 114, 116, 115, 128, 0]],
19
- ['>= 2^15 promoted to int', { int: 0x8000 }, [3, 105, 110, 116, 73, 0, 0, 128, 0]],
20
- ['< -2^15 promoted to int', { int: -0x8001 }, [3, 105, 110, 116, 73, 255, 255, 127, 255]],
21
- ['< 2^31 still an int', { int: 0x7fffffff }, [3, 105, 110, 116, 73, 127, 255, 255, 255]],
22
- ['>= -2^31 still an int', { int: -0x80000000 }, [3, 105, 110, 116, 73, 128, 0, 0, 0]],
23
- ['>= 2^31 promoted to long', { long: 0x80000000 }, [4, 108, 111, 110, 103, 108, 0, 0, 0, 0, 128, 0, 0, 0]],
24
- ['< -2^31 promoted to long', { long: -0x80000001 }, [4, 108, 111, 110, 103, 108, 255, 255, 255, 255, 127, 255, 255, 255]],
25
-
26
- // floating point
27
- ['float value', { double: 0.5 }, [6, 100, 111, 117, 98, 108, 101, 100, 63, 224, 0, 0, 0, 0, 0, 0]],
28
- ['negative float value', { double: -0.5 }, [6, 100, 111, 117, 98, 108, 101, 100, 191, 224, 0, 0, 0, 0, 0, 0]],
29
- // %% test some boundaries of precision?
30
-
31
- // string
32
- ['string', { string: 'boop' }, [6, 115, 116, 114, 105, 110, 103, 83, 0, 0, 0, 4, 98, 111, 111, 112]],
33
-
34
- // buffer -> byte array
35
- ['byte array from buffer', { bytes: Buffer.from([1, 2, 3, 4]) }, [5, 98, 121, 116, 101, 115, 120, 0, 0, 0, 4, 1, 2, 3, 4]],
36
-
37
- // boolean, void
38
- ['true', { bool: true }, [4, 98, 111, 111, 108, 116, 1]],
39
- ['false', { bool: false }, [4, 98, 111, 111, 108, 116, 0]],
40
- ['null', { void: null }, [4, 118, 111, 105, 100, 86]],
41
-
42
- // array, object
43
- ['array', { array: [6, true, 'foo'] }, [5, 97, 114, 114, 97, 121, 65, 0, 0, 0, 12, 98, 6, 116, 1, 83, 0, 0, 0, 3, 102, 111, 111]],
44
- [
45
- 'object',
46
- { object: { foo: 'bar', baz: 12 } },
47
- [6, 111, 98, 106, 101, 99, 116, 70, 0, 0, 0, 18, 3, 102, 111, 111, 83, 0, 0, 0, 3, 98, 97, 114, 3, 98, 97, 122, 98, 12],
48
- ],
49
-
50
- // exotic types
51
- [
52
- 'timestamp',
53
- { timestamp: { '!': 'timestamp', value: 1357212277527 } },
54
- [9, 116, 105, 109, 101, 115, 116, 97, 109, 112, 84, 0, 0, 1, 60, 0, 39, 219, 23],
55
- ],
56
- [
57
- 'decimal',
58
- { decimal: { '!': 'decimal', value: { digits: 2345, places: 2 } } },
59
- [7, 100, 101, 99, 105, 109, 97, 108, 68, 2, 0, 0, 9, 41],
60
- ],
61
- ['float', { float: { '!': 'float', value: 0.1 } }, [5, 102, 108, 111, 97, 116, 102, 61, 204, 204, 205]],
62
- [
63
- 'unsignedbyte',
64
- { unsignedbyte: { '!': 'unsignedbyte', value: 255 } },
65
- [12, 117, 110, 115, 105, 103, 110, 101, 100, 98, 121, 116, 101, 66, 255],
66
- ],
67
- [
68
- 'unsignedshort',
69
- { unsignedshort: { '!': 'unsignedshort', value: 65535 } },
70
- [13, 117, 110, 115, 105, 103, 110, 101, 100, 115, 104, 111, 114, 116, 117, 255, 255],
71
- ],
72
- [
73
- 'unsignedint',
74
- { unsignedint: { '!': 'unsignedint', value: 4294967295 } },
75
- [11, 117, 110, 115, 105, 103, 110, 101, 100, 105, 110, 116, 105, 255, 255, 255, 255],
76
- ],
77
- ];
78
-
79
- function bufferToArray(b) {
80
- return Array.prototype.slice.call(b);
81
- }
82
-
83
- describe('Codec', () => {
84
-
85
- describe('Implicit encodings', () => {
86
- testCases.forEach(([name, val, expect]) => {
87
- it(name, () => {
88
- const buffer = Buffer.alloc(1000);
89
- const size = codec.encodeTable(buffer, val, 0);
90
- const result = buffer.subarray(4, size);
91
- assert.deepEqual(expect, bufferToArray(result));
92
- });
93
- });
94
- });
95
-
96
- // Whole frames
97
- function roundtrip_table(t) {
98
- const buf = Buffer.alloc(4096);
99
- const size = codec.encodeTable(buf, t, 0);
100
- const decoded = codec.decodeFields(buf.subarray(4, size)); // ignore the length-prefix
101
- try {
102
- assert.deepEqual(removeExplicitTypes(t), decoded);
103
- } catch {
104
- return false;
105
- }
106
- return true;
107
- }
108
-
109
- function roundtrips(T) {
110
- return forAll(T).satisfy((v) => roundtrip_table({ value: v }));
111
- }
112
-
113
- describe('Roundtrip values', () => {
114
- [
115
- amqp.Octet,
116
- amqp.ShortStr,
117
- amqp.LongStr,
118
- amqp.UShort,
119
- amqp.ULong,
120
- amqp.ULongLong,
121
- amqp.UShort,
122
- amqp.Short,
123
- amqp.Long,
124
- amqp.Bit,
125
- amqp.Decimal,
126
- amqp.Timestamp,
127
- amqp.UnsignedByte,
128
- amqp.UnsignedShort,
129
- amqp.UnsignedInt,
130
- amqp.Double,
131
- amqp.Float,
132
- amqp.FieldArray,
133
- amqp.FieldTable,
134
- ].forEach((T) => {
135
- it(`${T.toString()} roundtrip`, roundtrips(T).asTest());
136
- });
137
- });
138
-
139
- function roundtripMethod(Method) {
140
- return forAll(Method).satisfy((method) => {
141
- const buf = defs.encodeMethod(method.id, 0, method.fields);
142
- // FIXME depends on framing, ugh
143
- const fs1 = defs.decode(method.id, buf.subarray(11, buf.length));
144
- assertEqualModuloDefaults(method, fs1);
145
- return true;
146
- });
147
- }
148
-
149
- function roundtripProperties(Properties) {
150
- return forAll(Properties).satisfy((properties) => {
151
- const buf = defs.encodeProperties(properties.id, 0, properties.size, properties.fields);
152
- // FIXME depends on framing, ugh
153
- const fs1 = defs.decode(properties.id, buf.subarray(19, buf.length));
154
- assert.equal(properties.size, Number(buf.readBigUInt64BE(11)));
155
- assertEqualModuloDefaults(properties, fs1);
156
- return true;
157
- });
158
- }
159
-
160
- describe('Roundtrip methods', () => {
161
- amqp.methods.forEach((Method) => {
162
- it(`${Method.toString()} roundtrip`, roundtripMethod(Method).asTest());
163
- });
164
- });
165
-
166
- describe('Roundtrip properties', () => {
167
- amqp.properties.forEach((Properties) => {
168
- it(`${Properties.toString()} roundtrip`, roundtripProperties(Properties).asTest());
169
- });
170
- });
171
- });
@@ -1,155 +0,0 @@
1
- const { describe, it, afterEach } = require('node:test');
2
- const assert = require('node:assert');
3
- const net = require('node:net');
4
- const connect = require('../lib/connect').connect;
5
- const defs = require('../lib/defs');
6
- const { plain, amqplain } = require('../lib/credentials')
7
- const { latch, runServer } = require('./lib/util');
8
-
9
- describe('Connect', () => {
10
-
11
- describe('Connect API', () => {
12
-
13
- let connection;
14
-
15
- afterEach((_t, done) => {
16
- if (connection) connection.close(() => done())
17
- else done();
18
- });
19
-
20
- it('Connection refused', (_t, done) => {
21
- connect('amqp://localhost:23450', {}, (err) => {
22
- assert.strictEqual(err.code, 'ECONNREFUSED');
23
- done();
24
- });
25
- });
26
-
27
- // %% this ought to fail the promise, rather than throwing an error
28
- it('bad URL', (_t, done) => {
29
- assert.throws(() => connect('blurble'), (err) => {
30
- assert.match(err.message, /Expected amqp: or amqps: as the protocol/);
31
- return true;
32
- });
33
- done();
34
- });
35
-
36
- it('wrongly typed open option', (_t, done) => {
37
- connect('amqp://localhost?frameMax=NOT_A_NUMBER', {}, (err) => {
38
- assert.match(err.message, /Field 'frameMax' is the wrong type/);
39
- done();
40
- });
41
- });
42
-
43
- it('serverProperties', (_t, done) => {
44
- connect({ protocol: 'amqp', hostname: 'localhost' }, {}, (err, _connection) => {
45
- connection = _connection;
46
- assert.ifError(err);
47
- assert.equal(connection.serverProperties.product, 'RabbitMQ');
48
- done();
49
- });
50
- });
51
-
52
- it('using custom heartbeat option', (_t, done) => {
53
- connect({ heartbeat: 20 }, {}, (err, _connection) => {
54
- assert.ifError(err);
55
- connection = _connection;
56
- assert.strictEqual(connection.heartbeat, 20);
57
- done();
58
- });
59
- });
60
-
61
- it('wrongly typed heartbeat option', (_t, done) => {
62
- connect('amqp://localhost?heartbeat=NOT_A_NUMBER', {}, (err) => {
63
- assert.match(err.message, /Field 'heartbeat' is the wrong type/);
64
- done();
65
- });
66
- });
67
-
68
- it('using plain credentials', (_t, done) => {
69
- connect('amqp://localhost', { credentials: plain('guest', 'guest') }, (err, _connection) => {
70
- assert.ifError(err);
71
- connection = _connection;
72
- done();
73
- });
74
- });
75
-
76
- it('using amqplain credentials', (_t, done) => {
77
- connect('amqp://localhost', { credentials: amqplain('guest', 'guest') }, (err, _connection) => {
78
- assert.ifError(err);
79
- connection = _connection;
80
- done();
81
- });
82
- });
83
-
84
- it('ipv6', (_t, done) => {
85
- connect('amqp://[::1]', {}, (err, _connection) => {
86
- assert.ifError(err);
87
- connection = _connection;
88
- done();
89
- });
90
- });
91
-
92
- it('using unsupported mechanism', (_t, done) => {
93
- const credentials = { mechanism: 'UNSUPPORTED', response: () => Buffer.from('') };
94
- connect('amqp://localhost', { credentials }, (err) => {
95
- assert.match(err.message, /SASL mechanism UNSUPPORTED is not provided by the server/);
96
- done();
97
- });
98
- });
99
-
100
- it('with a given connection timeout', (_t, done) => {
101
- const timeoutServer = net.createServer(() => { }).listen(31991);
102
-
103
- connect('amqp://localhost:31991', { timeout: 50 }, (err) => {
104
- timeoutServer.close();
105
- assert.match(err.message, /ETIMEDOUT/);
106
- done();
107
- });
108
- });
109
- });
110
-
111
- describe('Errors on connect', () => {
112
-
113
- let server;
114
-
115
- afterEach(() => {
116
- if (server) server.close();
117
- });
118
-
119
- it('closes underlying connection on authentication error', (_t, done) => {
120
- const decrementLatch = latch(2, done);
121
- server = net.createServer((socket) => {
122
- socket.once('data', (protocolHeader) => {
123
- assert.deepStrictEqual(protocolHeader, Buffer.from(`AMQP${String.fromCharCode(0, 0, 9, 1)}`));
124
- runServer(socket, (send, wait) => {
125
- send(defs.ConnectionStart, {
126
- versionMajor: 0,
127
- versionMinor: 9,
128
- serverProperties: {},
129
- mechanisms: Buffer.from('PLAIN'),
130
- locales: Buffer.from('en_US'),
131
- });
132
- wait(defs.ConnectionStartOk)().then(() => {
133
- send(defs.ConnectionClose, {
134
- replyCode: 403,
135
- replyText: 'ACCESS_REFUSED - Login was refused using authentication mechanism PLAIN',
136
- classId: 0,
137
- methodId: 0,
138
- });
139
- });
140
- });
141
- });
142
-
143
- // Wait for the connection to be closed after the authentication error
144
- socket.once('end', () => decrementLatch());
145
- });
146
- server.listen(0);
147
-
148
- connect(`amqp://localhost:${server.address().port}`, {}, (err) => {
149
- assert.match(err.message, /Handshake terminated by server: 403 \(ACCESS-REFUSED\)/);
150
- decrementLatch();
151
- });
152
- });
153
- });
154
-
155
- });