primer cambio

This commit is contained in:
beseira13
2026-01-19 12:12:38 -03:00
parent 5f59dba52d
commit 44990f015a
4759 changed files with 588702 additions and 0 deletions

69
node_modules/amqplib/test/bitset.js generated vendored Normal file
View File

@@ -0,0 +1,69 @@
'use strict';
const claire = require('claire');
const {BitSet} = require('../lib/bitset');
const {
forAll,
data: arb,
label,
choice,
transform
} = claire;
const PosInt = transform(Math.floor, arb.Positive);
const EmptyBitSet = label('bitset', transform(
size => {
return new BitSet(size);
},
choice(arb.Nothing, PosInt)));
suite('BitSet', () => {
test('get bit', forAll(EmptyBitSet, PosInt)
.satisfy((b, bit) => {
b.set(bit);
return b.get(bit);
}).asTest());
test('clear bit', forAll(EmptyBitSet, PosInt)
.satisfy((b, bit) => {
b.set(bit);
b.clear(bit);
return !b.get(bit);
}).asTest());
test('next set of empty', forAll(EmptyBitSet)
.satisfy(b => {
return b.nextSetBit(0) === -1;
}).asTest());
test('next set of one bit', forAll(EmptyBitSet, PosInt)
.satisfy((b, bit) => {
b.set(bit);
return b.nextSetBit(0) === bit;
}).asTest());
test('next set same bit', forAll(EmptyBitSet, PosInt)
.satisfy((b, bit) => {
b.set(bit);
return b.nextSetBit(bit) === bit;
}).asTest());
test('next set following bit', forAll(EmptyBitSet, PosInt)
.satisfy((b, bit) => {
b.set(bit);
return b.nextSetBit(bit+1) === -1;
}).asTest());
test('next clear of empty', forAll(EmptyBitSet, PosInt)
.satisfy((b, bit) => { return b.nextClearBit(bit) === bit; })
.asTest());
test('next clear of one set', forAll(EmptyBitSet, PosInt)
.satisfy((b, bit) => {
b.set(bit);
return b.nextClearBit(bit) === bit + 1;
}).asTest());
});

379
node_modules/amqplib/test/callback_api.js generated vendored Normal file
View File

@@ -0,0 +1,379 @@
'use strict';
var assert = require('assert');
var crypto = require('crypto');
var api = require('../callback_api');
var util = require('./util');
var schedule = util.schedule;
var randomString = util.randomString;
var kCallback = util.kCallback;
var domain = require('domain');
var URL = process.env.URL || 'amqp://localhost';
function connect(cb) {
api.connect(URL, {}, cb);
}
// Construct a node-style callback from a `done` function
function doneCallback(done) {
return function(err, _) {
if (err == null) done();
else done(err);
};
}
function ignore() {}
function twice(done) {
var first = function(err) {
if (err == undefined) second = done;
else second = ignore, done(err);
};
var second = function(err) {
if (err == undefined) first = done;
else first = ignore, done(err);
};
return {first: function(err) { first(err); },
second: function(err) { second(err); }};
}
// Adapt 'done' to a callback that's expected to fail
function failCallback(done) {
return function(err, _) {
if (err == null) done(new Error('Expected failure, got ' + val));
else done();
};
}
function waitForMessages(ch, q, k) {
ch.checkQueue(q, function(e, ok) {
if (e != null) return k(e);
else if (ok.messageCount > 0) return k(null, ok);
else schedule(waitForMessages.bind(null, ch, q, k));
});
}
suite('connect', function() {
test('at all', function(done) {
connect(doneCallback(done));
});
});
suite('updateSecret', function() {
test('updateSecret', function(done) {
connect(kCallback(function(c) {
c.updateSecret(Buffer.from('new secret'), 'no reason', doneCallback(done));
}));
});
});
function channel_test_fn(method) {
return function(name, options, chfun) {
if (arguments.length === 2) {
chfun = options;
options = {};
}
test(name, function(done) {
connect(kCallback(function(c) {
c[method](options, kCallback(function(ch) {
chfun(ch, done);
}, done));
}, done));
});
};
}
var channel_test = channel_test_fn('createChannel');
var confirm_channel_test = channel_test_fn('createConfirmChannel');
suite('channel open', function() {
channel_test('at all', function(ch, done) {
done();
});
channel_test('open and close', function(ch, done) {
ch.close(doneCallback(done));
});
});
suite('assert, check, delete', function() {
channel_test('assert, check, delete queue', function(ch, done) {
ch.assertQueue('test.cb.queue', {}, kCallback(function(q) {
ch.checkQueue('test.cb.queue', kCallback(function(ok) {
ch.deleteQueue('test.cb.queue', {}, doneCallback(done));
}, done));
}, done));
});
channel_test('assert, check, delete exchange', function(ch, done) {
ch.assertExchange(
'test.cb.exchange', 'topic', {}, kCallback(function(ex) {
ch.checkExchange('test.cb.exchange', kCallback(function(ok) {
ch.deleteExchange('test.cb.exchange', {}, doneCallback(done));
}, done));
}, done));
});
channel_test('fail on check non-queue', function(ch, done) {
var both = twice(done);
ch.on('error', failCallback(both.first));
ch.checkQueue('test.cb.nothere', failCallback(both.second));
});
channel_test('fail on check non-exchange', function(ch, done) {
var both = twice(done);
ch.on('error', failCallback(both.first));
ch.checkExchange('test.cb.nothere', failCallback(both.second));
});
});
suite('bindings', function() {
channel_test('bind queue', function(ch, done) {
ch.assertQueue('test.cb.bindq', {}, kCallback(function(q) {
ch.assertExchange(
'test.cb.bindex', 'fanout', {}, kCallback(function(ex) {
ch.bindQueue(q.queue, ex.exchange, '', {},
doneCallback(done));
}, done));
}, done));
});
channel_test('bind exchange', function(ch, done) {
ch.assertExchange(
'test.cb.bindex1', 'fanout', {}, kCallback(function(ex1) {
ch.assertExchange(
'test.cb.bindex2', 'fanout', {}, kCallback(function(ex2) {
ch.bindExchange(ex1.exchange,
ex2.exchange, '', {},
doneCallback(done));
}, done));
}, done));
});
});
suite('sending messages', function() {
channel_test('send to queue and consume noAck', function(ch, done) {
var msg = randomString();
ch.assertQueue('', {exclusive: true}, function(e, q) {
if (e !== null) return done(e);
ch.consume(q.queue, function(m) {
if (m.content.toString() == msg) done();
else done(new Error("message content doesn't match:" +
msg + " =/= " + m.content.toString()));
}, {noAck: true, exclusive: true});
ch.sendToQueue(q.queue, Buffer.from(msg));
});
});
channel_test('send to queue and consume ack', function(ch, done) {
var msg = randomString();
ch.assertQueue('', {exclusive: true}, function(e, q) {
if (e !== null) return done(e);
ch.consume(q.queue, function(m) {
if (m.content.toString() == msg) {
ch.ack(m);
done();
}
else done(new Error("message content doesn't match:" +
msg + " =/= " + m.content.toString()));
}, {noAck: false, exclusive: true});
ch.sendToQueue(q.queue, Buffer.from(msg));
});
});
channel_test('send to and get from queue', function(ch, done) {
ch.assertQueue('', {exclusive: true}, function(e, q) {
if (e != null) return done(e);
var msg = randomString();
ch.sendToQueue(q.queue, Buffer.from(msg));
waitForMessages(ch, q.queue, function(e, _) {
if (e != null) return done(e);
ch.get(q.queue, {noAck: true}, function(e, m) {
if (e != null)
return done(e);
else if (!m)
return done(new Error('Empty (false) not expected'));
else if (m.content.toString() == msg)
return done();
else
return done(
new Error('Messages do not match: ' +
msg + ' =/= ' + m.content.toString()));
});
});
});
});
var channelOptions = {};
channel_test('find high watermark', function(ch, done) {
var msg = randomString();
var baseline = 0;
ch.assertQueue('', {exclusive: true}, function(e, q) {
if (e !== null) return done(e);
while (ch.sendToQueue(q.queue, Buffer.from(msg))) {
baseline++;
};
channelOptions.highWaterMark = baseline * 2;
done();
})
});
channel_test('set high watermark', channelOptions, function(ch, done) {
var msg = randomString();
ch.assertQueue('', {exclusive: true}, function(e, q) {
if (e !== null) return done(e);
var ok;
for (var i = 0; i < channelOptions.highWaterMark; i++) {
ok = ch.sendToQueue(q.queue, Buffer.from(msg));
assert.equal(ok, true);
}
done();
});
});
});
suite('ConfirmChannel', function() {
confirm_channel_test('Receive confirmation', function(ch, done) {
// An unroutable message, on the basis that you're not allowed a
// queue with an empty name, and you can't make bindings to the
// default exchange. Tricky eh?
ch.publish('', '', Buffer.from('foo'), {}, done);
});
confirm_channel_test('Wait for confirms', function(ch, done) {
for (var i=0; i < 1000; i++) {
ch.publish('', '', Buffer.from('foo'), {});
}
ch.waitForConfirms(done);
});
var channelOptions = {};
confirm_channel_test('find high watermark', function(ch, done) {
var msg = randomString();
var baseline = 0;
ch.assertQueue('', {exclusive: true}, function(e, q) {
if (e !== null) return done(e);
while (ch.sendToQueue(q.queue, Buffer.from(msg))) {
baseline++;
};
channelOptions.highWaterMark = baseline * 2;
done();
})
});
confirm_channel_test('set high watermark', channelOptions, function(ch, done) {
var msg = randomString();
ch.assertQueue('', {exclusive: true}, function(e, q) {
if (e !== null) return done(e);
var ok;
for (var i = 0; i < channelOptions.highWaterMark; i++) {
ok = ch.sendToQueue(q.queue, Buffer.from(msg));
assert.equal(ok, true);
}
done();
});
});
});
suite("Error handling", function() {
/*
I don't like having to do this, but there appears to be something
broken about domains in Node.JS v0.8 and mocha. Apparently it has to
do with how mocha and domains hook into error propogation:
https://github.com/visionmedia/mocha/issues/513 (summary: domains in
Node.JS v0.8 don't prevent uncaughtException from firing, and that's
what mocha uses to detect .. an uncaught exception).
Using domains with amqplib *does* work in practice in Node.JS v0.8:
that is, it's possible to throw an exception in a callback and deal
with it in the active domain, and thereby avoid it crashing the
program.
*/
if (util.versionGreaterThan(process.versions.node, '0.8')) {
test('Throw error in connection open callback', function(done) {
var dom = domain.createDomain();
dom.on('error', failCallback(done));
connect(dom.bind(function(err, conn) {
throw new Error('Spurious connection open callback error');
}));
});
}
// TODO: refactor {error_test, channel_test}
function error_test(name, fun) {
test(name, function(done) {
var dom = domain.createDomain();
dom.run(function() {
connect(kCallback(function(c) {
// Seems like there were some unironed wrinkles in 0.8's
// implementation of domains; explicitly adding the connection
// to the domain makes sure any exception thrown in the course
// of processing frames is handled by the domain. For other
// versions of Node.JS, this ends up being belt-and-braces.
dom.add(c);
c.createChannel(kCallback(function(ch) {
fun(ch, done, dom);
}, done));
}, done));
});
});
}
error_test('Channel open callback throws an error', function(ch, done, dom) {
dom.on('error', failCallback(done));
throw new Error('Error in open callback');
});
error_test('RPC callback throws error', function(ch, done, dom) {
dom.on('error', failCallback(done));
ch.prefetch(0, false, function(err, ok) {
throw new Error('Spurious callback error');
});
});
error_test('Get callback throws error', function(ch, done, dom) {
dom.on('error', failCallback(done));
ch.assertQueue('test.cb.get-with-error', {}, function(err, ok) {
ch.get('test.cb.get-with-error', {noAck: true}, function() {
throw new Error('Spurious callback error');
});
});
});
error_test('Consume callback throws error', function(ch, done, dom) {
dom.on('error', failCallback(done));
ch.assertQueue('test.cb.consume-with-error', {}, function(err, ok) {
ch.consume('test.cb.consume-with-error', ignore, {noAck: true}, function() {
throw new Error('Spurious callback error');
});
});
});
error_test('Get from non-queue invokes error k', function(ch, done, dom) {
var both = twice(failCallback(done));
dom.on('error', both.first);
ch.get('', {}, both.second);
});
error_test('Consume from non-queue invokes error k', function(ch, done, dom) {
var both = twice(failCallback(done));
dom.on('error', both.first);
ch.consume('', both.second);
});
});

