| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302 |
- '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')
- })
- })
- })
|