303 lines
6.8 KiB
JavaScript
303 lines
6.8 KiB
JavaScript
'use strict'
|
|
|
|
const { test } = require('tap')
|
|
const { setup, connect, subscribe } = require('./helper')
|
|
const aedes = require('../')
|
|
const { validateTopic } = require('../lib/utils')
|
|
|
|
test('validation of `null` topic', function (t) {
|
|
// issue #780
|
|
t.plan(1)
|
|
const err = validateTopic(null, 'SUBSCRIBE')
|
|
t.equal(err.message, 'impossible to SUBSCRIBE to an empty topic')
|
|
})
|
|
|
|
// [MQTT-4.7.1-3]
|
|
test('Single-level wildcard should match empty level', function (t) {
|
|
t.plan(4)
|
|
|
|
const s = connect(setup())
|
|
t.teardown(s.broker.close.bind(s.broker))
|
|
|
|
subscribe(t, s, 'a/+/b', 0, function () {
|
|
s.outStream.once('data', function (packet) {
|
|
t.pass('ok')
|
|
})
|
|
|
|
s.inStream.write({
|
|
cmd: 'publish',
|
|
topic: 'a//b',
|
|
payload: 'world'
|
|
})
|
|
})
|
|
})
|
|
|
|
// [MQTT-4.7.3-1]
|
|
test('publish empty topic', function (t) {
|
|
t.plan(4)
|
|
|
|
const s = connect(setup())
|
|
|
|
subscribe(t, s, '#', 0, function () {
|
|
s.outStream.once('data', function (packet) {
|
|
t.fail('no packet')
|
|
})
|
|
|
|
s.inStream.write({
|
|
cmd: 'publish',
|
|
topic: '',
|
|
payload: 'world'
|
|
})
|
|
|
|
s.broker.close(function () {
|
|
t.equal(s.broker.connectedClients, 0, 'no connected clients')
|
|
})
|
|
})
|
|
})
|
|
|
|
test('publish invalid topic with #', function (t) {
|
|
t.plan(4)
|
|
|
|
const s = connect(setup())
|
|
t.teardown(s.broker.close.bind(s.broker))
|
|
|
|
subscribe(t, s, '#', 0, function () {
|
|
s.outStream.once('data', function (packet) {
|
|
t.fail('no packet')
|
|
})
|
|
|
|
s.inStream.write({
|
|
cmd: 'publish',
|
|
topic: 'hello/#',
|
|
payload: 'world'
|
|
})
|
|
})
|
|
|
|
s.broker.on('clientError', function () {
|
|
t.pass('raise an error')
|
|
})
|
|
})
|
|
|
|
test('publish invalid topic with +', function (t) {
|
|
t.plan(4)
|
|
|
|
const s = connect(setup())
|
|
t.teardown(s.broker.close.bind(s.broker))
|
|
|
|
subscribe(t, s, '#', 0, function () {
|
|
s.outStream.once('data', function (packet) {
|
|
t.fail('no packet')
|
|
})
|
|
|
|
s.inStream.write({
|
|
cmd: 'publish',
|
|
topic: 'hello/+/eee',
|
|
payload: 'world'
|
|
})
|
|
})
|
|
|
|
s.broker.on('clientError', function () {
|
|
t.pass('raise an error')
|
|
})
|
|
})
|
|
|
|
;['base/#/sub', 'base/#sub', 'base/sub#', 'base/xyz+/sub', 'base/+xyz/sub', ''].forEach(function (topic) {
|
|
test('subscribe to invalid topic with "' + topic + '"', function (t) {
|
|
t.plan(1)
|
|
|
|
const s = connect(setup())
|
|
t.teardown(s.broker.close.bind(s.broker))
|
|
|
|
s.broker.on('clientError', function () {
|
|
t.pass('raise an error')
|
|
})
|
|
|
|
s.inStream.write({
|
|
cmd: 'subscribe',
|
|
messageId: 24,
|
|
subscriptions: [{
|
|
topic,
|
|
qos: 0
|
|
}]
|
|
})
|
|
})
|
|
|
|
test('unsubscribe to invalid topic with "' + topic + '"', function (t) {
|
|
t.plan(1)
|
|
|
|
const s = connect(setup())
|
|
t.teardown(s.broker.close.bind(s.broker))
|
|
|
|
s.broker.on('clientError', function () {
|
|
t.pass('raise an error')
|
|
})
|
|
|
|
s.inStream.write({
|
|
cmd: 'unsubscribe',
|
|
messageId: 24,
|
|
unsubscriptions: [topic]
|
|
})
|
|
})
|
|
})
|
|
|
|
test('topics are case-sensitive', function (t) {
|
|
t.plan(4)
|
|
|
|
const broker = aedes()
|
|
t.teardown(broker.close.bind(broker))
|
|
|
|
const publisher = connect(setup(broker), { clean: true })
|
|
const subscriber = connect(setup(broker), { clean: true })
|
|
const expected = {
|
|
cmd: 'publish',
|
|
topic: 'hello',
|
|
payload: Buffer.from('world'),
|
|
qos: 0,
|
|
dup: false,
|
|
length: 12,
|
|
retain: false
|
|
}
|
|
|
|
subscribe(t, subscriber, 'hello', 0, function () {
|
|
subscriber.outStream.on('data', function (packet) {
|
|
t.same(packet, expected, 'packet mush match')
|
|
})
|
|
;['hello', 'HELLO', 'heLLo', 'HELLO/#', 'hello/+'].forEach(function (topic) {
|
|
publisher.inStream.write({
|
|
cmd: 'publish',
|
|
topic,
|
|
payload: 'world',
|
|
qos: 0,
|
|
retain: false
|
|
})
|
|
})
|
|
})
|
|
})
|
|
|
|
function subscribeMultipleTopics (t, broker, qos, subscriber, subscriptions, done) {
|
|
const publisher = connect(setup(broker))
|
|
subscriber.inStream.write({
|
|
cmd: 'subscribe',
|
|
messageId: 24,
|
|
subscriptions
|
|
})
|
|
|
|
subscriber.outStream.once('data', function (packet) {
|
|
t.equal(packet.cmd, 'suback')
|
|
t.same(packet.granted, subscriptions.map(obj => obj.qos))
|
|
t.equal(packet.messageId, 24)
|
|
|
|
publisher.inStream.write({
|
|
cmd: 'publish',
|
|
topic: 'hello/world',
|
|
payload: 'world',
|
|
qos,
|
|
messageId: 42
|
|
})
|
|
|
|
if (done) {
|
|
done(null, packet)
|
|
}
|
|
})
|
|
}
|
|
|
|
test('Overlapped topics with same QoS', function (t) {
|
|
t.plan(4)
|
|
|
|
const broker = aedes()
|
|
t.teardown(broker.close.bind(broker))
|
|
|
|
const subscriber = connect(setup(broker))
|
|
const expected = {
|
|
cmd: 'publish',
|
|
topic: 'hello/world',
|
|
payload: Buffer.from('world'),
|
|
qos: 1,
|
|
dup: false,
|
|
length: 20,
|
|
retain: false
|
|
}
|
|
const sub = [
|
|
{ topic: 'hello/world', qos: 1 },
|
|
{ topic: 'hello/#', qos: 1 }]
|
|
subscribeMultipleTopics(t, broker, 1, subscriber, sub, function () {
|
|
subscriber.outStream.on('data', function (packet) {
|
|
delete packet.messageId
|
|
t.same(packet, expected, 'packet must match')
|
|
})
|
|
})
|
|
})
|
|
|
|
// [MQTT-3.3.5-1]
|
|
test('deliver overlapped topics respecting the maximum QoS of all the matching subscriptions - QoS 0 publish', function (t) {
|
|
t.plan(4)
|
|
|
|
const broker = aedes()
|
|
t.teardown(broker.close.bind(broker))
|
|
|
|
const subscriber = connect(setup(broker))
|
|
const expected = {
|
|
cmd: 'publish',
|
|
topic: 'hello/world',
|
|
payload: Buffer.from('world'),
|
|
qos: 0,
|
|
dup: false,
|
|
length: 18,
|
|
retain: false
|
|
}
|
|
const sub = [
|
|
{ topic: 'hello/world', qos: 0 },
|
|
{ topic: 'hello/#', qos: 2 }]
|
|
subscribeMultipleTopics(t, broker, 0, subscriber, sub, function () {
|
|
subscriber.outStream.on('data', function (packet) {
|
|
delete packet.messageId
|
|
t.same(packet, expected, 'packet must match')
|
|
})
|
|
})
|
|
})
|
|
|
|
// [MQTT-3.3.5-1]
|
|
test('deliver overlapped topics respecting the maximum QoS of all the matching subscriptions - QoS 2 publish', function (t) {
|
|
t.plan(3)
|
|
|
|
const broker = aedes()
|
|
t.teardown(broker.close.bind(broker))
|
|
|
|
const subscriber = connect(setup(broker))
|
|
|
|
const sub = [
|
|
{ topic: 'hello/world', qos: 0 },
|
|
{ topic: 'hello/#', qos: 2 }]
|
|
subscribeMultipleTopics(t, broker, 2, subscriber, sub, function () {
|
|
subscriber.outStream.on('data', function () {
|
|
t.fail('should receive messages with the maximum QoS')
|
|
})
|
|
})
|
|
})
|
|
|
|
test('Overlapped topics with QoS downgrade', function (t) {
|
|
t.plan(4)
|
|
|
|
const broker = aedes()
|
|
t.teardown(broker.close.bind(broker))
|
|
|
|
const subscriber = connect(setup(broker))
|
|
const expected = {
|
|
cmd: 'publish',
|
|
topic: 'hello/world',
|
|
payload: Buffer.from('world'),
|
|
qos: 0,
|
|
dup: false,
|
|
length: 18,
|
|
retain: false
|
|
}
|
|
const sub = [
|
|
{ topic: 'hello/world', qos: 1 },
|
|
{ topic: 'hello/#', qos: 1 }]
|
|
subscribeMultipleTopics(t, broker, 0, subscriber, sub, function () {
|
|
subscriber.outStream.on('data', function (packet) {
|
|
t.same(packet, expected, 'packet must match')
|
|
})
|
|
})
|
|
})
|