621
node_modules/amqplib/test/channel.js generated vendored Normal file
View File

@@ -0,0 +1,621 @@
// Test the channel machinery
'use strict';
var assert = require('assert');
var promisify = require('util').promisify;
var Channel = require('../lib/channel').Channel;
var Connection = require('../lib/connection').Connection;
var util = require('./util');
var succeed = util.succeed, fail = util.fail, latch = util.latch;
var completes = util.completes;
var defs = require('../lib/defs');
var conn_handshake = require('./connection').connection_handshake;
var OPEN_OPTS = require('./connection').OPEN_OPTS;
var LOG_ERRORS = process.env.LOG_ERRORS;
function baseChannelTest(client, server) {
return function(done) {
var bothDone = latch(2, done);
var pair = util.socketPair();
var c = new Connection(pair.client);
if (LOG_ERRORS) c.on('error', console.warn);
c.open(OPEN_OPTS, function(err, ok) {
if (err === null) client(c, bothDone);
else fail(bothDone);
});
pair.server.read(8); // discard the protocol header
var s = util.runServer(pair.server, function(send, wait) {
conn_handshake(send, wait)
.then(function() {
server(send, wait, bothDone);
}, fail(bothDone));
});
};
}
function channelTest(client, server) {
return baseChannelTest(
function(conn, done) {
var ch = new Channel(conn);
if (LOG_ERRORS) ch.on('error', console.warn);
client(ch, done, conn);
},
function(send, wait, done) {
channel_handshake(send, wait)
.then(function(ch) {
return server(send, wait, done, ch);
}).then(null, fail(done)); // so you can return a promise to let
// errors bubble out
}
);
};
function channel_handshake(send, wait) {
return wait(defs.ChannelOpen)()
.then(function(open) {
assert.notEqual(0, open.channel);
send(defs.ChannelOpenOk, {channelId: Buffer.from('')}, open.channel);
return open.channel;
});
}
// fields for deliver and publish and get-ok
var DELIVER_FIELDS = {
consumerTag: 'fake',
deliveryTag: 1,
redelivered: false,
exchange: 'foo',
routingKey: 'bar',
replyCode: defs.constants.NO_ROUTE,
replyText: 'derp',
};
function open(ch) {
ch.allocate();
return promisify(function(cb) {
ch._rpc(defs.ChannelOpen, {outOfBand: ''}, defs.ChannelOpenOk, cb);
})();
}
suite("channel open and close", function() {
test("open", channelTest(
function(ch, done) {
open(ch).then(succeed(done), fail(done));
},
function(send, wait, done) {
done();
}));
test("bad server", baseChannelTest(
function(c, done) {
var ch = new Channel(c);
open(ch).then(fail(done), succeed(done));
},
function(send, wait, done) {
return wait(defs.ChannelOpen)()
.then(function(open) {
send(defs.ChannelCloseOk, {}, open.channel);
}).then(succeed(done), fail(done));
}));
test("open, close", channelTest(
function(ch, done) {
open(ch)
.then(function() {
return new Promise(function(resolve) {
ch.closeBecause("Bye", defs.constants.REPLY_SUCCESS, resolve);
});
})
.then(succeed(done), fail(done));
},
function(send, wait, done, ch) {
return wait(defs.ChannelClose)()
.then(function(close) {
send(defs.ChannelCloseOk, {}, ch);
}).then(succeed(done), fail(done));
}));
test("server close", channelTest(
function(ch, done) {
ch.on('error', function(error) {
assert.strictEqual(504, error.code);
assert.strictEqual(0, error.classId);
assert.strictEqual(0, error.methodId);
succeed(done)();
});
open(ch);
},
function(send, wait, done, ch) {
send(defs.ChannelClose, {
replyText: 'Forced close',
replyCode: defs.constants.CHANNEL_ERROR,
classId: 0, methodId: 0
}, ch);
wait(defs.ChannelCloseOk)()
.then(succeed(done), fail(done));
}));
test("overlapping channel/server close", channelTest(
function(ch, done, conn) {
var both = latch(2, done);
conn.on('error', succeed(both));
ch.on('close', succeed(both));
open(ch).then(function() {
ch.closeBecause("Bye", defs.constants.REPLY_SUCCESS);
}, fail(both));
},
function(send, wait, done, ch) {
wait(defs.ChannelClose)()
.then(function() {
send(defs.ConnectionClose, {
replyText: 'Got there first',
replyCode: defs.constants.INTERNAL_ERROR,
classId: 0, methodId: 0
}, 0);
})
.then(wait(defs.ConnectionCloseOk))
.then(succeed(done), fail(done));
}));
test("double close", channelTest(
function(ch, done) {
open(ch).then(function() {
ch.closeBecause("First close", defs.constants.REPLY_SUCCESS);
// NB no synchronisation, we do this straight away
assert.throws(function() {
ch.closeBecause("Second close", defs.constants.REPLY_SUCCESS);
});
}).then(succeed(done), fail(done));
},
function(send, wait, done, ch) {
wait(defs.ChannelClose)()
.then(function() {
send(defs.ChannelCloseOk, {
}, ch);
})
.then(succeed(done), fail(done));
}));
}); //suite
suite("channel machinery", function() {
test("RPC", channelTest(
function(ch, done) {
var rpcLatch = latch(3, done);
open(ch).then(function() {
function wheeboom(err, f) {
if (err !== null) rpcLatch(err);
else rpcLatch();
}
var fields = {
prefetchCount: 10,
prefetchSize: 0,
global: false
};
ch._rpc(defs.BasicQos, fields, defs.BasicQosOk, wheeboom);
ch._rpc(defs.BasicQos, fields, defs.BasicQosOk, wheeboom);
ch._rpc(defs.BasicQos, fields, defs.BasicQosOk, wheeboom);
}).then(null, fail(rpcLatch));
},
function(send, wait, done, ch) {
function sendOk(f) {
send(defs.BasicQosOk, {}, ch);
}
return wait(defs.BasicQos)()
.then(sendOk)
.then(wait(defs.BasicQos))
.then(sendOk)
.then(wait(defs.BasicQos))
.then(sendOk)
.then(succeed(done), fail(done));
}));
test("Bad RPC", channelTest(
function(ch, done) {
// We want to see the RPC rejected and the channel closed (with an
// error)
var errLatch = latch(2, done);
ch.on('error', function(error) {
assert.strictEqual(505, error.code);
assert.strictEqual(60, error.classId);
assert.strictEqual(72, error.methodId);
succeed(errLatch)();
});
open(ch)
.then(function() {
ch._rpc(defs.BasicRecover, {requeue: true}, defs.BasicRecoverOk,
function(err) {
if (err !== null) errLatch();
else errLatch(new Error('Expected RPC failure'));
});
}, fail(errLatch));
},
function(send, wait, done, ch) {
return wait()()
.then(function() {
send(defs.BasicGetEmpty, {clusterId: ''}, ch);
}) // oh wait! that was wrong! expect a channel close
.then(wait(defs.ChannelClose))
.then(function() {
send(defs.ChannelCloseOk, {}, ch);
}).then(succeed(done), fail(done));
}));
test("RPC on closed channel", channelTest(
function(ch, done) {
open(ch);
var close = new Promise(function(resolve) {
ch.on('error', function(error) {
assert.strictEqual(504, error.code);
assert.strictEqual(0, error.classId);
assert.strictEqual(0, error.methodId);
resolve();
});
});
function failureCb(resolve, reject) {
return function(err) {
if (err !== null) resolve();
else reject();
}
}
var fail1 = new Promise(function(resolve, reject) {
return ch._rpc(defs.BasicRecover, {requeue:true}, defs.BasicRecoverOk,
failureCb(resolve, reject));
});
var fail2 = new Promise(function(resolve, reject) {
return ch._rpc(defs.BasicRecover, {requeue:true}, defs.BasicRecoverOk,
failureCb(resolve, reject));
});
Promise.all([close, fail1, fail2])
.then(succeed(done))
.catch(fail(done));
},
function(send, wait, done, ch) {
wait(defs.BasicRecover)()
.then(function() {
send(defs.ChannelClose, {
replyText: 'Nuh-uh!',
replyCode: defs.constants.CHANNEL_ERROR,
methodId: 0, classId: 0
}, ch);
return wait(defs.ChannelCloseOk);
})
.then(succeed(done))
.catch(fail(done));
}));
test("publish all < single chunk threshold", channelTest(
function(ch, done) {
open(ch)
.then(function() {
ch.sendMessage({
exchange: 'foo', routingKey: 'bar',
mandatory: false, immediate: false, ticket: 0
}, {}, Buffer.from('foobar'));
})
.then(succeed(done), fail(done));
},
function(send, wait, done, ch) {
wait(defs.BasicPublish)()
.then(wait(defs.BasicProperties))
.then(wait(undefined)) // content frame
.then(function(f) {
assert.equal('foobar', f.content.toString());
}).then(succeed(done), fail(done));
}));
test("publish content > single chunk threshold", channelTest(
function(ch, done) {
open(ch);
completes(function() {
ch.sendMessage({
exchange: 'foo', routingKey: 'bar',
mandatory: false, immediate: false, ticket: 0
}, {}, Buffer.alloc(3000));
}, done);
},
function(send, wait, done, ch) {
wait(defs.BasicPublish)()
.then(wait(defs.BasicProperties))
.then(wait(undefined)) // content frame
.then(function(f) {
assert.equal(3000, f.content.length);
}).then(succeed(done), fail(done));
}));
test("publish method & headers > threshold", channelTest(
function(ch, done) {
open(ch);
completes(function() {
ch.sendMessage({
exchange: 'foo', routingKey: 'bar',
mandatory: false, immediate: false, ticket: 0
}, {
headers: {foo: Buffer.alloc(3000)}
}, Buffer.from('foobar'));
}, done);
},
function(send, wait, done, ch) {
wait(defs.BasicPublish)()
.then(wait(defs.BasicProperties))
.then(wait(undefined)) // content frame
.then(function(f) {
assert.equal('foobar', f.content.toString());
}).then(succeed(done), fail(done));
}));
test("publish zero-length message", channelTest(
function(ch, done) {
open(ch);
completes(function() {
ch.sendMessage({
exchange: 'foo', routingKey: 'bar',
mandatory: false, immediate: false, ticket: 0
}, {}, Buffer.alloc(0));
ch.sendMessage({
exchange: 'foo', routingKey: 'bar',
mandatory: false, immediate: false, ticket: 0
}, {}, Buffer.alloc(0));
}, done);
},
function(send, wait, done, ch) {
wait(defs.BasicPublish)()
.then(wait(defs.BasicProperties))
// no content frame for a zero-length message
.then(wait(defs.BasicPublish))
.then(succeed(done), fail(done));
}));
test("delivery", channelTest(
function(ch, done) {
open(ch);
ch.on('delivery', function(m) {
completes(function() {
assert.equal('barfoo', m.content.toString());
}, done);
});
},
function(send, wait, done, ch) {
completes(function() {
send(defs.BasicDeliver, DELIVER_FIELDS, ch, Buffer.from('barfoo'));
}, done);
}));
test("zero byte msg", channelTest(
function(ch, done) {
open(ch);
ch.on('delivery', function(m) {
completes(function() {
assert.deepEqual(Buffer.alloc(0), m.content);
}, done);
});
},
function(send, wait, done, ch) {
completes(function() {
send(defs.BasicDeliver, DELIVER_FIELDS, ch, Buffer.from(''));
}, done);
}));
test("bad delivery", channelTest(
function(ch, done) {
var errorAndClose = latch(2, done);
ch.on('error', function(error) {
assert.strictEqual(505, error.code);
assert.strictEqual(60, error.classId);
assert.strictEqual(60, error.methodId);
succeed(errorAndClose)();
});
ch.on('close', succeed(errorAndClose));
open(ch);
},
function(send, wait, done, ch) {
send(defs.BasicDeliver, DELIVER_FIELDS, ch);
// now send another deliver without having sent the content
send(defs.BasicDeliver, DELIVER_FIELDS, ch);
return wait(defs.ChannelClose)()
.then(function() {
send(defs.ChannelCloseOk, {}, ch);
}).then(succeed(done), fail(done));
}));
test("bad content send", channelTest(
function(ch, done) {
completes(function() {
open(ch);
assert.throws(function() {
ch.sendMessage({routingKey: 'foo',
exchange: 'amq.direct'},
{}, null);
});
}, done);
},
function(send, wait, done, ch) {
done();
}));
test("bad properties send", channelTest(
function(ch, done) {
completes(function() {
open(ch);
assert.throws(function() {
ch.sendMessage({routingKey: 'foo',
exchange: 'amq.direct'},
{contentEncoding: 7},
Buffer.from('foobar'));
});
}, done);
},
function(send, wait, done, ch) {
done();
}));
test("bad consumer", channelTest(
function(ch, done) {
var errorAndClose = latch(2, done);
ch.on('delivery', function() {
throw new Error("I am a bad consumer");
});
ch.on('error', function(error) {
assert.strictEqual(541, error.code);
assert.strictEqual(undefined, error.classId);
assert.strictEqual(undefined, error.methodId);
succeed(errorAndClose)();
});
ch.on('close', succeed(errorAndClose));
open(ch);
},
function(send, wait, done, ch) {
send(defs.BasicDeliver, DELIVER_FIELDS, ch, Buffer.from('barfoo'));
return wait(defs.ChannelClose)()
.then(function() {
send(defs.ChannelCloseOk, {}, ch);
}).then(succeed(done), fail(done));
}));
test("bad send in consumer", channelTest(
function(ch, done) {
var errorAndClose = latch(2, done);
ch.on('close', succeed(errorAndClose));
ch.on('error', function(error) {
assert.strictEqual(541, error.code);
assert.strictEqual(undefined, error.classId);
assert.strictEqual(undefined, error.methodId);
succeed(errorAndClose)();
});
ch.on('delivery', function() {
ch.sendMessage({routingKey: 'foo',
exchange: 'amq.direct'},
{}, null); // can't send null
});
open(ch);
},
function(send, wait, done, ch) {
completes(function() {
send(defs.BasicDeliver, DELIVER_FIELDS, ch,
Buffer.from('barfoo'));
}, done);
return wait(defs.ChannelClose)()
.then(function() {
send(defs.ChannelCloseOk, {}, ch);
}).then(succeed(done), fail(done));
}));
test("return", channelTest(
function(ch, done) {
ch.on('return', function(m) {
completes(function() {
assert.equal('barfoo', m.content.toString());
}, done);
});
open(ch);
},
function(send, wait, done, ch) {
completes(function() {
send(defs.BasicReturn, DELIVER_FIELDS, ch, Buffer.from('barfoo'));
}, done);
}));
test("cancel", channelTest(
function(ch, done) {
ch.on('cancel', function(f) {
completes(function() {
assert.equal('product of society', f.consumerTag);
}, done);
});
open(ch);
},
function(send, wait, done, ch) {
completes(function() {
send(defs.BasicCancel, {
consumerTag: 'product of society',
nowait: false
}, ch);
}, done);
}));
function confirmTest(variety, Method) {
return test('confirm ' + variety, channelTest(
function(ch, done) {
ch.on(variety, function(f) {
completes(function() {
assert.equal(1, f.deliveryTag);
}, done);
});
open(ch);
},
function(send, wait, done, ch) {
completes(function() {
send(Method, {
deliveryTag: 1,
multiple: false
}, ch);
}, done);
}));
}
confirmTest("ack", defs.BasicAck);
confirmTest("nack", defs.BasicNack);
test("out-of-order acks", channelTest(
function(ch, done) {
var allConfirms = latch(3, function() {
completes(function() {
assert.equal(0, ch.unconfirmed.length);
assert.equal(4, ch.lwm);
}, done);
});
ch.pushConfirmCallback(allConfirms);
ch.pushConfirmCallback(allConfirms);
ch.pushConfirmCallback(allConfirms);
open(ch);
},
function(send, wait, done, ch) {
completes(function() {
send(defs.BasicAck, {deliveryTag: 2, multiple: false}, ch);
send(defs.BasicAck, {deliveryTag: 3, multiple: false}, ch);
send(defs.BasicAck, {deliveryTag: 1, multiple: false}, ch);
}, done);
}));
test("not all out-of-order acks", channelTest(
function(ch, done) {
var allConfirms = latch(2, function() {
completes(function() {
assert.equal(1, ch.unconfirmed.length);
assert.equal(3, ch.lwm);
}, done);
});
ch.pushConfirmCallback(allConfirms); // tag = 1
ch.pushConfirmCallback(allConfirms); // tag = 2
ch.pushConfirmCallback(function() {
done(new Error('Confirm callback should not be called'));
});
open(ch);
},
function(send, wait, done, ch) {
completes(function() {
send(defs.BasicAck, {deliveryTag: 2, multiple: false}, ch);
send(defs.BasicAck, {deliveryTag: 1, multiple: false}, ch);
}, done);
}));
});

606
node_modules/amqplib/test/channel_api.js generated vendored Normal file
View File

@@ -0,0 +1,606 @@
'use strict';
var assert = require('assert');
var api = require('../channel_api');
var util = require('./util');
var succeed = util.succeed, fail = util.fail;
var schedule = util.schedule;
var randomString = util.randomString;
var promisify = require('util').promisify;
var URL = process.env.URL || 'amqp://localhost';
function connect() {
return api.connect(URL);
}
// Expect this promise to fail, and flip the results accordingly.
function expectFail(promise) {
return new Promise(function(resolve, reject) {
return promise.then(reject).catch(resolve);
});
}
// I'll rely on operations being rejected, rather than the channel
// close error, to detect failure.
function ignore () {}
function ignoreErrors(c) {
c.on('error', ignore); return c;
}
function logErrors(c) {
c.on('error', console.warn); return c;
}
// Run a test with `name`, given a function that takes an open
// channel, and returns a promise that is resolved on test success or
// rejected on test failure.
function channel_test(chmethod, name, chfun) {
test(name, function(done) {
connect(URL).then(logErrors).then(function(c) {
c[chmethod]().then(ignoreErrors).then(chfun)
.then(succeed(done), fail(done))
// close the connection regardless of what happens with the test
.finally(function() {c.close();});
});
});
}
var chtest = channel_test.bind(null, 'createChannel');
suite("connect", function() {
test("at all", function(done) {
connect(URL).then(function(c) {
return c.close()
;}).then(succeed(done), fail(done));
});
chtest("create channel", ignore); // i.e., just don't bork
});
suite("updateSecret", function() {
test("updateSecret", function(done) {
connect().then(function(c) {
c.updateSecret(Buffer.from("new secret"), "no reason")
.then(succeed(done), fail(done))
.finally(function() { c.close(); });
});
});
});
var QUEUE_OPTS = {durable: false};
var EX_OPTS = {durable: false};
suite("assert, check, delete", function() {
chtest("assert and check queue", function(ch) {
return ch.assertQueue('test.check-queue', QUEUE_OPTS)
.then(function(qok) {
return ch.checkQueue('test.check-queue');
});
});
chtest("assert and check exchange", function(ch) {
return ch.assertExchange('test.check-exchange', 'direct', EX_OPTS)
.then(function(eok) {
assert.equal('test.check-exchange', eok.exchange);
return ch.checkExchange('test.check-exchange');
});
});
chtest("fail on reasserting queue with different options",
function(ch) {
var q = 'test.reassert-queue';
return ch.assertQueue(
q, {durable: false, autoDelete: true})
.then(function() {
return expectFail(
ch.assertQueue(q, {durable: false,
autoDelete: false}));
});
});
chtest("fail on checking a queue that's not there", function(ch) {
return expectFail(ch.checkQueue('test.random-' + randomString()));
});
chtest("fail on checking an exchange that's not there", function(ch) {
return expectFail(ch.checkExchange('test.random-' + randomString()));
});
chtest("fail on reasserting exchange with different type",
function(ch) {
var ex = 'test.reassert-ex';
return ch.assertExchange(ex, 'fanout', EX_OPTS)
.then(function() {
return expectFail(
ch.assertExchange(ex, 'direct', EX_OPTS));
});
});
chtest("channel break on publishing to non-exchange", function(ch) {
return new Promise(function(resolve) {
ch.on('error', resolve);
ch.publish(randomString(), '', Buffer.from('foobar'));
});
});
chtest("delete queue", function(ch) {
var q = 'test.delete-queue';
return Promise.all([
ch.assertQueue(q, QUEUE_OPTS),
ch.checkQueue(q)])
.then(function() {
return ch.deleteQueue(q);})
.then(function() {
return expectFail(ch.checkQueue(q));});
});
chtest("delete exchange", function(ch) {
var ex = 'test.delete-exchange';
return Promise.all([
ch.assertExchange(ex, 'fanout', EX_OPTS),
ch.checkExchange(ex)])
.then(function() {
return ch.deleteExchange(ex);})
.then(function() {
return expectFail(ch.checkExchange(ex));});
});
});
// Wait for the queue to meet the condition; useful for waiting for
// messages to arrive, for example.
function waitForQueue(q, condition) {
return connect(URL).then(function(c) {
return c.createChannel()
.then(function(ch) {
return ch.checkQueue(q).then(function(qok) {
function check() {
return ch.checkQueue(q).then(function(qok) {
if (condition(qok)) {
c.close();
return qok;
}
else schedule(check);
});
}
return check();
});
});
});
}
// Return a promise that resolves when the queue has at least `num`
// messages. If num is not supplied its assumed to be 1.
function waitForMessages(q, num) {
var min = (num === undefined) ? 1 : num;
return waitForQueue(q, function(qok) {
return qok.messageCount >= min;
});
}
suite("sendMessage", function() {
// publish different size messages
chtest("send to queue and get from queue", function(ch) {
var q = 'test.send-to-q';
var msg = randomString();
return Promise.all([ch.assertQueue(q, QUEUE_OPTS), ch.purgeQueue(q)])
.then(function() {
ch.sendToQueue(q, Buffer.from(msg));
return waitForMessages(q);
})
.then(function() {
return ch.get(q, {noAck: true});
})
.then(function(m) {
assert(m);
assert.equal(msg, m.content.toString());
});
});
chtest("send (and get) zero content to queue", function(ch) {
var q = 'test.send-to-q';
var msg = Buffer.alloc(0);
return Promise.all([
ch.assertQueue(q, QUEUE_OPTS),
ch.purgeQueue(q)])
.then(function() {
ch.sendToQueue(q, msg);
return waitForMessages(q);})
.then(function() {
return ch.get(q, {noAck: true});})
.then(function(m) {
assert(m);
assert.deepEqual(msg, m.content);
});
});
});
suite("binding, consuming", function() {
// bind, publish, get
chtest("route message", function(ch) {
var ex = 'test.route-message';
var q = 'test.route-message-q';
var msg = randomString();
return Promise.all([
ch.assertExchange(ex, 'fanout', EX_OPTS),
ch.assertQueue(q, QUEUE_OPTS),
ch.purgeQueue(q),
ch.bindQueue(q, ex, '', {})])
.then(function() {
ch.publish(ex, '', Buffer.from(msg));
return waitForMessages(q);})
.then(function() {
return ch.get(q, {noAck: true});})
.then(function(m) {
assert(m);
assert.equal(msg, m.content.toString());
});
});
// send to queue, purge, get-empty
chtest("purge queue", function(ch) {
var q = 'test.purge-queue';
return ch.assertQueue(q, {durable: false})
.then(function() {
ch.sendToQueue(q, Buffer.from('foobar'));
return waitForMessages(q);})
.then(function() {
ch.purgeQueue(q);
return ch.get(q, {noAck: true});})
.then(function(m) {
assert(!m); // get-empty
});
});
// bind again, unbind, publish, get-empty
chtest("unbind queue", function(ch) {
var ex = 'test.unbind-queue-ex';
var q = 'test.unbind-queue';
var viabinding = randomString();
var direct = randomString();
return Promise.all([
ch.assertExchange(ex, 'fanout', EX_OPTS),
ch.assertQueue(q, QUEUE_OPTS),
ch.purgeQueue(q),
ch.bindQueue(q, ex, '', {})])
.then(function() {
ch.publish(ex, '', Buffer.from('foobar'));
return waitForMessages(q);})
.then(function() { // message got through!
return ch.get(q, {noAck:true})
.then(function(m) {assert(m);});})
.then(function() {
return ch.unbindQueue(q, ex, '', {});})
.then(function() {
// via the no-longer-existing binding
ch.publish(ex, '', Buffer.from(viabinding));
// direct to the queue
ch.sendToQueue(q, Buffer.from(direct));
return waitForMessages(q);})
.then(function() {return ch.get(q)})
.then(function(m) {
// the direct to queue message got through, the via-binding
// message (sent first) did not
assert.equal(direct, m.content.toString());
});
});
// To some extent this is now just testing semantics of the server,
// but we can at least try out a few settings, and consume.
chtest("consume via exchange-exchange binding", function(ch) {
var ex1 = 'test.ex-ex-binding1', ex2 = 'test.ex-ex-binding2';
var q = 'test.ex-ex-binding-q';
var rk = 'test.routing.key', msg = randomString();
return Promise.all([
ch.assertExchange(ex1, 'direct', EX_OPTS),
ch.assertExchange(ex2, 'fanout',
{durable: false, internal: true}),
ch.assertQueue(q, QUEUE_OPTS),
ch.purgeQueue(q),
ch.bindExchange(ex2, ex1, rk, {}),
ch.bindQueue(q, ex2, '', {})])
.then(function() {
return new Promise(function(resolve, reject) {
function delivery(m) {
if (m.content.toString() === msg) resolve();
else reject(new Error("Wrong message"));
}
ch.consume(q, delivery, {noAck: true})
.then(function() {
ch.publish(ex1, rk, Buffer.from(msg));
});
});
});
});
// bind again, unbind, publish, get-empty
chtest("unbind exchange", function(ch) {
var source = 'test.unbind-ex-source';
var dest = 'test.unbind-ex-dest';
var q = 'test.unbind-ex-queue';
var viabinding = randomString();
var direct = randomString();
return Promise.all([
ch.assertExchange(source, 'fanout', EX_OPTS),
ch.assertExchange(dest, 'fanout', EX_OPTS),
ch.assertQueue(q, QUEUE_OPTS),
ch.purgeQueue(q),
ch.bindExchange(dest, source, '', {}),
ch.bindQueue(q, dest, '', {})])
.then(function() {
ch.publish(source, '', Buffer.from('foobar'));
return waitForMessages(q);})
.then(function() { // message got through!
return ch.get(q, {noAck:true})
.then(function(m) {assert(m);});})
.then(function() {
return ch.unbindExchange(dest, source, '', {});})
.then(function() {
// via the no-longer-existing binding
ch.publish(source, '', Buffer.from(viabinding));
// direct to the queue
ch.sendToQueue(q, Buffer.from(direct));
return waitForMessages(q);})
.then(function() {return ch.get(q)})
.then(function(m) {
// the direct to queue message got through, the via-binding
// message (sent first) did not
assert.equal(direct, m.content.toString());
});
});
// This is a bit convoluted. Sorry.
chtest("cancel consumer", function(ch) {
var q = 'test.consumer-cancel';
var ctag;
var recv1 = new Promise(function (resolve, reject) {
Promise.all([
ch.assertQueue(q, QUEUE_OPTS),
ch.purgeQueue(q),
// My callback is 'resolve the promise in `arrived`'
ch.consume(q, resolve, {noAck:true})
.then(function(ok) {
ctag = ok.consumerTag;
ch.sendToQueue(q, Buffer.from('foo'));
})]);
});
// A message should arrive because of the consume
return recv1.then(function() {
var recv2 = Promise.all([
ch.cancel(ctag).then(function() {
return ch.sendToQueue(q, Buffer.from('bar'));
}),
// but check a message did arrive in the queue
waitForMessages(q)])
.then(function() {
return ch.get(q, {noAck:true});
})
.then(function(m) {
// I'm going to reject it, because I flip succeed/fail
// just below
if (m.content.toString() === 'bar') {
throw new Error();
}
});
return expectFail(recv2);
});
});
chtest("cancelled consumer", function(ch) {
var q = 'test.cancelled-consumer';
return new Promise(function(resolve, reject) {
return Promise.all([
ch.assertQueue(q),
ch.purgeQueue(q),
ch.consume(q, function(msg) {
if (msg === null) resolve();
else reject(new Error('Message not expected'));
})])
.then(function() {
return ch.deleteQueue(q);
});
});
});
// ack, by default, removes a single message from the queue
chtest("ack", function(ch) {
var q = 'test.ack';
var msg1 = randomString(), msg2 = randomString();
return Promise.all([
ch.assertQueue(q, QUEUE_OPTS),
ch.purgeQueue(q)])
.then(function() {
ch.sendToQueue(q, Buffer.from(msg1));
ch.sendToQueue(q, Buffer.from(msg2));
return waitForMessages(q, 2);
})
.then(function() {
return ch.get(q, {noAck: false})
})
.then(function(m) {
assert.equal(msg1, m.content.toString());
ch.ack(m);
// %%% is there a race here? may depend on
// rabbitmq-sepcific semantics
return ch.get(q);
})
.then(function(m) {
assert(m);
assert.equal(msg2, m.content.toString());
});
});
// Nack, by default, puts a message back on the queue (where in the
// queue is up to the server)
chtest("nack", function(ch) {
var q = 'test.nack';
var msg1 = randomString();
return Promise.all([
ch.assertQueue(q, QUEUE_OPTS), ch.purgeQueue(q)])
.then(function() {
ch.sendToQueue(q, Buffer.from(msg1));
return waitForMessages(q);})
.then(function() {
return ch.get(q, {noAck: false})})
.then(function(m) {
assert.equal(msg1, m.content.toString());
ch.nack(m);
return waitForMessages(q);})
.then(function() {
return ch.get(q);})
.then(function(m) {
assert(m);
assert.equal(msg1, m.content.toString());
});
});
// reject is a near-synonym for nack, the latter of which is not
// available in earlier RabbitMQ (or in AMQP proper).
chtest("reject", function(ch) {
var q = 'test.reject';
var msg1 = randomString();
return Promise.all([
ch.assertQueue(q, QUEUE_OPTS), ch.purgeQueue(q)])
.then(function() {
ch.sendToQueue(q, Buffer.from(msg1));
return waitForMessages(q);})
.then(function() {
return ch.get(q, {noAck: false})})
.then(function(m) {
assert.equal(msg1, m.content.toString());
ch.reject(m);
return waitForMessages(q);})
.then(function() {
return ch.get(q);})
.then(function(m) {
assert(m);
assert.equal(msg1, m.content.toString());
});
});
chtest("prefetch", function(ch) {
var q = 'test.prefetch';
return Promise.all([
ch.assertQueue(q, QUEUE_OPTS), ch.purgeQueue(q),
ch.prefetch(1)])
.then(function() {
ch.sendToQueue(q, Buffer.from('foobar'));
ch.sendToQueue(q, Buffer.from('foobar'));
return waitForMessages(q, 2);
})
.then(function() {
return new Promise(function(resolve) {
var messageCount = 0;
function receive(msg) {
ch.ack(msg);
if (++messageCount > 1) {
resolve(messageCount);
}
}
return ch.consume(q, receive, {noAck: false})
});
})
.then(function(c) {
return assert.equal(2, c);
});
});
chtest('close', function(ch) {
// Resolving promise guarantees
// channel is closed
return ch.close();
});
});
var confirmtest = channel_test.bind(null, 'createConfirmChannel');
suite("confirms", function() {
confirmtest('message is confirmed', function(ch) {
var q = 'test.confirm-message';
return Promise.all([
ch.assertQueue(q, QUEUE_OPTS), ch.purgeQueue(q)])
.then(function() {
return ch.sendToQueue(q, Buffer.from('bleep'));
});
});
// Usually one can provoke the server into confirming more than one
// message in an ack by simply sending a few messages in quick
// succession; a bit unscientific I know. Luckily we can eavesdrop on
// the acknowledgements coming through to see if we really did get a
// multi-ack.
confirmtest('multiple confirms', function(ch) {
var q = 'test.multiple-confirms';
return Promise.all([
ch.assertQueue(q, QUEUE_OPTS), ch.purgeQueue(q)])
.then(function() {
var multipleRainbows = false;
ch.on('ack', function(a) {
if (a.multiple) multipleRainbows = true;
});
function prod(num) {
var cs = [];
function sendAndPushPromise() {
var conf = promisify(function(cb) {
return ch.sendToQueue(q, Buffer.from('bleep'), {}, cb);
})();
cs.push(conf);
}
for (var i=0; i < num; i++) sendAndPushPromise();
return Promise.all(cs).then(function() {
if (multipleRainbows) return true;
else if (num > 500) throw new Error(
"Couldn't provoke the server" +
" into multi-acking with " + num +
" messages; giving up");
else {
//console.warn("Failed with " + num + "; trying " + num * 2);
return prod(num * 2);
}
});
}
return prod(5);
});
});
confirmtest('wait for confirms', function(ch) {
for (var i=0; i < 1000; i++) {
ch.publish('', '', Buffer.from('foobar'), {});
}
return ch.waitForConfirms();
})
confirmtest('works when channel is closed', function(ch) {
for (var i=0; i < 1000; i++) {
ch.publish('', '', Buffer.from('foobar'), {});
}
return ch.close().then(function () {
return ch.waitForConfirms()
}).then(function () {
assert.strictEqual(true, false, 'Wait should have failed.')
}, function (e) {
assert.strictEqual(e.message, 'channel closed')
});
});
});

237
node_modules/amqplib/test/codec.js generated vendored Normal file
View File

@@ -0,0 +1,237 @@
'use strict';
var codec = require('../lib/codec');
var defs = require('../lib/defs');
var assert = require('assert');
var ints = require('buffer-more-ints');
var C = require('claire');
var forAll = C.forAll;
// These just test known encodings; to generate the answers I used
// RabbitMQ's binary generator module.
var testCases = [
// integers
['byte', {byte: 112}, [4,98,121,116,101,98,112]],
['byte max value', {byte: 127}, [4,98,121,116,101,98,127]],
['byte min value', {byte: -128}, [4,98,121,116,101,98,128]],
['< -128 promoted to signed short', {short: -129}, [5,115,104,111,114,116,115,255,127]],
['> 127 promoted to short', {short: 128}, [5,115,104,111,114,116,115,0,128]],
['< 2^15 still a short', {short: 0x7fff}, [5,115,104,111,114,116,115,127,255]],
['-2^15 still a short', {short: -0x8000}, [5,115,104,111,114,116,115,128,0]],
['>= 2^15 promoted to int', {int: 0x8000}, [3,105,110,116,73,0,0,128,0]],
['< -2^15 promoted to int', {int: -0x8001}, [3,105,110,116,73,255,255,127,255]],
['< 2^31 still an int', {int: 0x7fffffff}, [3,105,110,116,73,127,255,255,255]],
['>= -2^31 still an int', {int: -0x80000000}, [3,105,110,116,73,128,0,0,0]],
['>= 2^31 promoted to long', {long: 0x80000000}, [4,108,111,110,103,108,0,0,0,0,128,0,0,0]],
['< -2^31 promoted to long', {long: -0x80000001}, [4,108,111,110,103,108,255,255,255,255,127,255,255,255]],
// floating point
['float value', {double: 0.5}, [6,100,111,117,98,108,101,100,63,224,0,0,0,0,0,0]],
['negative float value', {double: -0.5}, [6,100,111,117,98,108,101,100,191,224,0,0,0,0,0,0]],
// %% test some boundaries of precision?
// string
['string', {string: "boop"}, [6,115,116,114,105,110,103,83,0,0,0,4,98,111,111,112]],
// buffer -> byte array
['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]],
// boolean, void
['true', {bool: true}, [4,98,111,111,108,116,1]],
['false', {bool: false}, [4,98,111,111,108,116,0]],
['null', {'void': null}, [4,118,111,105,100,86]],
// array, object
['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]],
['object', {object: {foo: "bar", baz: 12}},[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]],
// exotic types
['timestamp', {timestamp: {'!': 'timestamp', value: 1357212277527}},[9,116,105,109,101,115,116,97,109,112,84,0,0,1,60,0,39,219,23]],
['decimal', {decimal: {'!': 'decimal', value: {digits: 2345, places: 2}}},[7,100,101,99,105,109,97,108,68,2,0,0,9,41]],
['float', {float: {'!': 'float', value: 0.1}},[5,102,108,111,97,116,102,61,204,204,205]],
['unsignedbyte', {unsignedbyte:{'!': 'unsignedbyte', value: 255}}, [12,117,110,115,105,103,110,101,100,98,121,116,101,66,255]],
['unsignedshort', {unsignedshort:{'!': 'unsignedshort', value: 65535}}, [13,117,110,115,105,103,110,101,100,115,104,111,114,116,117,255,255]],
['unsignedint', {unsignedint:{'!': 'unsignedint', value: 4294967295}}, [11,117,110,115,105,103,110,101,100,105,110,116,105,255,255,255,255]],
];
function bufferToArray(b) {
return Array.prototype.slice.call(b);
}
suite("Implicit encodings", function() {
testCases.forEach(function(tc) {
var name = tc[0], val = tc[1], expect = tc[2];
test(name, function() {
var buffer = Buffer.alloc(1000);
var size = codec.encodeTable(buffer, val, 0);
var result = buffer.subarray(4, size);
assert.deepEqual(expect, bufferToArray(result));
});
});
});
// Whole frames
var amqp = require('./data');
function roundtrip_table(t) {
var buf = Buffer.alloc(4096);
var size = codec.encodeTable(buf, t, 0);
var decoded = codec.decodeFields(buf.subarray(4, size)); // ignore the length-prefix
try {
assert.deepEqual(removeExplicitTypes(t), decoded);
}
catch (e) { return false; }
return true;
}
function roundtrips(T) {
return forAll(T).satisfy(function(v) { return roundtrip_table({value: v}); });
}
suite("Roundtrip values", function() {
[
amqp.Octet,
amqp.ShortStr,
amqp.LongStr,
amqp.UShort,
amqp.ULong,
amqp.ULongLong,
amqp.UShort,
amqp.Short,
amqp.Long,
amqp.Bit,
amqp.Decimal,
amqp.Timestamp,
amqp.UnsignedByte,
amqp.UnsignedShort,
amqp.UnsignedInt,
amqp.Double,
amqp.Float,
amqp.FieldArray,
amqp.FieldTable
].forEach(function(T) {
test(T.toString() + ' roundtrip', roundtrips(T).asTest());
});
});
// When encoding, you can supply explicitly-typed fields like `{'!':
// int32, 50}`. Most of these do not appear in the decoded values, so
// to compare like-to-like we have to remove them from the input.
function removeExplicitTypes(input) {
switch (typeof input) {
case 'object':
if (input == null) {
return null;
}
if (Array.isArray(input)) {
var newArr = [];
for (var i = 0; i < input.length; i++) {
newArr[i] = removeExplicitTypes(input[i]);
}
return newArr;
}
if (Buffer.isBuffer(input)) {
return input;
}
switch (input['!']) {
case 'timestamp':
case 'decimal':
case 'float':
return input;
case undefined:
var newObj = {}
for (var k in input) {
newObj[k] = removeExplicitTypes(input[k]);
}
return newObj;
default:
return input.value;
}
default:
return input;
}
}
// Asserts that the decoded fields are equal to the original fields,
// or equal to a default where absent in the original. The defaults
// depend on the type of method or properties.
//
// This works slightly different for methods and properties: for
// methods, each field must have a value, so the default is
// substituted for undefined values when encoding; for properties,
// fields may be absent in the encoded value, so a default is
// substituted for missing fields when decoding. The effect is the
// same so far as these tests are concerned.
function assertEqualModuloDefaults(original, decodedFields) {
var args = defs.info(original.id).args;
for (var i=0; i < args.length; i++) {
var arg = args[i];
var originalValue = original.fields[arg.name];
var decodedValue = decodedFields[arg.name];
try {
if (originalValue === undefined) {
// longstr gets special treatment here, since the defaults are
// given as strings rather than buffers, but the decoded values
// will be buffers.
assert.deepEqual((arg.type === 'longstr') ?
Buffer.from(arg.default) : arg.default,
decodedValue);
}
else {
assert.deepEqual(removeExplicitTypes(originalValue), decodedValue);
}
}
catch (assertionErr) {
var methodOrProps = defs.info(original.id).name;
assertionErr.message += ' (frame ' + methodOrProps +
' field ' + arg.name + ')';
throw assertionErr;
}
}
// %%% TODO make sure there's no surplus fields
return true;
}
// This is handy for elsewhere
module.exports.assertEqualModuloDefaults = assertEqualModuloDefaults;
function roundtripMethod(Method) {
return forAll(Method).satisfy(function(method) {
var buf = defs.encodeMethod(method.id, 0, method.fields);
// FIXME depends on framing, ugh
var fs1 = defs.decode(method.id, buf.subarray(11, buf.length));
assertEqualModuloDefaults(method, fs1);
return true;
});
}
function roundtripProperties(Properties) {
return forAll(Properties).satisfy(function(properties) {
var buf = defs.encodeProperties(properties.id, 0, properties.size,
properties.fields);
// FIXME depends on framing, ugh
var fs1 = defs.decode(properties.id, buf.subarray(19, buf.length));
assert.equal(properties.size, ints.readUInt64BE(buf, 11));
assertEqualModuloDefaults(properties, fs1);
return true;
});
}
suite("Roundtrip methods", function() {
amqp.methods.forEach(function(Method) {
test(Method.toString() + ' roundtrip',
roundtripMethod(Method).asTest());
});
});
suite("Roundtrip properties", function() {
amqp.properties.forEach(function(Properties) {
test(Properties.toString() + ' roundtrip',
roundtripProperties(Properties).asTest());
});
});

197
node_modules/amqplib/test/connect.js generated vendored Normal file
View File

@@ -0,0 +1,197 @@
'use strict';
var connect = require('../lib/connect').connect;
var credentialsFromUrl = require('../lib/connect').credentialsFromUrl;
var defs = require('../lib/defs');
var assert = require('assert');
var util = require('./util');
var net = require('net');
var fail = util.fail, succeed = util.succeed, latch = util.latch,
kCallback = util.kCallback,
succeedIfAttributeEquals = util.succeedIfAttributeEquals;
var format = require('util').format;
var URL = process.env.URL || 'amqp://localhost';
var urlparse = require('url-parse');
suite("Credentials", function() {
function checkCreds(creds, user, pass, done) {
if (creds.mechanism != 'PLAIN') {
return done('expected mechanism PLAIN');
}
if (creds.username != user || creds.password != pass) {
return done(format("expected '%s', '%s'; got '%s', '%s'",
user, pass, creds.username, creds.password));
}
done();
}
test("no creds", function(done) {
var parts = urlparse('amqp://localhost');
var creds = credentialsFromUrl(parts);
checkCreds(creds, 'guest', 'guest', done);
});
test("usual user:pass", function(done) {
var parts = urlparse('amqp://user:pass@localhost')
var creds = credentialsFromUrl(parts);
checkCreds(creds, 'user', 'pass', done);
});
test("missing user", function(done) {
var parts = urlparse('amqps://:password@localhost');
var creds = credentialsFromUrl(parts);
checkCreds(creds, '', 'password', done);
});
test("missing password", function(done) {
var parts = urlparse('amqps://username:@localhost');
var creds = credentialsFromUrl(parts);
checkCreds(creds, 'username', '', done);
});
test("escaped colons", function(done) {
var parts = urlparse('amqp://user%3Aname:pass%3Aword@localhost')
var creds = credentialsFromUrl(parts);
checkCreds(creds, 'user:name', 'pass:word', done);
});
});
suite("Connect API", function() {
test("Connection refused", function(done) {
connect('amqp://localhost:23450', {},
kCallback(fail(done), succeed(done)));
});
// %% this ought to fail the promise, rather than throwing an error
test("bad URL", function() {
assert.throws(function() {
connect('blurble');
});
});
test("wrongly typed open option", function(done) {
var url = require('url');
var parts = url.parse(URL, true);
var q = parts.query || {};
q.frameMax = 'NOT A NUMBER';
parts.query = q;
var u = url.format(parts);
connect(u, {}, kCallback(fail(done), succeed(done)));
});
test("serverProperties", function(done) {
var url = require('url');
var parts = url.parse(URL, true);
var config = parts.query || {};
connect(config, {}, function(err, connection) {
if (err) { return done(err); }
assert.equal(connection.serverProperties.product, 'RabbitMQ');
done();
});
});
test("using custom heartbeat option", function(done) {
var url = require('url');
var parts = url.parse(URL, true);
var config = parts.query || {};
config.heartbeat = 20;
connect(config, {}, kCallback(succeedIfAttributeEquals('heartbeat', 20, done), fail(done)));
});
test("wrongly typed heartbeat option", function(done) {
var url = require('url');
var parts = url.parse(URL, true);
var config = parts.query || {};
config.heartbeat = 'NOT A NUMBER';
connect(config, {}, kCallback(fail(done), succeed(done)));
});
test("using plain credentials", function(done) {
var url = require('url');
var parts = url.parse(URL, true);
var u = 'guest', p = 'guest';
if (parts.auth) {
var auth = parts.auth.split(":");
u = auth[0], p = auth[1];
}
connect(URL, {credentials: require('../lib/credentials').plain(u, p)},
kCallback(succeed(done), fail(done)));
});
test("using amqplain credentials", function(done) {
var url = require('url');
var parts = url.parse(URL, true);
var u = 'guest', p = 'guest';
if (parts.auth) {
var auth = parts.auth.split(":");
u = auth[0], p = auth[1];
}
connect(URL, {credentials: require('../lib/credentials').amqplain(u, p)},
kCallback(succeed(done), fail(done)));
});
test("using unsupported mechanism", function(done) {
var creds = {
mechanism: 'UNSUPPORTED',
response: function() { return Buffer.from(''); }
};
connect(URL, {credentials: creds},
kCallback(fail(done), succeed(done)));
});
test("with a given connection timeout", function(done) {
var timeoutServer = net.createServer(function() {}).listen(31991);
connect('amqp://localhost:31991', {timeout: 50}, function(err, val) {
timeoutServer.close();
if (val) done(new Error('Expected connection timeout, did not'));
else done();
});
});
});
suite('Errors on connect', function() {
var server
teardown(function() {
if (server) {
server.close();
}
})
test("closes underlying connection on authentication error", function(done) {
var bothDone = latch(2, done);
server = net.createServer(function(socket) {
socket.once('data', function(protocolHeader) {
assert.deepStrictEqual(
protocolHeader,
Buffer.from("AMQP" + String.fromCharCode(0,0,9,1))
);
util.runServer(socket, function(send, wait) {
send(defs.ConnectionStart,
{versionMajor: 0,
versionMinor: 9,
serverProperties: {},
mechanisms: Buffer.from('PLAIN'),
locales: Buffer.from('en_US')});
wait(defs.ConnectionStartOk)().then(function() {
send(defs.ConnectionClose,
{replyCode: 403,
replyText: 'ACCESS_REFUSED - Login was refused using authentication mechanism PLAIN',
classId: 0,
methodId: 0});
});
});
});
// Wait for the connection to be closed after the authentication error
socket.once('end', function() {
bothDone();
});
}).listen(0);
connect('amqp://localhost:' + server.address().port, {}, function(err) {
if (!err) bothDone(new Error('Expected authentication error'));
bothDone();
});
});
});

390
node_modules/amqplib/test/connection.js generated vendored Normal file
View File

@@ -0,0 +1,390 @@
'use strict';
var assert = require('assert');
var defs = require('../lib/defs');
var Connection = require('../lib/connection').Connection;
var HEARTBEAT = require('../lib/frame').HEARTBEAT;
var HB_BUF = require('../lib/frame').HEARTBEAT_BUF;
var util = require('./util');
var succeed = util.succeed, fail = util.fail, latch = util.latch;
var completes = util.completes;
var kCallback = util.kCallback;
var LOG_ERRORS = process.env.LOG_ERRORS;
var OPEN_OPTS = {
// start-ok
'clientProperties': {},
'mechanism': 'PLAIN',
'response': Buffer.from(['', 'guest', 'guest'].join(String.fromCharCode(0))),
'locale': 'en_US',
// tune-ok
'channelMax': 0,
'frameMax': 0,
'heartbeat': 0,
// open
'virtualHost': '/',
'capabilities': '',
'insist': 0
};
module.exports.OPEN_OPTS = OPEN_OPTS;
function happy_open(send, wait) {
// kick it off
send(defs.ConnectionStart,
{versionMajor: 0,
versionMinor: 9,
serverProperties: {},
mechanisms: Buffer.from('PLAIN'),
locales: Buffer.from('en_US')});
return wait(defs.ConnectionStartOk)()
.then(function(f) {
send(defs.ConnectionTune,
{channelMax: 0,
heartbeat: 0,
frameMax: 0});
})
.then(wait(defs.ConnectionTuneOk))
.then(wait(defs.ConnectionOpen))
.then(function(f) {
send(defs.ConnectionOpenOk,
{knownHosts: ''});
});
}
module.exports.connection_handshake = happy_open;
function connectionTest(client, server) {
return function(done) {
var bothDone = latch(2, done);
var pair = util.socketPair();
var c = new Connection(pair.client);
if (LOG_ERRORS) c.on('error', console.warn);
client(c, bothDone);
// NB only not a race here because the writes are synchronous
var protocolHeader = pair.server.read(8);
assert.deepEqual(Buffer.from("AMQP" + String.fromCharCode(0,0,9,1)),
protocolHeader);
var s = util.runServer(pair.server, function(send, wait) {
server(send, wait, bothDone, pair.server);
});
};
}
suite("Connection errors", function() {
test("socket close during open", function(done) {
// RabbitMQ itself will take at least 3 seconds to close the socket
// in the event of a handshake problem. Instead of using a live
// connection, I'm just going to pretend.
var pair = util.socketPair();
var conn = new Connection(pair.client);
pair.server.on('readable', function() {
pair.server.end();
});
conn.open({}, kCallback(fail(done), succeed(done)));
});
test("bad frame during open", function(done) {
var ss = util.socketPair();
var conn = new (require('../lib/connection').Connection)(ss.client);
ss.server.on('readable', function() {
ss.server.write(Buffer.from([0, 0, 0, 0, 0, 0, 0, 0, 0, 0]));
});
conn.open({}, kCallback(fail(done), succeed(done)));
});
});
suite("Connection open", function() {
test("happy", connectionTest(
function(c, done) {
c.open(OPEN_OPTS, kCallback(succeed(done), fail(done)));
},
function(send, wait, done) {
happy_open(send, wait).then(succeed(done), fail(done));
}));
test("wrong first frame", connectionTest(
function(c, done) {
c.open(OPEN_OPTS, kCallback(fail(done), succeed(done)));
},
function(send, wait, done) {
// bad server! bad! whatever were you thinking?
completes(function() {
send(defs.ConnectionTune,
{channelMax: 0,
heartbeat: 0,
frameMax: 0});
}, done);
}));
test("unexpected socket close", connectionTest(
function(c, done) {
c.open(OPEN_OPTS, kCallback(fail(done), succeed(done)));
},
function(send, wait, done, socket) {
send(defs.ConnectionStart,
{versionMajor: 0,
versionMinor: 9,
serverProperties: {},
mechanisms: Buffer.from('PLAIN'),
locales: Buffer.from('en_US')});
return wait(defs.ConnectionStartOk)()
.then(function() {
socket.end();
})
.then(succeed(done), fail(done));
}));
});
suite("Connection running", function() {
test("wrong frame on channel 0", connectionTest(
function(c, done) {
c.on('error', succeed(done));
c.open(OPEN_OPTS);
},
function(send, wait, done) {
happy_open(send, wait)
.then(function() {
// there's actually nothing that would plausibly be sent to a
// just opened connection, so this is violating more than one
// rule. Nonetheless.
send(defs.ChannelOpenOk, {channelId: Buffer.from('')}, 0);
})
.then(wait(defs.ConnectionClose))
.then(function(close) {
send(defs.ConnectionCloseOk, {}, 0);
}).then(succeed(done), fail(done));
}));
test("unopened channel", connectionTest(
function(c, done) {
c.on('error', succeed(done));
c.open(OPEN_OPTS);
},
function(send, wait, done) {
happy_open(send, wait)
.then(function() {
// there's actually nothing that would plausibly be sent to a
// just opened connection, so this is violating more than one
// rule. Nonetheless.
send(defs.ChannelOpenOk, {channelId: Buffer.from('')}, 3);
})
.then(wait(defs.ConnectionClose))
.then(function(close) {
send(defs.ConnectionCloseOk, {}, 0);
}).then(succeed(done), fail(done));
}));
test("unexpected socket close", connectionTest(
function(c, done) {
var errorAndClosed = latch(2, done);
c.on('error', succeed(errorAndClosed));
c.on('close', succeed(errorAndClosed));
c.open(OPEN_OPTS, kCallback(function() {
c.sendHeartbeat();
}, fail(errorAndClosed)));
},
function(send, wait, done, socket) {
happy_open(send, wait)
.then(wait())
.then(function() {
socket.end();
}).then(succeed(done));
}));
test("connection.blocked", connectionTest(
function(c, done) {
c.on('blocked', succeed(done));
c.open(OPEN_OPTS);
},
function(send, wait, done, socket) {
happy_open(send, wait)
.then(function() {
send(defs.ConnectionBlocked, {reason: 'felt like it'}, 0);
})
.then(succeed(done));
}));
test("connection.unblocked", connectionTest(
function(c, done) {
c.on('unblocked', succeed(done));
c.open(OPEN_OPTS);
},
function(send, wait, done, socket) {
happy_open(send, wait)
.then(function() {
send(defs.ConnectionUnblocked, {}, 0);
})
.then(succeed(done));
}));
});
suite("Connection close", function() {
test("happy", connectionTest(
function(c, done0) {
var done = latch(2, done0);
c.on('close', done);
c.open(OPEN_OPTS, kCallback(function(_ok) {
c.close(kCallback(succeed(done), fail(done)));
}, function() {}));
},
function(send, wait, done) {
happy_open(send, wait)
.then(wait(defs.ConnectionClose))
.then(function(close) {
send(defs.ConnectionCloseOk, {});
})
.then(succeed(done), fail(done));
}));
test("interleaved close frames", connectionTest(
function(c, done0) {
var done = latch(2, done0);
c.on('close', done);
c.open(OPEN_OPTS, kCallback(function(_ok) {
c.close(kCallback(succeed(done), fail(done)));
}, done));
},
function(send, wait, done) {
happy_open(send, wait)
.then(wait(defs.ConnectionClose))
.then(function(f) {
send(defs.ConnectionClose, {
replyText: "Ha!",
replyCode: defs.constants.REPLY_SUCCESS,
methodId: 0, classId: 0
});
})
.then(wait(defs.ConnectionCloseOk))
.then(function(f) {
send(defs.ConnectionCloseOk, {});
})
.then(succeed(done), fail(done));
}));
test("server error close", connectionTest(
function(c, done0) {
var done = latch(2, done0);
c.on('close', succeed(done));
c.on('error', succeed(done));
c.open(OPEN_OPTS);
},
function(send, wait, done) {
happy_open(send, wait)
.then(function(f) {
send(defs.ConnectionClose, {
replyText: "Begone",
replyCode: defs.constants.INTERNAL_ERROR,
methodId: 0, classId: 0
});
})
.then(wait(defs.ConnectionCloseOk))
.then(succeed(done), fail(done));
}));
test("operator-intiated close", connectionTest(
function(c, done) {
c.on('close', succeed(done));
c.on('error', fail(done));
c.open(OPEN_OPTS);
},
function(send, wait, done) {
happy_open(send, wait)
.then(function(f) {
send(defs.ConnectionClose, {
replyText: "Begone",
replyCode: defs.constants.CONNECTION_FORCED,
methodId: 0, classId: 0
});
})
.then(wait(defs.ConnectionCloseOk))
.then(succeed(done), fail(done));
}));
test("double close", connectionTest(
function(c, done) {
c.open(OPEN_OPTS, kCallback(function() {
c.close();
// NB no synchronisation, we do this straight away
assert.throws(function() {
c.close();
});
done();
}, done));
},
function(send, wait, done) {
happy_open(send, wait)
.then(wait(defs.ConnectionClose))
.then(function() {
send(defs.ConnectionCloseOk, {});
})
.then(succeed(done), fail(done));
}));
});
suite("heartbeats", function() {
var heartbeat = require('../lib/heartbeat');
setup(function() {
heartbeat.UNITS_TO_MS = 20;
});
teardown(function() {
heartbeat.UNITS_TO_MS = 1000;
});
test("send heartbeat after open", connectionTest(
function(c, done) {
completes(function() {
var opts = Object.create(OPEN_OPTS);
opts.heartbeat = 1;
// Don't leave the error waiting to happen for the next test, this
// confuses mocha awfully
c.on('error', function() {});
c.open(opts);
}, done);
},
function(send, wait, done, socket) {
var timer;
happy_open(send, wait)
.then(function() {
timer = setInterval(function() {
socket.write(HB_BUF);
}, heartbeat.UNITS_TO_MS);
})
.then(wait())
.then(function(hb) {
if (hb === HEARTBEAT) done();
else done("Next frame after silence not a heartbeat");
clearInterval(timer);
});
}));
test("detect lack of heartbeats", connectionTest(
function(c, done) {
var opts = Object.create(OPEN_OPTS);
opts.heartbeat = 1;
c.on('error', succeed(done));
c.open(opts);
},
function(send, wait, done, socket) {
happy_open(send, wait)
.then(succeed(done), fail(done));
// conspicuously not sending anything ...
}));
});

269
node_modules/amqplib/test/data.js generated vendored Normal file
View File

@@ -0,0 +1,269 @@
// Property-based testing representations of various things in AMQP
'use strict';
var C = require('claire');
var forAll = C.forAll;
var arb = C.data;
var transform = C.transform;
var repeat = C.repeat;
var label = C.label;
var sequence = C.sequence;
var asGenerator = C.asGenerator;
var sized = C.sized;
var recursive = C.recursive;
var choice = C.choice;
var Undefined = C.Undefined;
// Stub these out so we can use outside tests
// if (!suite) var suite = function() {}
// if (!test) var test = function() {}
// These aren't exported in claire/index. so I could have to reproduce
// them I guess.
function choose(a, b) {
return Math.random() * (b - a) + a;
}
function chooseInt(a, b) {
return Math.floor(choose(a, b));
}
function rangeInt(name, a, b) {
return label(name,
asGenerator(function(_) { return chooseInt(a, b); }));
}
function toFloat32(i) {
var b = Buffer.alloc(4);
b.writeFloatBE(i, 0);
return b.readFloatBE(0);
}
function floatChooser(maxExp) {
return function() {
var n = Number.NaN;
while (isNaN(n)) {
var mantissa = Math.random() * 2 - 1;
var exponent = chooseInt(0, maxExp);
n = Math.pow(mantissa, exponent);
}
return n;
}
}
function explicitType(t, underlying) {
return label(t, transform(function(n) {
return {'!': t, value: n};
}, underlying));
}
// FIXME null, byte array, others?
var Octet = rangeInt('octet', 0, 255);
var ShortStr = label('shortstr',
transform(function(s) {
return s.substr(0, 255);
}, arb.Str));
var LongStr = label('longstr',
transform(
function(bytes) { return Buffer.from(bytes); },
repeat(Octet)));
var UShort = rangeInt('short-uint', 0, 0xffff);
var ULong = rangeInt('long-uint', 0, 0xffffffff);
var ULongLong = rangeInt('longlong-uint', 0, 0xffffffffffffffff);
var Short = rangeInt('short-int', -0x8000, 0x7fff);
var Long = rangeInt('long-int', -0x80000000, 0x7fffffff);
var LongLong = rangeInt('longlong-int', -0x8000000000000000,
0x7fffffffffffffff);
var Bit = label('bit', arb.Bool);
var Double = label('double', asGenerator(floatChooser(308)));
var Float = label('float', transform(toFloat32, floatChooser(38)));
var Timestamp = label('timestamp', transform(
function(n) {
return {'!': 'timestamp', value: n};
}, ULongLong));
var Decimal = label('decimal', transform(
function(args) {
return {'!': 'decimal', value: {places: args[1], digits: args[0]}};
}, sequence(arb.UInt, Octet)));
var UnsignedByte = label('unsignedbyte', transform(
function(n) {
return {'!': 'unsignedbyte', value: n};
}, Octet));
var UnsignedShort = label('unsignedshort', transform(
function(n) {
return {'!': 'unsignedshort', value: n};
}, UShort));
var UnsignedInt = label('unsignedint', transform(
function(n) {
return {'!': 'unsignedint', value: n};
}, ULong));
// Signed 8 bit int
var Byte = rangeInt('byte', -128, 127);
// Explicitly typed values
var ExByte = explicitType('byte', Byte);
var ExInt8 = explicitType('int8', Byte);
var ExShort = explicitType('short', Short);
var ExInt16 = explicitType('int16', Short);
var ExInt = explicitType('int', Long);
var ExInt32 = explicitType('int32', Long);
var ExLong = explicitType('long', LongLong);
var ExInt64 = explicitType('int64', LongLong);
var FieldArray = label('field-array', recursive(function() {
return arb.Array(
arb.Null,
LongStr, ShortStr,
Octet, UShort, ULong, ULongLong,
Byte, Short, Long, LongLong,
ExByte, ExInt8, ExShort, ExInt16,
ExInt, ExInt32, ExLong, ExInt64,
Bit, Float, Double, FieldTable, FieldArray)
}));
var FieldTable = label('table', recursive(function() {
return sized(function() { return 5; },
arb.Object(
arb.Null,
LongStr, ShortStr, Octet,
UShort, ULong, ULongLong,
Byte, Short, Long, LongLong,
ExByte, ExInt8, ExShort, ExInt16,
ExInt, ExInt32, ExLong, ExInt64,
Bit, Float, Double, FieldArray, FieldTable))
}));
// Internal tests of our properties
var domainProps = [
[Octet, function(n) { return n >= 0 && n < 256; }],
[ShortStr, function(s) { return typeof s === 'string' && s.length < 256; }],
[LongStr, function(s) { return Buffer.isBuffer(s); }],
[UShort, function(n) { return n >= 0 && n <= 0xffff; }],
[ULong, function(n) { return n >= 0 && n <= 0xffffffff; }],
[ULongLong, function(n) {
return n >= 0 && n <= 0xffffffffffffffff; }],
[Short, function(n) { return n >= -0x8000 && n <= 0x8000; }],
[Long, function(n) { return n >= -0x80000000 && n < 0x80000000; }],
[LongLong, function(n) { return n >= -0x8000000000000000 && n < 0x8000000000000000; }],
[Bit, function(b) { return typeof b === 'boolean'; }],
[Double, function(f) { return !isNaN(f) && isFinite(f); }],
[Float, function(f) { return !isNaN(f) && isFinite(f) && (Math.log(Math.abs(f)) * Math.LOG10E) < 309; }],
[Decimal, function(d) {
return d['!'] === 'decimal' &&
d.value['places'] <= 255 &&
d.value['digits'] <= 0xffffffff;
}],
[Timestamp, function(t) { return t['!'] === 'timestamp'; }],
[FieldTable, function(t) { return typeof t === 'object'; }],
[FieldArray, function(a) { return Array.isArray(a); }]
];
suite("Domains", function() {
domainProps.forEach(function(p) {
test(p[0] + ' domain',
forAll(p[0]).satisfy(p[1]).asTest({times: 500}));
});
});
// For methods and properties (as opposed to field table values) it's
// easier just to accept and produce numbers for timestamps.
var ArgTimestamp = label('timestamp', ULongLong);
// These are the domains used in method arguments
var ARG_TYPES = {
'octet': Octet,
'shortstr': ShortStr,
'longstr': LongStr,
'short': UShort,
'long': ULong,
'longlong': ULongLong,
'bit': Bit,
'table': FieldTable,
'timestamp': ArgTimestamp
};
function argtype(thing) {
if (thing.default === undefined) {
return ARG_TYPES[thing.type];
}
else {
return choice(ARG_TYPES[thing.type], Undefined);
}
}
function zipObject(vals, names) {
var obj = {};
vals.forEach(function(v, i) { obj[names[i]] = v; });
return obj;
}
function name(arg) { return arg.name; }
var defs = require('../lib/defs');
function method(info) {
var domain = sequence.apply(null, info.args.map(argtype));
var names = info.args.map(name);
return label(info.name, transform(function(fieldVals) {
return {id: info.id,
fields: zipObject(fieldVals, names)};
}, domain));
}
function properties(info) {
var types = info.args.map(argtype);
types.unshift(ULongLong); // size
var domain = sequence.apply(null, types);
var names = info.args.map(name);
return label(info.name, transform(function(fieldVals) {
return {id: info.id,
size: fieldVals[0],
fields: zipObject(fieldVals.slice(1), names)};
}, domain));
}
var methods = [];
var propertieses = [];
for (var k in defs) {
if (k.substr(0, 10) === 'methodInfo') {
methods.push(method(defs[k]));
methods[defs[k].name] = method(defs[k]);
}
else if (k.substr(0, 14) === 'propertiesInfo') {
propertieses.push(properties(defs[k]));
propertieses[defs[k].name] = properties(defs[k]);
}
};
module.exports = {
Octet: Octet,
ShortStr: ShortStr,
LongStr: LongStr,
UShort: UShort,
ULong: ULong,
ULongLong: ULongLong,
Short: Short,
Long: Long,
LongLong: LongLong,
Bit: Bit,
Double: Double,
Float: Float,
Timestamp: Timestamp,
Decimal: Decimal,
UnsignedByte: UnsignedByte,
UnsignedShort: UnsignedShort,
UnsignedInt: UnsignedInt,
FieldArray: FieldArray,
FieldTable: FieldTable,
methods: methods,
properties: propertieses
};
module.exports.rangeInt = rangeInt;

191
node_modules/amqplib/test/frame.js generated vendored Normal file
View File

@@ -0,0 +1,191 @@
'use strict';
var assert = require('assert');
var succeed = require('./util').succeed;
var fail = require('./util').fail;
var connection = require('../lib/connection');
var Frames = connection.Connection;
var HEARTBEAT = require('../lib/frame').HEARTBEAT;
var Stream = require('stream');
var PassThrough = Stream.PassThrough;
var defs = require('../lib/defs');
// We'll need to supply a stream which we manipulate ourselves
function inputs() {
// don't coalesce buffers, since that could mess up properties
// (e.g., encoded frame size)
return new PassThrough({objectMode: true});
}
var HB = Buffer.from([defs.constants.FRAME_HEARTBEAT,
0, 0, // channel 0
0, 0, 0, 0, // zero size
defs.constants.FRAME_END]);
suite("Explicit parsing", function() {
test('Parse heartbeat', function() {
var input = inputs();
var frames = new Frames(input);
input.write(HB);
assert(frames.recvFrame() === HEARTBEAT);
assert(!frames.recvFrame());
});
test('Parse partitioned', function() {
var input = inputs();
var frames = new Frames(input);
input.write(HB.subarray(0, 3));
assert(!frames.recvFrame());
input.write(HB.subarray(3));
assert(frames.recvFrame() === HEARTBEAT);
assert(!frames.recvFrame());
});
function testBogusFrame(name, bytes) {
test(name, function(done) {
var input = inputs();
var frames = new Frames(input);
frames.frameMax = 5; //for the max frame test
input.write(Buffer.from(bytes));
frames.step(function(err, frame) {
if (err != null) done();
else done(new Error('Was a bogus frame!'));
});
});
}
testBogusFrame('Wrong sized frame',
[defs.constants.FRAME_BODY,
0,0, 0,0,0,0, // zero length
65, // but a byte!
defs.constants.FRAME_END]);
testBogusFrame('Unknown method frame',
[defs.constants.FRAME_METHOD,
0,0, 0,0,0,4,
0,0,0,0, // garbage ID
defs.constants.FRAME_END]);
});
// Now for a bit more fun.
var amqp = require('./data');
var claire = require('claire');
var choice = claire.choice;
var forAll = claire.forAll;
var repeat = claire.repeat;
var label = claire.label;
var sequence = claire.sequence;
var transform = claire.transform;
var sized = claire.sized;
var assertEqualModuloDefaults =
require('./codec').assertEqualModuloDefaults;
var Trace = label('frame trace',
repeat(choice.apply(choice, amqp.methods)));
suite("Parsing", function() {
function testPartitioning(partition) {
return forAll(Trace).satisfy(function(t) {
var bufs = [];
var input = inputs();
var frames = new Frames(input);
var i = 0, ex;
frames.accept = function(f) {
// A minor hack to make sure we get the assertion exception;
// otherwise, it's just a test that we reached the line
// incrementing `i` for each frame.
try {
assertEqualModuloDefaults(t[i], f.fields);
}
catch (e) {
ex = e;
}
i++;
};
t.forEach(function(f) {
f.channel = 0;
bufs.push(defs.encodeMethod(f.id, 0, f.fields));
});
partition(bufs).forEach(function (chunk) { input.write(chunk); });
frames.acceptLoop();
if (ex) throw ex;
return i === t.length;
}).asTest({times: 20})
};
test("Parse trace of methods",
testPartitioning(function(bufs) { return bufs; }));
test("Parse concat'd methods",
testPartitioning(function(bufs) {
return [Buffer.concat(bufs)];
}));
test("Parse partitioned methods",
testPartitioning(function(bufs) {
var full = Buffer.concat(bufs);
var onethird = Math.floor(full.length / 3);
var twothirds = 2 * onethird;
return [
full.subarray(0, onethird),
full.subarray(onethird, twothirds),
full.subarray(twothirds)
];
}));
});
var FRAME_MAX_MAX = 4096 * 4;
var FRAME_MAX_MIN = 4096;
var FrameMax = amqp.rangeInt('frame max',
FRAME_MAX_MIN,
FRAME_MAX_MAX);
var Body = sized(function(_n) {
return Math.floor(Math.random() * FRAME_MAX_MAX);
}, repeat(amqp.Octet));
var Content = transform(function(args) {
return {
method: args[0].fields,
header: args[1].fields,
body: Buffer.from(args[2])
}
}, sequence(amqp.methods['BasicDeliver'],
amqp.properties['BasicProperties'], Body));
suite("Content framing", function() {
test("Adhere to frame max",
forAll(Content, FrameMax).satisfy(function(content, max) {
var input = inputs();
var frames = new Frames(input);
frames.frameMax = max;
frames.sendMessage(
0,
defs.BasicDeliver, content.method,
defs.BasicProperties, content.header,
content.body);
var f, i = 0, largest = 0;
while (f = input.read()) {
i++;
if (f.length > largest) largest = f.length;
if (f.length > max) {
return false;
}
}
// The ratio of frames to 'contents' should always be >= 2
// (one properties frame and at least one content frame); > 2
// indicates fragmentation. The largest is always, of course <= frame max
//console.log('Frames: %d; frames per message: %d; largest frame %d', i, i / t.length, largest);
return true;
}).asTest());
});

203
node_modules/amqplib/test/mux.js generated vendored Normal file
View File

@@ -0,0 +1,203 @@
'use strict';
var assert = require('assert');
var Mux = require('../lib/mux').Mux;
var PassThrough = require('stream').PassThrough;
var latch = require('./util').latch;
var schedule = require('./util').schedule;
function stream() {
return new PassThrough({objectMode: true});
}
function readAllObjects(s, cb) {
var objs = [];
function read() {
var v = s.read();
while (v !== null) {
objs.push(v);
v = s.read();
}
}
s.on('end', function() { cb(objs); });
s.on('readable', read);
read();
}
test("single input", function(done) {
var input = stream();
var output = stream();
input.on('end', function() { output.end() });
var mux = new Mux(output);
mux.pipeFrom(input);
var data = [1,2,3,4,5,6,7,8,9];
// not 0, it's treated specially by PassThrough for some reason. By
// 'specially' I mean it breaks the stream. See e.g.,
// https://github.com/isaacs/readable-stream/pull/55
data.forEach(function (chunk) { input.write(chunk); });
readAllObjects(output, function(vals) {
assert.deepEqual(data, vals);
done();
});
input.end();
});
test("single input, resuming stream", function(done) {
var input = stream();
var output = stream();
input.on('end', function() { output.end() });
var mux = new Mux(output);
mux.pipeFrom(input);
// Streams might be blocked and become readable again, simulate this
// using a special read function and a marker
var data = [1,2,3,4,'skip',6,7,8,9];
var oldRead = input.read;
input.read = function(size) {
var val = oldRead.call(input, size)
if (val === 'skip') {
input.emit('readable');
return null
}
return val;
}
data.forEach(function (chunk) { input.write(chunk); });
readAllObjects(output, function(vals) {
assert.deepEqual([1,2,3,4,6,7,8,9], vals);
done();
});
input.end();
});
test("two sequential inputs", function(done) {
var input1 = stream();
var input2 = stream();
var output = stream();
var mux = new Mux(output);
mux.pipeFrom(input1);
mux.pipeFrom(input2);
var data = [1,2,3,4,5,6,7,8,9];
data.forEach(function(v) { input1.write(v); });
input1.on('end', function() {
data.forEach(function (v) { input2.write(v); });
input2.end();
});
input2.on('end', function() { output.end(); });
input1.end();
readAllObjects(output, function(vs) {
assert.equal(2 * data.length, vs.length);
done();
});
});
test("two interleaved inputs", function(done) {
var input1 = stream();
var input2 = stream();
var output = stream();
var mux = new Mux(output);
mux.pipeFrom(input1);
mux.pipeFrom(input2);
var endLatch = latch(2, function() { output.end(); });
input1.on('end', endLatch);
input2.on('end', endLatch);
var data = [1,2,3,4,5,6,7,8,9];
data.forEach(function(v) { input1.write(v); });
input1.end();
data.forEach(function(v) { input2.write(v); });
input2.end();
readAllObjects(output, function(vs) {
assert.equal(2 * data.length, vs.length);
done();
});
});
test("unpipe", function(done) {
var input = stream();
var output = stream();
var mux = new Mux(output);
var pipedData = [1,2,3,4,5];
var unpipedData = [6,7,8,9];
mux.pipeFrom(input);
schedule(function() {
pipedData.forEach(function (chunk) { input.write(chunk); });
schedule(function() {
mux.unpipeFrom(input);
schedule(function() {
unpipedData.forEach(function(chunk) { input.write(chunk); });
input.end();
schedule(function() {
// exhaust so that 'end' fires
var v; while (v = input.read());
});
});
});
});
input.on('end', function() {
output.end();
});
readAllObjects(output, function(vals) {
try {
assert.deepEqual(pipedData, vals);
done();
}
catch (e) { done(e); }
});
});
test("roundrobin", function(done) {
var input1 = stream();
var input2 = stream();
var output = stream();
var mux = new Mux(output);
mux.pipeFrom(input1);
mux.pipeFrom(input2);
var endLatch = latch(2, function() { output.end(); });
input1.on('end', endLatch);
input2.on('end', endLatch);
var ones = [1,1,1,1,1];
ones.forEach(function(v) { input1.write(v); });
input1.end();
var twos = [2,2,2,2,2];
twos.forEach(function(v) { input2.write(v); });
input2.end();
readAllObjects(output, function(vs) {
assert.deepEqual([1,2,1,2,1,2,1,2,1,2], vs);
done();
});
});

217
node_modules/amqplib/test/util.js generated vendored Normal file
View File

@@ -0,0 +1,217 @@
'use strict';
var crypto = require('crypto');
var Connection = require('../lib/connection').Connection;
var PassThrough = require('stream').PassThrough;
var defs = require('../lib/defs');
var assert = require('assert');
var schedule = (typeof setImmediate === 'function') ?
setImmediate : process.nextTick;
function randomString() {
var hash = crypto.createHash('sha1');
hash.update(crypto.randomBytes(64));
return hash.digest('base64');
}
// Set up a socket pair {client, server}, such that writes to the
// client are readable from the server, and writes to the server are
// readable at the client.
//
// +---+ +---+
// | C | | S |
// --write->| l |----->| e |--read-->
// | i | | r |
// <--read--| e |<-----| v |<-write--
// | n | | e |
// | t | | r |
// +---+ +---+
//
// I also need to make sure that end called on either socket affects
// the other.
function socketPair() {
var server = new PassThrough();
var client = new PassThrough();
server.write = client.push.bind(client);
client.write = server.push.bind(server);
function end(chunk, encoding) {
if (chunk) this.push(chunk, encoding);
this.push(null);
}
server.end = end.bind(client);
client.end = end.bind(server);
return {client: client, server: server};
}
function runServer(socket, run) {
var frames = new Connection(socket);
// We will be closing the socket without doing a closing handshake,
// so cheat
frames.expectSocketClose = true;
// We also need to create some channel buffers, again a cheat
frames.freshChannel(null);
frames.freshChannel(null);
frames.freshChannel(null);
function send(id, fields, channel, content) {
channel = channel || 0;
if (content) {
schedule(function() {
frames.sendMessage(channel, id, fields,
defs.BasicProperties, fields,
content);
});
}
else {
schedule(function() {
frames.sendMethod(channel, id, fields);
});
}
}
function wait(method) {
return function() {
return new Promise(function(resolve, reject) {
if (method) {
frames.step(function(e, f) {
if (e !== null) return reject(e);
if (f.id === method)
resolve(f);
else
reject(new Error("Expected method: " + method +
", got " + f.id));
});
}
else {
frames.step(function(e, f) {
if (e !== null) return reject(e);
else resolve(f);
});
}
});
};
}
run(send, wait);
return frames;
}
// Produce a callback that will complete the test successfully
function succeed(done) {
return function() { done(); }
}
// Produce a callback that will complete the test successfully
// only if the value is an object, it has the specified
// attribute, and its value is equals to the expected value
function succeedIfAttributeEquals(attribute, value, done) {
return function(object) {
if (object && !(object instanceof Error) && value === object[attribute]) {
return done();
}
done(new Error(attribute + " is not equal to " + value));
};
}
// Produce a callback that will fail the test, given either an error
// (to be used as a failure continuation) or any other value (to be
// used as a success continuation when failure is expected)
function fail(done) {
return function(err) {
if (err instanceof Error) done(err);
else done(new Error("Expected to fail, instead got " + err.toString()));
}
}
// Create a function that will call done once it's been called itself
// `count` times. If it's called with an error value, it will
// immediately call done with that error value.
function latch(count, done) {
var awaiting = count;
var alive = true;
return function(err) {
if (err instanceof Error && alive) {
alive = false;
done(err);
}
else {
awaiting--;
if (awaiting === 0 && alive) {
alive = false;
done();
}
}
};
}
// Call a thunk with a continuation that will be called with an error
// if the thunk throws one, or nothing if it runs to completion.
function completes(thunk, done) {
try {
thunk();
done();
}
catch (e) { done(e); }
}
// Construct a Node.JS-style callback from a success continuation and
// an error continuation
function kCallback(k, ek) {
return function(err, val) {
if (err === null) k && k(val);
else ek && ek(err);
};
}
// A noddy way to make tests depend on the node version.
function versionGreaterThan(actual, spec) {
function int(e) { return parseInt(e); }
var version = actual.split('.').map(int);
var desired = spec.split('.').map(int);
for (var i=0; i < desired.length; i++) {
var a = version[i], b = desired[i];
if (a != b) return a > b;
}
return false;
}
suite('versionGreaterThan', function() {
test('full spec', function() {
assert(versionGreaterThan('0.8.26', '0.6.12'));
assert(versionGreaterThan('0.8.26', '0.8.21'));
});
test('partial spec', function() {
assert(versionGreaterThan('0.9.12', '0.8'));
});
test('not greater', function() {
assert(!versionGreaterThan('0.8.12', '0.8.26'));
assert(!versionGreaterThan('0.6.2', '0.6.12'));
assert(!versionGreaterThan('0.8.29', '0.8'));
});
test
});
module.exports = {
socketPair: socketPair,
runServer: runServer,
succeed: succeed,
succeedIfAttributeEquals: succeedIfAttributeEquals,
fail: fail,
latch: latch,
completes: completes,
kCallback: kCallback,
schedule: schedule,
randomString: randomString,
versionGreaterThan: versionGreaterThan
};