File Explorer

/proc/self/root/proc/self/root/var/runtime/node_modules/@aws-sdk/node_modules/mqtt-packet

This explorer reads the filesystem of the server it runs on, so /workspace/user isn't present here. Browsing and the terminal still work against this server's own disk from /.

test.js66.3 KB · 2867 lines
const util = require('util') const test = require('tape')const mqtt = require('./')const WS = require('readable-stream').Writable function normalExpectedObject (object) {  if (object.username != null) object.username = object.username.toString()  if (object.password != null) object.password = Buffer.from(object.password)  return object} function testParseGenerate (name, object, buffer, opts) {  test(`${name} parse`, t => {    t.plan(2)     const parser = mqtt.parser(opts)    const expected = object    const fixture = buffer     parser.on('packet', packet => {      if (packet.cmd !== 'publish') {        delete packet.topic        delete packet.payload      }      t.deepLooseEqual(packet, normalExpectedObject(expected), 'expected packet')    })     parser.on('error', err => {      t.fail(err)    })     t.equal(parser.parse(fixture), 0, 'remaining bytes')  })   test(`${name} generate`, t => {    // For really large buffers, the expanded hex string can be so long as to    // generate an error in nodejs 14.x, so only do the test with extra output    // for relatively small buffers.    const bigLength = 10000    const generatedBuffer = mqtt.generate(object, opts)    if (generatedBuffer.length < bigLength && buffer.length < bigLength) {      t.equal(generatedBuffer.toString('hex'), buffer.toString('hex'))    } else {      const bufferOkay = generatedBuffer.equals(buffer)      if (bufferOkay) {        t.pass()      } else {        // Output abbreviated representations of the buffers.        t.comment('Expected:\n' + util.inspect(buffer))        t.comment('Got:\n' + util.inspect(generatedBuffer))        t.fail('Large buffers not equal')      }    }    t.end()  })   test(`${name} mirror`, t => {    t.plan(2)     const parser = mqtt.parser(opts)    const expected = object    const fixture = mqtt.generate(object, opts)     parser.on('packet', packet => {      if (packet.cmd !== 'publish') {        delete packet.topic        delete packet.payload      }      t.deepLooseEqual(packet, normalExpectedObject(expected), 'expected packet')    })     parser.on('error', err => {      t.fail(err)    })     t.equal(parser.parse(fixture), 0, 'remaining bytes')  })   test(`${name} writeToStream`, t => {    const stream = WS()    stream.write = () => true    stream.on('error', (err) => t.fail(err))     const result = mqtt.writeToStream(object, stream, opts)    t.equal(result, true, 'should return true')    t.end()  })} // the API allows to pass strings as buffers to writeToStream and generate// parsing them back will result in a string so only generate and compare to bufferfunction testGenerateOnly (name, object, buffer, opts) {  test(name, t => {    t.equal(mqtt.generate(object, opts).toString('hex'), buffer.toString('hex'))    t.end()  })} function testParseOnly (name, object, buffer, opts) {  test(name, t => {    const parser = mqtt.parser(opts)    // const expected = object    // const fixture = buffer     t.plan(2 + Object.keys(object).length)     parser.on('packet', packet => {      t.equal(Object.keys(object).length, Object.keys(packet).length, 'key count')      Object.keys(object).forEach(key => {        t.deepEqual(packet[key], object[key], `expected packet property ${key}`)      })    })     t.equal(parser.parse(buffer), 0, 'remaining bytes')    t.end()  })} function testParseError (expected, fixture, opts) {  test(expected, t => {    t.plan(1)     const parser = mqtt.parser(opts)     parser.on('error', err => {      t.equal(err.message, expected, 'expected error message')    })     parser.on('packet', () => {      t.fail('parse errors should not be followed by packet events')    })     parser.parse(fixture)    t.end()  })} function testGenerateError (expected, fixture, opts, name) {  test(name || expected, t => {    t.plan(1)     try {      mqtt.generate(fixture, opts)    } catch (err) {      t.equal(expected, err.message)    }    t.end()  })} function testGenerateErrorMultipleCmds (cmds, expected, fixture, opts) {  cmds.forEach(cmd => {    const obj = Object.assign({}, fixture)    obj.cmd = cmd    testGenerateError(expected, obj, opts, `${expected} on ${cmd}`)  }  )} function testParseGenerateDefaults (name, object, buffer, generated, opts) {  testParseOnly(`${name} parse`, generated, buffer, opts)  testGenerateOnly(`${name} generate`, object, buffer, opts)} function testParseAndGenerate (name, object, buffer, opts) {  testParseOnly(`${name} parse`, object, buffer, opts)  testGenerateOnly(`${name} generate`, object, buffer, opts)} function testWriteToStreamError (expected, fixture) {  test(`writeToStream ${expected} error`, t => {    t.plan(2)     const stream = WS()     stream.write = () => t.fail('should not have called write')    stream.on('error', () => t.pass('error emitted'))     const result = mqtt.writeToStream(fixture, stream)     t.false(result, 'result should be false')    t.end()  })} test('cacheNumbers get/set/unset', t => {  t.true(mqtt.writeToStream.cacheNumbers, 'initial state of cacheNumbers is enabled')  mqtt.writeToStream.cacheNumbers = false  t.false(mqtt.writeToStream.cacheNumbers, 'cacheNumbers can be disabled')  mqtt.writeToStream.cacheNumbers = true  t.true(mqtt.writeToStream.cacheNumbers, 'cacheNumbers can be enabled')  t.end()}) test('disabled numbers cache', t => {  const stream = WS()  const message = {    cmd: 'publish',    retain: false,    qos: 0,    dup: false,    length: 10,    topic: Buffer.from('test'),    payload: Buffer.from('test')  }  const expected = Buffer.from([    48, 10, // Header    0, 4, // Topic length    116, 101, 115, 116, // Topic (test)    116, 101, 115, 116 // Payload (test)  ])  let written = Buffer.alloc(0)   stream.write = (chunk) => {    written = Buffer.concat([written, chunk])  }  mqtt.writeToStream.cacheNumbers = false   mqtt.writeToStream(message, stream)   t.deepEqual(written, expected, 'written buffer is expected')   mqtt.writeToStream.cacheNumbers = true   stream.end()  t.end()}) testGenerateError('Unknown command', {}) testParseError('Not supported', Buffer.from([0, 1, 0]), {}) // Length header fieldtestParseError('Invalid variable byte integer', Buffer.from(  [16, 255, 255, 255, 255]), {})testParseError('Invalid variable byte integer', Buffer.from(  [16, 255, 255, 255, 128]), {})testParseError('Invalid variable byte integer', Buffer.from(  [16, 255, 255, 255, 255, 1]), {})testParseError('Invalid variable byte integer', Buffer.from(  [16, 255, 255, 255, 255, 127]), {})testParseError('Invalid variable byte integer', Buffer.from(  [16, 255, 255, 255, 255, 128]), {})testParseError('Invalid variable byte integer', Buffer.from(  [16, 255, 255, 255, 255, 255, 1]), {}) testParseGenerate('minimal connect', {  cmd: 'connect',  retain: false,  qos: 0,  dup: false,  length: 18,  protocolId: 'MQIsdp',  protocolVersion: 3,  clean: false,  keepalive: 30,  clientId: 'test'}, Buffer.from([  16, 18, // Header  0, 6, // Protocol ID length  77, 81, 73, 115, 100, 112, // Protocol ID  3, // Protocol version  0, // Connect flags  0, 30, // Keepalive  0, 4, // Client ID length  116, 101, 115, 116 // Client ID])) testGenerateOnly('minimal connect with clientId as Buffer', {  cmd: 'connect',  retain: false,  qos: 0,  dup: false,  length: 18,  protocolId: 'MQIsdp',  protocolVersion: 3,  clean: false,  keepalive: 30,  clientId: Buffer.from('test')}, Buffer.from([  16, 18, // Header  0, 6, // Protocol ID length  77, 81, 73, 115, 100, 112, // Protocol ID  3, // Protocol version  0, // Connect flags  0, 30, // Keepalive  0, 4, // Client ID length  116, 101, 115, 116 // Client ID])) testParseGenerate('connect MQTT bridge 131', {  cmd: 'connect',  retain: false,  qos: 0,  dup: false,  length: 18,  protocolId: 'MQIsdp',  protocolVersion: 3,  bridgeMode: true,  clean: false,  keepalive: 30,  clientId: 'test'}, Buffer.from([  16, 18, // Header  0, 6, // Protocol ID length  77, 81, 73, 115, 100, 112, // Protocol ID  131, // Protocol version  0, // Connect flags  0, 30, // Keepalive  0, 4, // Client ID length  116, 101, 115, 116 // Client ID])) testParseGenerate('connect MQTT bridge 132', {  cmd: 'connect',  retain: false,  qos: 0,  dup: false,  length: 18,  protocolId: 'MQIsdp',  protocolVersion: 4,  bridgeMode: true,  clean: false,  keepalive: 30,  clientId: 'test'}, Buffer.from([  16, 18, // Header  0, 6, // Protocol ID length  77, 81, 73, 115, 100, 112, // Protocol ID  132, // Protocol version  0, // Connect flags  0, 30, // Keepalive  0, 4, // Client ID length  116, 101, 115, 116 // Client ID])) testParseGenerate('connect MQTT 5', {  cmd: 'connect',  retain: false,  qos: 0,  dup: false,  length: 125,  protocolId: 'MQTT',  protocolVersion: 5,  will: {    retain: true,    qos: 2,    properties: {      willDelayInterval: 1234,      payloadFormatIndicator: false,      messageExpiryInterval: 4321,      contentType: 'test',      responseTopic: 'topic',      correlationData: Buffer.from([1, 2, 3, 4]),      userProperties: {        test: 'test'      }    },    topic: 'topic',    payload: Buffer.from([4, 3, 2, 1])  },  clean: true,  keepalive: 30,  properties: {    sessionExpiryInterval: 1234,    receiveMaximum: 432,    maximumPacketSize: 100,    topicAliasMaximum: 456,    requestResponseInformation: true,    requestProblemInformation: true,    userProperties: {      test: 'test'    },    authenticationMethod: 'test',    authenticationData: Buffer.from([1, 2, 3, 4])  },  clientId: 'test'}, Buffer.from([  16, 125, // Header  0, 4, // Protocol ID length  77, 81, 84, 84, // Protocol ID  5, // Protocol version  54, // Connect flags  0, 30, // Keepalive  47, // properties length  17, 0, 0, 4, 210, // sessionExpiryInterval  33, 1, 176, // receiveMaximum  39, 0, 0, 0, 100, // maximumPacketSize  34, 1, 200, // topicAliasMaximum  25, 1, // requestResponseInformation  23, 1, // requestProblemInformation,  38, 0, 4, 116, 101, 115, 116, 0, 4, 116, 101, 115, 116, // userProperties,  21, 0, 4, 116, 101, 115, 116, // authenticationMethod  22, 0, 4, 1, 2, 3, 4, // authenticationData  0, 4, // Client ID length  116, 101, 115, 116, // Client ID  47, // will properties  24, 0, 0, 4, 210, // will delay interval  1, 0, // payload format indicator  2, 0, 0, 16, 225, // message expiry interval  3, 0, 4, 116, 101, 115, 116, // content type  8, 0, 5, 116, 111, 112, 105, 99, // response topic  9, 0, 4, 1, 2, 3, 4, // corelation data  38, 0, 4, 116, 101, 115, 116, 0, 4, 116, 101, 115, 116, // user properties  0, 5, // Will topic length  116, 111, 112, 105, 99, // Will topic  0, 4, // Will payload length  4, 3, 2, 1// Will payload])) testParseGenerate('connect MQTT 5 with will properties but with empty will payload', {  cmd: 'connect',  retain: false,  qos: 0,  dup: false,  length: 121,  protocolId: 'MQTT',  protocolVersion: 5,  will: {    retain: true,    qos: 2,    properties: {      willDelayInterval: 1234,      payloadFormatIndicator: false,      messageExpiryInterval: 4321,      contentType: 'test',      responseTopic: 'topic',      correlationData: Buffer.from([1, 2, 3, 4]),      userProperties: {        test: 'test'      }    },    topic: 'topic',    payload: Buffer.from([])  },  clean: true,  keepalive: 30,  properties: {    sessionExpiryInterval: 1234,    receiveMaximum: 432,    maximumPacketSize: 100,    topicAliasMaximum: 456,    requestResponseInformation: true,    requestProblemInformation: true,    userProperties: {      test: 'test'    },    authenticationMethod: 'test',    authenticationData: Buffer.from([1, 2, 3, 4])  },  clientId: 'test'}, Buffer.from([  16, 121, // Header  0, 4, // Protocol ID length  77, 81, 84, 84, // Protocol ID  5, // Protocol version  54, // Connect flags  0, 30, // Keepalive  47, // properties length  17, 0, 0, 4, 210, // sessionExpiryInterval  33, 1, 176, // receiveMaximum  39, 0, 0, 0, 100, // maximumPacketSize  34, 1, 200, // topicAliasMaximum  25, 1, // requestResponseInformation  23, 1, // requestProblemInformation,  38, 0, 4, 116, 101, 115, 116, 0, 4, 116, 101, 115, 116, // userProperties,  21, 0, 4, 116, 101, 115, 116, // authenticationMethod  22, 0, 4, 1, 2, 3, 4, // authenticationData  0, 4, // Client ID length  116, 101, 115, 116, // Client ID  47, // will properties  24, 0, 0, 4, 210, // will delay interval  1, 0, // payload format indicator  2, 0, 0, 16, 225, // message expiry interval  3, 0, 4, 116, 101, 115, 116, // content type  8, 0, 5, 116, 111, 112, 105, 99, // response topic  9, 0, 4, 1, 2, 3, 4, // corelation data  38, 0, 4, 116, 101, 115, 116, 0, 4, 116, 101, 115, 116, // user properties  0, 5, // Will topic length  116, 111, 112, 105, 99, // Will topic  0, 0 // Will payload length])) testParseGenerate('connect MQTT 5 w/o will properties', {  cmd: 'connect',  retain: false,  qos: 0,  dup: false,  length: 78,  protocolId: 'MQTT',  protocolVersion: 5,  will: {    retain: true,    qos: 2,    topic: 'topic',    payload: Buffer.from([4, 3, 2, 1])  },  clean: true,  keepalive: 30,  properties: {    sessionExpiryInterval: 1234,    receiveMaximum: 432,    maximumPacketSize: 100,    topicAliasMaximum: 456,    requestResponseInformation: true,    requestProblemInformation: true,    userProperties: {      test: 'test'    },    authenticationMethod: 'test',    authenticationData: Buffer.from([1, 2, 3, 4])  },  clientId: 'test'}, Buffer.from([  16, 78, // Header  0, 4, // Protocol ID length  77, 81, 84, 84, // Protocol ID  5, // Protocol version  54, // Connect flags  0, 30, // Keepalive  47, // properties length  17, 0, 0, 4, 210, // sessionExpiryInterval  33, 1, 176, // receiveMaximum  39, 0, 0, 0, 100, // maximumPacketSize  34, 1, 200, // topicAliasMaximum  25, 1, // requestResponseInformation  23, 1, // requestProblemInformation,  38, 0, 4, 116, 101, 115, 116, 0, 4, 116, 101, 115, 116, // userProperties,  21, 0, 4, 116, 101, 115, 116, // authenticationMethod  22, 0, 4, 1, 2, 3, 4, // authenticationData  0, 4, // Client ID length  116, 101, 115, 116, // Client ID  0, // will properties  0, 5, // Will topic length  116, 111, 112, 105, 99, // Will topic  0, 4, // Will payload length  4, 3, 2, 1// Will payload])) testParseGenerate('no clientId with 3.1.1', {  cmd: 'connect',  retain: false,  qos: 0,  dup: false,  length: 12,  protocolId: 'MQTT',  protocolVersion: 4,  clean: true,  keepalive: 30,  clientId: ''}, Buffer.from([  16, 12, // Header  0, 4, // Protocol ID length  77, 81, 84, 84, // Protocol ID  4, // Protocol version  2, // Connect flags  0, 30, // Keepalive  0, 0 // Client ID length])) testParseGenerateDefaults('no clientId with 5.0', {  cmd: 'connect',  protocolId: 'MQTT',  protocolVersion: 5,  clean: true,  keepalive: 60,  properties:  {    receiveMaximum: 20  },  clientId: ''}, Buffer.from(  [16, 16, 0, 4, 77, 81, 84, 84, 5, 2, 0, 60, 3, 33, 0, 20, 0, 0]), {  cmd: 'connect',  retain: false,  qos: 0,  dup: false,  length: 16,  topic: null,  payload: null,  protocolId: 'MQTT',  protocolVersion: 5,  clean: true,  keepalive: 60,  properties: {    receiveMaximum: 20  },  clientId: ''}, { protocolVersion: 5 }) testParseGenerateDefaults('utf-8 clientId with 5.0', {  cmd: 'connect',  retain: false,  qos: 0,  dup: false,  length: 23,  protocolId: 'MQTT',  protocolVersion: 4,  clean: true,  keepalive: 30,  clientId: 'Ŧėśt🜄'}, Buffer.from([  16, 23, // Header  0, 4, // Protocol ID length  77, 81, 84, 84, // Protocol ID  4, // Protocol version  2, // Connect flags  0, 30, // Keepalive  0, 11, // Client ID length  197, 166, // Ŧ (UTF-8: 0xc5a6)  196, 151, // ė (UTF-8: 0xc497)  197, 155, // ś (utf-8: 0xc59b)  116, // t (utf-8: 0x74)  240, 159, 156, 132 // 🜄 (utf-8: 0xf09f9c84)]), {  cmd: 'connect',  retain: false,  qos: 0,  dup: false,  length: 23,  topic: null,  payload: null,  protocolId: 'MQTT',  protocolVersion: 4,  clean: true,  keepalive: 30,  clientId: 'Ŧėśt🜄'}, { protocol: 5 }) testParseGenerateDefaults('default connect', {  cmd: 'connect',  clientId: 'test'}, Buffer.from([  16, 16, 0, 4, 77, 81, 84,  84, 4, 2, 0, 0,  0, 4, 116, 101, 115, 116]), {  cmd: 'connect',  retain: false,  qos: 0,  dup: false,  length: 16,  topic: null,  payload: null,  protocolId: 'MQTT',  protocolVersion: 4,  clean: true,  keepalive: 0,  clientId: 'test'}) testParseAndGenerate('Version 4 CONACK', {  cmd: 'connack',  retain: false,  qos: 0,  dup: false,  length: 2,  topic: null,  payload: null,  sessionPresent: false,  returnCode: 1}, Buffer.from([  32, 2, // Fixed Header (CONNACK, Remaining Length)  0, 1 // Variable Header (Session not present, Connection Refused - unacceptable protocol version)]), {}) // Default protocolVersion (4) testParseAndGenerate('Version 5 CONACK', {  cmd: 'connack',  retain: false,  qos: 0,  dup: false,  length: 3,  topic: null,  payload: null,  sessionPresent: false,  reasonCode: 140}, Buffer.from([  32, 3, // Fixed Header (CONNACK, Remaining Length)  0, 140, // Variable Header (Session not present, Bad authentication method)  0 // Property Length Zero]), { protocolVersion: 5 }) testParseOnly('Version 4 CONACK in Version 5 mode', {  cmd: 'connack',  retain: false,  qos: 0,  dup: false,  length: 2,  topic: null,  payload: null,  sessionPresent: false,  reasonCode: 1 // a version 4 return code stored in the version 5 reasonCode because this client is in version 5}, Buffer.from([  32, 2, // Fixed Header (CONNACK, Remaining Length)  0, 1 // Variable Header (Session not present, Connection Refused - unacceptable protocol version)]), { protocolVersion: 5 }) // message is in version 4 format, but this client is in version 5 mode testParseOnly('Version 5 PUBACK test 1', {  cmd: 'puback',  messageId: 42,  retain: false,  qos: 0,  dup: false,  length: 2,  topic: null,  payload: null,  reasonCode: 0}, Buffer.from([  64, 2, // Fixed Header (PUBACK, Remaining Length)  0, 42 // Variable Header (2 Bytes: Packet Identifier 42, Implied Reason code: Success, Implied no properties)]), { protocolVersion: 5 }) testParseAndGenerate('Version 5 PUBACK test 2', {  cmd: 'puback',  messageId: 42,  retain: false,  qos: 0,  dup: false,  length: 3,  topic: null,  payload: null,  reasonCode: 0}, Buffer.from([  64, 3, // Fixed Header (PUBACK, Remaining Length)  0, 42, 0 // Variable Header (2 Bytes: Packet Identifier 42, Reason code: 0 Success, Implied no properties)]), { protocolVersion: 5 }) testParseOnly('Version 5 PUBACK test 3', {  cmd: 'puback',  messageId: 42,  retain: false,  qos: 0,  dup: false,  length: 4,  topic: null,  payload: null,  reasonCode: 0}, Buffer.from([  64, 4, // Fixed Header (PUBACK, Remaining Length)  0, 42, 0, // Variable Header (2 Bytes: Packet Identifier 42, Reason code: 0 Success)  0 // no properties]), { protocolVersion: 5 }) testParseOnly('Version 5 CONNACK test 1', {  cmd: 'connack',  retain: false,  qos: 0,  dup: false,  length: 1,  topic: null,  payload: null,  sessionPresent: true,  reasonCode: 0}, Buffer.from([  32, 1, // Fixed Header (CONNACK, Remaining Length)  1 // Variable Header (Session Present: 1 => true, Implied Reason code: Success, Implied no properties)]), { protocolVersion: 5 }) testParseOnly('Version 5 CONNACK test 2', {  cmd: 'connack',  retain: false,  qos: 0,  dup: false,  length: 2,  topic: null,  payload: null,  sessionPresent: true,  reasonCode: 0}, Buffer.from([  32, 2, // Fixed Header (CONNACK, Remaining Length)  1, 0 // Variable Header (Session Present: 1 => true, Connect Reason code: Success, Implied no properties)]), { protocolVersion: 5 }) testParseAndGenerate('Version 5 CONNACK test 3', {  cmd: 'connack',  retain: false,  qos: 0,  dup: false,  length: 3,  topic: null,  payload: null,  sessionPresent: true,  reasonCode: 0}, Buffer.from([  32, 3, // Fixed Header (CONNACK, Remaining Length)  1, 0, // Variable Header (Session Present: 1 => true, Connect Reason code: Success)  0 // no properties]), { protocolVersion: 5 }) testParseOnly('Version 5 DISCONNECT test 1', {  cmd: 'disconnect',  retain: false,  qos: 0,  dup: false,  length: 0,  topic: null,  payload: null,  reasonCode: 0}, Buffer.from([  224, 0 // Fixed Header (DISCONNECT, Remaining Length), Implied Reason code: Normal Disconnection]), { protocolVersion: 5 }) testParseOnly('Version 5 DISCONNECT test 2', {  cmd: 'disconnect',  retain: false,  qos: 0,  dup: false,  length: 1,  topic: null,  payload: null,  reasonCode: 0}, Buffer.from([  224, 1, // Fixed Header (DISCONNECT, Remaining Length)  0 // reason Code (Normal disconnection)]), { protocolVersion: 5 }) testParseAndGenerate('Version 5 DISCONNECT test 3', {  cmd: 'disconnect',  retain: false,  qos: 0,  dup: false,  length: 2,  topic: null,  payload: null,  reasonCode: 0}, Buffer.from([  224, 2, // Fixed Header (DISCONNECT, Remaining Length)  0, // reason Code (Normal disconnection)  0 // no properties]), { protocolVersion: 5 }) testParseGenerate('empty will payload', {  cmd: 'connect',  retain: false,  qos: 0,  dup: false,  length: 47,  protocolId: 'MQIsdp',  protocolVersion: 3,  will: {    retain: true,    qos: 2,    topic: 'topic',    payload: Buffer.alloc(0)  },  clean: true,  keepalive: 30,  clientId: 'test',  username: 'username',  password: Buffer.from('password')}, Buffer.from([  16, 47, // Header  0, 6, // Protocol ID length  77, 81, 73, 115, 100, 112, // Protocol ID  3, // Protocol version  246, // Connect flags  0, 30, // Keepalive  0, 4, // Client ID length  116, 101, 115, 116, // Client ID  0, 5, // Will topic length  116, 111, 112, 105, 99, // Will topic  0, 0, // Will payload length  // Will payload  0, 8, // Username length  117, 115, 101, 114, 110, 97, 109, 101, // Username  0, 8, // Password length  112, 97, 115, 115, 119, 111, 114, 100 // Password])) testParseGenerate('empty buffer username payload', {  cmd: 'connect',  retain: false,  qos: 0,  dup: false,  length: 20,  protocolId: 'MQIsdp',  protocolVersion: 3,  clean: true,  keepalive: 30,  clientId: 'test',  username: Buffer.from('')}, Buffer.from([  16, 20, // Header  0, 6, // Protocol ID length  77, 81, 73, 115, 100, 112, // Protocol ID  3, // Protocol version  130, // Connect flags  0, 30, // Keepalive  0, 4, // Client ID length  116, 101, 115, 116, // Client ID  0, 0 // Username length  // Empty Username payload])) testParseGenerate('empty string username payload', {  cmd: 'connect',  retain: false,  qos: 0,  dup: false,  length: 20,  protocolId: 'MQIsdp',  protocolVersion: 3,  clean: true,  keepalive: 30,  clientId: 'test',  username: ''}, Buffer.from([  16, 20, // Header  0, 6, // Protocol ID length  77, 81, 73, 115, 100, 112, // Protocol ID  3, // Protocol version  130, // Connect flags  0, 30, // Keepalive  0, 4, // Client ID length  116, 101, 115, 116, // Client ID  0, 0 // Username length  // Empty Username payload])) testParseGenerate('empty buffer password payload', {  cmd: 'connect',  retain: false,  qos: 0,  dup: false,  length: 30,  protocolId: 'MQIsdp',  protocolVersion: 3,  clean: true,  keepalive: 30,  clientId: 'test',  username: 'username',  password: Buffer.from('')}, Buffer.from([  16, 30, // Header  0, 6, // Protocol ID length  77, 81, 73, 115, 100, 112, // Protocol ID  3, // Protocol version  194, // Connect flags  0, 30, // Keepalive  0, 4, // Client ID length  116, 101, 115, 116, // Client ID  0, 8, // Username length  117, 115, 101, 114, 110, 97, 109, 101, // Username payload  0, 0 // Password length  // Empty password payload])) testParseGenerate('empty string password payload', {  cmd: 'connect',  retain: false,  qos: 0,  dup: false,  length: 30,  protocolId: 'MQIsdp',  protocolVersion: 3,  clean: true,  keepalive: 30,  clientId: 'test',  username: 'username',  password: ''}, Buffer.from([  16, 30, // Header  0, 6, // Protocol ID length  77, 81, 73, 115, 100, 112, // Protocol ID  3, // Protocol version  194, // Connect flags  0, 30, // Keepalive  0, 4, // Client ID length  116, 101, 115, 116, // Client ID  0, 8, // Username length  117, 115, 101, 114, 110, 97, 109, 101, // Username payload  0, 0 // Password length  // Empty password payload])) testParseGenerate('empty string username and password payload', {  cmd: 'connect',  retain: false,  qos: 0,  dup: false,  length: 22,  protocolId: 'MQIsdp',  protocolVersion: 3,  clean: true,  keepalive: 30,  clientId: 'test',  username: '',  password: Buffer.from('')}, Buffer.from([  16, 22, // Header  0, 6, // Protocol ID length  77, 81, 73, 115, 100, 112, // Protocol ID  3, // Protocol version  194, // Connect flags  0, 30, // Keepalive  0, 4, // Client ID length  116, 101, 115, 116, // Client ID  0, 0, // Username length  // Empty Username payload  0, 0 // Password length  // Empty password payload])) testParseGenerate('maximal connect', {  cmd: 'connect',  retain: false,  qos: 0,  dup: false,  length: 54,  protocolId: 'MQIsdp',  protocolVersion: 3,  will: {    retain: true,    qos: 2,    topic: 'topic',    payload: Buffer.from('payload')  },  clean: true,  keepalive: 30,  clientId: 'test',  username: 'username',  password: Buffer.from('password')}, Buffer.from([  16, 54, // Header  0, 6, // Protocol ID length  77, 81, 73, 115, 100, 112, // Protocol ID  3, // Protocol version  246, // Connect flags  0, 30, // Keepalive  0, 4, // Client ID length  116, 101, 115, 116, // Client ID  0, 5, // Will topic length  116, 111, 112, 105, 99, // Will topic  0, 7, // Will payload length  112, 97, 121, 108, 111, 97, 100, // Will payload  0, 8, // Username length  117, 115, 101, 114, 110, 97, 109, 101, // Username  0, 8, // Password length  112, 97, 115, 115, 119, 111, 114, 100 // Password])) testParseGenerate('max connect with special chars', {  cmd: 'connect',  retain: false,  qos: 0,  dup: false,  length: 57,  protocolId: 'MQIsdp',  protocolVersion: 3,  will: {    retain: true,    qos: 2,    topic: 'tòpic',    payload: Buffer.from('pay£oad')  },  clean: true,  keepalive: 30,  clientId: 'te$t',  username: 'u$ern4me',  password: Buffer.from('p4$$w0£d')}, Buffer.from([  16, 57, // Header  0, 6, // Protocol ID length  77, 81, 73, 115, 100, 112, // Protocol ID  3, // Protocol version  246, // Connect flags  0, 30, // Keepalive  0, 4, // Client ID length  116, 101, 36, 116, // Client ID  0, 6, // Will topic length  116, 195, 178, 112, 105, 99, // Will topic  0, 8, // Will payload length  112, 97, 121, 194, 163, 111, 97, 100, // Will payload  0, 8, // Username length  117, 36, 101, 114, 110, 52, 109, 101, // Username  0, 9, // Password length  112, 52, 36, 36, 119, 48, 194, 163, 100 // Password])) testGenerateOnly('connect all strings generate', {  cmd: 'connect',  retain: false,  qos: 0,  dup: false,  length: 54,  protocolId: 'MQIsdp',  protocolVersion: 3,  will: {    retain: true,    qos: 2,    topic: 'topic',    payload: 'payload'  },  clean: true,  keepalive: 30,  clientId: 'test',  username: 'username',  password: 'password'}, Buffer.from([  16, 54, // Header  0, 6, // Protocol ID length  77, 81, 73, 115, 100, 112, // Protocol ID  3, // Protocol version  246, // Connect flags  0, 30, // Keepalive  0, 4, // Client ID length  116, 101, 115, 116, // Client ID  0, 5, // Will topic length  116, 111, 112, 105, 99, // Will topic  0, 7, // Will payload length  112, 97, 121, 108, 111, 97, 100, // Will payload  0, 8, // Username length  117, 115, 101, 114, 110, 97, 109, 101, // Username  0, 8, // Password length  112, 97, 115, 115, 119, 111, 114, 100 // Password])) testParseError('Cannot parse protocolId', Buffer.from([  16, 4,  0, 6,  77, 81])) // missing protocol version on connecttestParseError('Packet too short', Buffer.from([  16, 8, // Header  0, 6, // Protocol ID length  77, 81, 73, 115, 100, 112 // Protocol ID])) // missing keepalive on connecttestParseError('Packet too short', Buffer.from([  16, 10, // Header  0, 6, // Protocol ID length  77, 81, 73, 115, 100, 112, // Protocol ID  3, // Protocol version  246 // Connect flags])) // missing clientid on connecttestParseError('Packet too short', Buffer.from([  16, 10, // Header  0, 6, // Protocol ID length  77, 81, 73, 115, 100, 112, // Protocol ID  3, // Protocol version  246, // Connect flags  0, 30 // Keepalive])) // missing will topic on connecttestParseError('Cannot parse will topic', Buffer.from([  16, 16, // Header  0, 6, // Protocol ID length  77, 81, 73, 115, 100, 112, // Protocol ID  3, // Protocol version  246, // Connect flags  0, 30, // Keepalive  0, 2, // Will topic length  0, 0 // Will topic])) // missing will payload on connecttestParseError('Cannot parse will payload', Buffer.from([  16, 23, // Header  0, 6, // Protocol ID length  77, 81, 73, 115, 100, 112, // Protocol ID  3, // Protocol version  246, // Connect flags  0, 30, // Keepalive  0, 5, // Will topic length  116, 111, 112, 105, 99, // Will topic  0, 2, // Will payload length  0, 0 // Will payload])) // missing username on connecttestParseError('Cannot parse username', Buffer.from([  16, 32, // Header  0, 6, // Protocol ID length  77, 81, 73, 115, 100, 112, // Protocol ID  3, // Protocol version  246, // Connect flags  0, 30, // Keepalive  0, 5, // Will topic length  116, 111, 112, 105, 99, // Will topic  0, 7, // Will payload length  112, 97, 121, 108, 111, 97, 100, // Will payload  0, 2, // Username length  0, 0 // Username])) // missing password on connecttestParseError('Cannot parse password', Buffer.from([  16, 42, // Header  0, 6, // Protocol ID length  77, 81, 73, 115, 100, 112, // Protocol ID  3, // Protocol version  246, // Connect flags  0, 30, // Keepalive  0, 5, // Will topic length  116, 111, 112, 105, 99, // Will topic  0, 7, // Will payload length  112, 97, 121, 108, 111, 97, 100, // Will payload  0, 8, // Username length  117, 115, 101, 114, 110, 97, 109, 101, // Username  0, 2, // Password length  0, 0 // Password])) testParseGenerate('connack with return code 0', {  cmd: 'connack',  retain: false,  qos: 0,  dup: false,  length: 2,  sessionPresent: false,  returnCode: 0}, Buffer.from([  32, 2, 0, 0])) testParseGenerate('connack MQTT 5 with properties', {  cmd: 'connack',  retain: false,  qos: 0,  dup: false,  length: 87,  sessionPresent: false,  reasonCode: 0,  properties: {    sessionExpiryInterval: 1234,    receiveMaximum: 432,    maximumQoS: 2,    retainAvailable: true,    maximumPacketSize: 100,    assignedClientIdentifier: 'test',    topicAliasMaximum: 456,    reasonString: 'test',    userProperties: {      test: 'test'    },    wildcardSubscriptionAvailable: true,    subscriptionIdentifiersAvailable: true,    sharedSubscriptionAvailable: false,    serverKeepAlive: 1234,    responseInformation: 'test',    serverReference: 'test',    authenticationMethod: 'test',    authenticationData: Buffer.from([1, 2, 3, 4])  }}, Buffer.from([  32, 87, 0, 0,  84, // properties length  17, 0, 0, 4, 210, // sessionExpiryInterval  33, 1, 176, // receiveMaximum  36, 2, // Maximum qos  37, 1, // retainAvailable  39, 0, 0, 0, 100, // maximumPacketSize  18, 0, 4, 116, 101, 115, 116, // assignedClientIdentifier  34, 1, 200, // topicAliasMaximum  31, 0, 4, 116, 101, 115, 116, // reasonString  38, 0, 4, 116, 101, 115, 116, 0, 4, 116, 101, 115, 116, // userProperties  40, 1, // wildcardSubscriptionAvailable  41, 1, // subscriptionIdentifiersAvailable  42, 0, // sharedSubscriptionAvailable  19, 4, 210, // serverKeepAlive  26, 0, 4, 116, 101, 115, 116, // responseInformation  28, 0, 4, 116, 101, 115, 116, // serverReference  21, 0, 4, 116, 101, 115, 116, // authenticationMethod  22, 0, 4, 1, 2, 3, 4 // authenticationData]), { protocolVersion: 5 }) testParseGenerate('connack MQTT 5 with properties and doubled user properties', {  cmd: 'connack',  retain: false,  qos: 0,  dup: false,  length: 100,  sessionPresent: false,  reasonCode: 0,  properties: {    sessionExpiryInterval: 1234,    receiveMaximum: 432,    maximumQoS: 2,    retainAvailable: true,    maximumPacketSize: 100,    assignedClientIdentifier: 'test',    topicAliasMaximum: 456,    reasonString: 'test',    userProperties: {      test: ['test', 'test']    },    wildcardSubscriptionAvailable: true,    subscriptionIdentifiersAvailable: true,    sharedSubscriptionAvailable: false,    serverKeepAlive: 1234,    responseInformation: 'test',    serverReference: 'test',    authenticationMethod: 'test',    authenticationData: Buffer.from([1, 2, 3, 4])  }}, Buffer.from([  32, 100, 0, 0,  97, // properties length  17, 0, 0, 4, 210, // sessionExpiryInterval  33, 1, 176, // receiveMaximum  36, 2, // Maximum qos  37, 1, // retainAvailable  39, 0, 0, 0, 100, // maximumPacketSize  18, 0, 4, 116, 101, 115, 116, // assignedClientIdentifier  34, 1, 200, // topicAliasMaximum  31, 0, 4, 116, 101, 115, 116, // reasonString  38, 0, 4, 116, 101, 115, 116, 0, 4, 116, 101, 115, 116,  38, 0, 4, 116, 101, 115, 116, 0, 4, 116, 101, 115, 116, // userProperties  40, 1, // wildcardSubscriptionAvailable  41, 1, // subscriptionIdentifiersAvailable  42, 0, // sharedSubscriptionAvailable  19, 4, 210, // serverKeepAlive  26, 0, 4, 116, 101, 115, 116, // responseInformation  28, 0, 4, 116, 101, 115, 116, // serverReference  21, 0, 4, 116, 101, 115, 116, // authenticationMethod  22, 0, 4, 1, 2, 3, 4 // authenticationData]), { protocolVersion: 5 }) testParseGenerate('connack with return code 0 session present bit set', {  cmd: 'connack',  retain: false,  qos: 0,  dup: false,  length: 2,  sessionPresent: true,  returnCode: 0}, Buffer.from([  32, 2, 1, 0])) testParseGenerate('connack with return code 5', {  cmd: 'connack',  retain: false,  qos: 0,  dup: false,  length: 2,  sessionPresent: false,  returnCode: 5}, Buffer.from([  32, 2, 0, 5])) testGenerateError('Invalid return code', {  cmd: 'connack',  retain: false,  qos: 0,  dup: false,  length: 2,  sessionPresent: false,  returnCode: '5' // returncode must be a number}) testParseGenerate('minimal publish', {  cmd: 'publish',  retain: false,  qos: 0,  dup: false,  length: 10,  topic: 'test',  payload: Buffer.from('test')}, Buffer.from([  48, 10, // Header  0, 4, // Topic length  116, 101, 115, 116, // Topic (test)  116, 101, 115, 116 // Payload (test)])) testParseGenerate('publish MQTT 5 properties', {  cmd: 'publish',  retain: true,  qos: 2,  dup: true,  length: 86,  topic: 'test',  payload: Buffer.from('test'),  messageId: 10,  properties: {    payloadFormatIndicator: true,    messageExpiryInterval: 4321,    topicAlias: 100,    responseTopic: 'topic',    correlationData: Buffer.from([1, 2, 3, 4]),    userProperties: {      test: ['test', 'test', 'test']    },    subscriptionIdentifier: 120,    contentType: 'test'  }}, Buffer.from([  61, 86, // Header  0, 4, // Topic length  116, 101, 115, 116, // Topic (test)  0, 10, // Message ID  73, // properties length  1, 1, // payloadFormatIndicator  2, 0, 0, 16, 225, // message expiry interval  35, 0, 100, // topicAlias  8, 0, 5, 116, 111, 112, 105, 99, // response topic  9, 0, 4, 1, 2, 3, 4, // correlationData  38, 0, 4, 116, 101, 115, 116, 0, 4, 116, 101, 115, 116, // userProperties  38, 0, 4, 116, 101, 115, 116, 0, 4, 116, 101, 115, 116, // userProperties  38, 0, 4, 116, 101, 115, 116, 0, 4, 116, 101, 115, 116, // userProperties  11, 120, // subscriptionIdentifier  3, 0, 4, 116, 101, 115, 116, // content type  116, 101, 115, 116 // Payload (test)]), { protocolVersion: 5 }) testParseGenerate('publish MQTT 5 with multiple same properties', {  cmd: 'publish',  retain: true,  qos: 2,  dup: true,  length: 64,  topic: 'test',  payload: Buffer.from('test'),  messageId: 10,  properties: {    payloadFormatIndicator: true,    messageExpiryInterval: 4321,    topicAlias: 100,    responseTopic: 'topic',    correlationData: Buffer.from([1, 2, 3, 4]),    userProperties: {      test: 'test'    },    subscriptionIdentifier: [120, 121, 122],    contentType: 'test'  }}, Buffer.from([  61, 64, // Header  0, 4, // Topic length  116, 101, 115, 116, // Topic (test)  0, 10, // Message ID  51, // properties length  1, 1, // payloadFormatIndicator  2, 0, 0, 16, 225, // message expiry interval  35, 0, 100, // topicAlias  8, 0, 5, 116, 111, 112, 105, 99, // response topic  9, 0, 4, 1, 2, 3, 4, // correlationData  38, 0, 4, 116, 101, 115, 116, 0, 4, 116, 101, 115, 116, // userProperties  11, 120, // subscriptionIdentifier  11, 121, // subscriptionIdentifier  11, 122, // subscriptionIdentifier  3, 0, 4, 116, 101, 115, 116, // content type  116, 101, 115, 116 // Payload (test)]), { protocolVersion: 5 }) testParseGenerate('publish MQTT 5 properties with 0-4 byte varbyte', {  cmd: 'publish',  retain: true,  qos: 2,  dup: true,  length: 27,  topic: 'test',  payload: Buffer.from('test'),  messageId: 10,  properties: {    payloadFormatIndicator: false,    subscriptionIdentifier: [128, 16384, 2097152] // this tests the varbyte handling  }}, Buffer.from([  61, 27, // Header  0, 4, // Topic length  116, 101, 115, 116, // Topic (test)  0, 10, // Message ID  14, // properties length  1, 0, // payloadFormatIndicator  11, 128, 1, // subscriptionIdentifier  11, 128, 128, 1, // subscriptionIdentifier  11, 128, 128, 128, 1, // subscriptionIdentifier  116, 101, 115, 116 // Payload (test)]), { protocolVersion: 5 }) testParseGenerate('publish MQTT 5 properties with max value varbyte', {  cmd: 'publish',  retain: true,  qos: 2,  dup: true,  length: 22,  topic: 'test',  payload: Buffer.from('test'),  messageId: 10,  properties: {    payloadFormatIndicator: false,    subscriptionIdentifier: [1, 268435455]  }}, Buffer.from([  61, 22, // Header  0, 4, // Topic length  116, 101, 115, 116, // Topic (test)  0, 10, // Message ID  9, // properties length  1, 0, // payloadFormatIndicator  11, 1, // subscriptionIdentifier  11, 255, 255, 255, 127, // subscriptionIdentifier (max value)  116, 101, 115, 116 // Payload (test)]), { protocolVersion: 5 }) ; (() => {  const buffer = Buffer.alloc(2048)  testParseGenerate('2KB publish packet', {    cmd: 'publish',    retain: false,    qos: 0,    dup: false,    length: 2054,    topic: 'test',    payload: buffer  }, Buffer.concat([Buffer.from([    48, 134, 16, // Header    0, 4, // Topic length    116, 101, 115, 116 // Topic (test)  ]), buffer]))})() ; (() => {  const maxLength = 268435455  const buffer = Buffer.alloc(maxLength - 6)  testParseGenerate('Max payload publish packet', {    cmd: 'publish',    retain: false,    qos: 0,    dup: false,    length: maxLength,    topic: 'test',    payload: buffer  }, Buffer.concat([Buffer.from([    48, 255, 255, 255, 127, // Header    0, 4, // Topic length    116, 101, 115, 116 // Topic (test)  ]), buffer]))})() testParseGenerate('maximal publish', {  cmd: 'publish',  retain: true,  qos: 2,  length: 12,  dup: true,  topic: 'test',  messageId: 10,  payload: Buffer.from('test')}, Buffer.from([  61, 12, // Header  0, 4, // Topic length  116, 101, 115, 116, // Topic  0, 10, // Message ID  116, 101, 115, 116 // Payload])) test('publish all strings generate', t => {  const message = {    cmd: 'publish',    retain: true,    qos: 2,    length: 12,    dup: true,    topic: 'test',    messageId: 10,    payload: Buffer.from('test')  }  const expected = Buffer.from([    61, 12, // Header    0, 4, // Topic length    116, 101, 115, 116, // Topic    0, 10, // Message ID    116, 101, 115, 116 // Payload  ])   t.equal(mqtt.generate(message).toString('hex'), expected.toString('hex'))  t.end()}) testParseGenerate('empty publish', {  cmd: 'publish',  retain: false,  qos: 0,  dup: false,  length: 6,  topic: 'test',  payload: Buffer.alloc(0)}, Buffer.from([  48, 6, // Header  0, 4, // Topic length  116, 101, 115, 116 // Topic  // Empty payload])) test('splitted publish parse', t => {  t.plan(3)   const parser = mqtt.parser()  const expected = {    cmd: 'publish',    retain: false,    qos: 0,    dup: false,    length: 10,    topic: 'test',    payload: Buffer.from('test')  }   parser.on('packet', packet => {    t.deepLooseEqual(packet, expected, 'expected packet')  })   t.equal(parser.parse(Buffer.from([    48, 10, // Header    0, 4, // Topic length    116, 101, 115, 116 // Topic (test)  ])), 6, 'remaining bytes')   t.equal(parser.parse(Buffer.from([    116, 101, 115, 116 // Payload (test)  ])), 0, 'remaining bytes')}) test('split publish longer', t => {  t.plan(3)   const length = 255  const topic = 'test'  // Minus two bytes for the topic length specifier  const payloadLength = length - topic.length - 2   const parser = mqtt.parser()  const expected = {    cmd: 'publish',    retain: false,    qos: 0,    dup: false,    length: length,    topic: topic,    payload: Buffer.from('a'.repeat(payloadLength))  }   parser.on('packet', packet => {    t.deepLooseEqual(packet, expected, 'expected packet')  })   t.equal(parser.parse(Buffer.from([    48, 255, 1, // Header    0, topic.length, // Topic length    116, 101, 115, 116 // Topic (test)  ])), 6, 'remaining bytes')   t.equal(parser.parse(Buffer.from(Array(payloadLength).fill(97))),    0, 'remaining bytes')}) test('split length parse', t => {  t.plan(4)   const length = 255  const topic = 'test'  const payloadLength = length - topic.length - 2   const parser = mqtt.parser()  const expected = {    cmd: 'publish',    retain: false,    qos: 0,    dup: false,    length: length,    topic: topic,    payload: Buffer.from('a'.repeat(payloadLength))  }   parser.on('packet', packet => {    t.deepLooseEqual(packet, expected, 'expected packet')  })   t.equal(parser.parse(Buffer.from([    48, 255 // Header (partial length)  ])), 1, 'remaining bytes')   t.equal(parser.parse(Buffer.from([    1, // Rest of header length    0, topic.length, // Topic length    116, 101, 115, 116 // Topic (test)  ])), 6, 'remaining bytes')   t.equal(parser.parse(Buffer.from(Array(payloadLength).fill(97))),    0, 'remaining bytes')}) testGenerateError('Invalid variable byte integer: 268435456', {  cmd: 'publish',  retain: false,  qos: 0,  dup: false,  length: (268435455 + 1),  topic: 'test',  payload: Buffer.alloc(268435455 + 1 - 6)}, {}, 'Length var byte integer over max allowed value throws error') testGenerateError('Invalid subscriptionIdentifier: 268435456', {  cmd: 'publish',  retain: true,  qos: 2,  dup: true,  length: 27,  topic: 'test',  payload: Buffer.from('test'),  messageId: 10,  properties: {    payloadFormatIndicator: false,    subscriptionIdentifier: 268435456  }}, { protocolVersion: 5 }, 'MQTT 5.0 var byte integer >24 bits throws error') testParseGenerate('puback', {  cmd: 'puback',  retain: false,  qos: 0,  dup: false,  length: 2,  messageId: 2}, Buffer.from([  64, 2, // Header  0, 2 // Message ID])) testParseGenerate('puback with reason and no MQTT 5 properties', {  cmd: 'puback',  retain: false,  qos: 0,  dup: false,  length: 3,  messageId: 2,  reasonCode: 16}, Buffer.from([  64, 3, // Header  0, 2, // Message ID  16 // reason code]), { protocolVersion: 5 }) testParseGenerate('puback MQTT 5 properties', {  cmd: 'puback',  retain: false,  qos: 0,  dup: false,  length: 24,  messageId: 2,  reasonCode: 16,  properties: {    reasonString: 'test',    userProperties: {      test: 'test'    }  }}, Buffer.from([  64, 24, // Header  0, 2, // Message ID  16, // reason code  20, // properties length  31, 0, 4, 116, 101, 115, 116, // reasonString  38, 0, 4, 116, 101, 115, 116, 0, 4, 116, 101, 115, 116 // userProperties]), { protocolVersion: 5 }) testParseGenerate('pubrec', {  cmd: 'pubrec',  retain: false,  qos: 0,  dup: false,  length: 2,  messageId: 2}, Buffer.from([  80, 2, // Header  0, 2 // Message ID])) testParseGenerate('pubrec MQTT 5 properties', {  cmd: 'pubrec',  retain: false,  qos: 0,  dup: false,  length: 24,  messageId: 2,  reasonCode: 16,  properties: {    reasonString: 'test',    userProperties: {      test: 'test'    }  }}, Buffer.from([  80, 24, // Header  0, 2, // Message ID  16, // reason code  20, // properties length  31, 0, 4, 116, 101, 115, 116, // reasonString  38, 0, 4, 116, 101, 115, 116, 0, 4, 116, 101, 115, 116 // userProperties]), { protocolVersion: 5 }) testParseGenerate('pubrel', {  cmd: 'pubrel',  retain: false,  qos: 1,  dup: false,  length: 2,  messageId: 2}, Buffer.from([  98, 2, // Header  0, 2 // Message ID])) testParseGenerate('pubrel MQTT5 properties', {  cmd: 'pubrel',  retain: false,  qos: 1,  dup: false,  length: 24,  messageId: 2,  reasonCode: 16,  properties: {    reasonString: 'test',    userProperties: {      test: 'test'    }  }}, Buffer.from([  98, 24, // Header  0, 2, // Message ID  16, // reason code  20, // properties length  31, 0, 4, 116, 101, 115, 116, // reasonString  38, 0, 4, 116, 101, 115, 116, 0, 4, 116, 101, 115, 116 // userProperties]), { protocolVersion: 5 }) testParseGenerate('pubcomp', {  cmd: 'pubcomp',  retain: false,  qos: 0,  dup: false,  length: 2,  messageId: 2}, Buffer.from([  112, 2, // Header  0, 2 // Message ID])) testParseGenerate('pubcomp MQTT 5 properties', {  cmd: 'pubcomp',  retain: false,  qos: 0,  dup: false,  length: 24,  messageId: 2,  reasonCode: 16,  properties: {    reasonString: 'test',    userProperties: {      test: 'test'    }  }}, Buffer.from([  112, 24, // Header  0, 2, // Message ID  16, // reason code  20, // properties length  31, 0, 4, 116, 101, 115, 116, // reasonString  38, 0, 4, 116, 101, 115, 116, 0, 4, 116, 101, 115, 116 // userProperties]), { protocolVersion: 5 }) testParseError('Wrong subscribe header', Buffer.from([  128, 9, // Header (subscribeqos=0length=9)  0, 6, // Message ID (6)  0, 4, // Topic length,  116, 101, 115, 116, // Topic (test)  0 // Qos (0)])) testParseGenerate('subscribe to one topic', {  cmd: 'subscribe',  retain: false,  qos: 1,  dup: false,  length: 9,  subscriptions: [    {      topic: 'test',      qos: 0    }  ],  messageId: 6}, Buffer.from([  130, 9, // Header (subscribeqos=1length=9)  0, 6, // Message ID (6)  0, 4, // Topic length,  116, 101, 115, 116, // Topic (test)  0 // Qos (0)])) testParseGenerate('subscribe to one topic by MQTT 5', {  cmd: 'subscribe',  retain: false,  qos: 1,  dup: false,  length: 26,  subscriptions: [    {      topic: 'test',      qos: 0,      nl: false,      rap: true,      rh: 1    }  ],  messageId: 6,  properties: {    subscriptionIdentifier: 145,    userProperties: {      test: 'test'    }  }}, Buffer.from([  130, 26, // Header (subscribeqos=1length=9)  0, 6, // Message ID (6)  16, // properties length  11, 145, 1, // subscriptionIdentifier  38, 0, 4, 116, 101, 115, 116, 0, 4, 116, 101, 115, 116, // userProperties  0, 4, // Topic length,  116, 101, 115, 116, // Topic (test)  24 // settings(qos: 0, noLocal: false, Retain as Published: true, retain handling: 1)]), { protocolVersion: 5 }) testParseGenerate('subscribe to three topics', {  cmd: 'subscribe',  retain: false,  qos: 1,  dup: false,  length: 23,  subscriptions: [    {      topic: 'test',      qos: 0    }, {      topic: 'uest',      qos: 1    }, {      topic: 'tfst',      qos: 2    }  ],  messageId: 6}, Buffer.from([  130, 23, // Header (publishqos=1length=9)  0, 6, // Message ID (6)  0, 4, // Topic length,  116, 101, 115, 116, // Topic (test)  0, // Qos (0)  0, 4, // Topic length  117, 101, 115, 116, // Topic (uest)  1, // Qos (1)  0, 4, // Topic length  116, 102, 115, 116, // Topic (tfst)  2 // Qos (2)])) testParseGenerate('subscribe to 3 topics by MQTT 5', {  cmd: 'subscribe',  retain: false,  qos: 1,  dup: false,  length: 40,  subscriptions: [    {      topic: 'test',      qos: 0,      nl: false,      rap: true,      rh: 1    },    {      topic: 'uest',      qos: 1,      nl: false,      rap: false,      rh: 0    }, {      topic: 'tfst',      qos: 2,      nl: true,      rap: false,      rh: 0    }  ],  messageId: 6,  properties: {    subscriptionIdentifier: 145,    userProperties: {      test: 'test'    }  }}, Buffer.from([  130, 40, // Header (subscribeqos=1length=9)  0, 6, // Message ID (6)  16, // properties length  11, 145, 1, // subscriptionIdentifier  38, 0, 4, 116, 101, 115, 116, 0, 4, 116, 101, 115, 116, // userProperties  0, 4, // Topic length,  116, 101, 115, 116, // Topic (test)  24, // settings(qos: 0, noLocal: false, Retain as Published: true, retain handling: 1)  0, 4, // Topic length  117, 101, 115, 116, // Topic (uest)  1, // Qos (1)  0, 4, // Topic length  116, 102, 115, 116, // Topic (tfst)  6 // Qos (2), No Local: true]), { protocolVersion: 5 }) testParseGenerate('suback', {  cmd: 'suback',  retain: false,  qos: 0,  dup: false,  length: 6,  granted: [0, 1, 2, 128],  messageId: 6}, Buffer.from([  144, 6, // Header  0, 6, // Message ID  0, 1, 2, 128 // Granted qos (0, 1, 2) and a rejected being 0x80])) testParseGenerate('suback MQTT 5', {  cmd: 'suback',  retain: false,  qos: 0,  dup: false,  length: 27,  granted: [0, 1, 2, 128],  messageId: 6,  properties: {    reasonString: 'test',    userProperties: {      test: 'test'    }  }}, Buffer.from([  144, 27, // Header  0, 6, // Message ID  20, // properties length  31, 0, 4, 116, 101, 115, 116, // reasonString  38, 0, 4, 116, 101, 115, 116, 0, 4, 116, 101, 115, 116, // userProperties  0, 1, 2, 128 // Granted qos (0, 1, 2) and a rejected being 0x80]), { protocolVersion: 5 }) testParseGenerate('unsubscribe', {  cmd: 'unsubscribe',  retain: false,  qos: 1,  dup: false,  length: 14,  unsubscriptions: [    'tfst',    'test'  ],  messageId: 7}, Buffer.from([  162, 14,  0, 7, // Message ID (7)  0, 4, // Topic length  116, 102, 115, 116, // Topic (tfst)  0, 4, // Topic length,  116, 101, 115, 116 // Topic (test)])) testGenerateError('Invalid unsubscriptions', {  cmd: 'unsubscribe',  retain: false,  qos: 1,  dup: true,  length: 5,  unsubscriptions: 5,  messageId: 7}, {}, 'unsubscribe with unsubscriptions not an array') testGenerateError('Invalid unsubscriptions', {  cmd: 'unsubscribe',  retain: false,  qos: 1,  dup: true,  length: 5,  unsubscriptions: [1, 2],  messageId: 7}, {}, 'unsubscribe with unsubscriptions as an object') testParseGenerate('unsubscribe MQTT 5', {  cmd: 'unsubscribe',  retain: false,  qos: 1,  dup: false,  length: 28,  unsubscriptions: [    'tfst',    'test'  ],  messageId: 7,  properties: {    userProperties: {      test: 'test'    }  }}, Buffer.from([  162, 28,  0, 7, // Message ID (7)  13, // properties length  38, 0, 4, 116, 101, 115, 116, 0, 4, 116, 101, 115, 116, // userProperties  0, 4, // Topic length  116, 102, 115, 116, // Topic (tfst)  0, 4, // Topic length,  116, 101, 115, 116 // Topic (test)]), { protocolVersion: 5 }) testParseGenerate('unsuback', {  cmd: 'unsuback',  retain: false,  qos: 0,  dup: false,  length: 2,  messageId: 8}, Buffer.from([  176, 2, // Header  0, 8 // Message ID])) testParseGenerate('unsuback MQTT 5', {  cmd: 'unsuback',  retain: false,  qos: 0,  dup: false,  length: 25,  messageId: 8,  properties: {    reasonString: 'test',    userProperties: {      test: 'test'    }  },  granted: [0, 128]}, Buffer.from([  176, 25, // Header  0, 8, // Message ID  20, // properties length  31, 0, 4, 116, 101, 115, 116, // reasonString  38, 0, 4, 116, 101, 115, 116, 0, 4, 116, 101, 115, 116, // userProperties  0, 128 // success and error]), { protocolVersion: 5 }) testParseGenerate('pingreq', {  cmd: 'pingreq',  retain: false,  qos: 0,  dup: false,  length: 0}, Buffer.from([  192, 0 // Header])) testParseGenerate('pingresp', {  cmd: 'pingresp',  retain: false,  qos: 0,  dup: false,  length: 0}, Buffer.from([  208, 0 // Header])) testParseGenerate('disconnect', {  cmd: 'disconnect',  retain: false,  qos: 0,  dup: false,  length: 0}, Buffer.from([  224, 0 // Header])) testParseGenerate('disconnect MQTT 5', {  cmd: 'disconnect',  retain: false,  qos: 0,  dup: false,  length: 34,  reasonCode: 0,  properties: {    sessionExpiryInterval: 145,    reasonString: 'test',    userProperties: {      test: 'test'    },    serverReference: 'test'  }}, Buffer.from([  224, 34, // Header  0, // reason code  32, // properties length  17, 0, 0, 0, 145, // sessionExpiryInterval  31, 0, 4, 116, 101, 115, 116, // reasonString  38, 0, 4, 116, 101, 115, 116, 0, 4, 116, 101, 115, 116, // userProperties  28, 0, 4, 116, 101, 115, 116// serverReference]), { protocolVersion: 5 }) testParseGenerate('disconnect MQTT 5 with no properties', {  cmd: 'disconnect',  retain: false,  qos: 0,  dup: false,  length: 2,  reasonCode: 0}, Buffer.from([  224, 2, // Fixed Header (DISCONNECT, Remaining Length)  0, // Reason Code (Normal Disconnection)  0 // Property Length (0 => No Properties)]), { protocolVersion: 5 }) testParseGenerate('auth MQTT 5', {  cmd: 'auth',  retain: false,  qos: 0,  dup: false,  length: 36,  reasonCode: 0,  properties: {    authenticationMethod: 'test',    authenticationData: Buffer.from([0, 1, 2, 3]),    reasonString: 'test',    userProperties: {      test: 'test'    }  }}, Buffer.from([  240, 36, // Header  0, // reason code  34, // properties length  21, 0, 4, 116, 101, 115, 116, // auth method  22, 0, 4, 0, 1, 2, 3, // auth data  31, 0, 4, 116, 101, 115, 116, // reasonString  38, 0, 4, 116, 101, 115, 116, 0, 4, 116, 101, 115, 116 // userProperties]), { protocolVersion: 5 }) testGenerateError('Invalid protocolId', {  cmd: 'connect',  retain: false,  qos: 0,  dup: false,  length: 54,  protocolId: 42,  protocolVersion: 3,  will: {    retain: true,    qos: 2,    topic: 'topic',    payload: 'payload'  },  clean: true,  keepalive: 30,  clientId: 'test',  username: 'username',  password: 'password'}) testGenerateError('Invalid protocol version', {  cmd: 'connect',  retain: false,  qos: 0,  dup: false,  length: 54,  protocolId: 'MQIsdp',  protocolVersion: 1,  will: {    retain: true,    qos: 2,    topic: 'topic',    payload: 'payload'  },  clean: true,  keepalive: 30,  clientId: 'test',  username: 'username',  password: 'password'}) testGenerateError('clientId must be supplied before 3.1.1', {  cmd: 'connect',  retain: false,  qos: 0,  dup: false,  length: 54,  protocolId: 'MQIsdp',  protocolVersion: 3,  will: {    retain: true,    qos: 2,    topic: 'topic',    payload: 'payload'  },  clean: true,  keepalive: 30,  username: 'username',  password: 'password'}) testGenerateError('clientId must be given if cleanSession set to 0', {  cmd: 'connect',  retain: false,  qos: 0,  dup: false,  length: 54,  protocolId: 'MQTT',  protocolVersion: 4,  will: {    retain: true,    qos: 2,    topic: 'topic',    payload: 'payload'  },  clean: false,  keepalive: 30,  username: 'username',  password: 'password'}) testGenerateError('Invalid keepalive', {  cmd: 'connect',  retain: false,  qos: 0,  dup: false,  length: 54,  protocolId: 'MQIsdp',  protocolVersion: 3,  will: {    retain: true,    qos: 2,    topic: 'topic',    payload: 'payload'  },  clean: true,  keepalive: 'hello',  clientId: 'test',  username: 'username',  password: 'password'}) testGenerateError('Invalid keepalive', {  cmd: 'connect',  keepalive: 3.1416}) testGenerateError('Invalid will', {  cmd: 'connect',  retain: false,  qos: 0,  dup: false,  length: 54,  protocolId: 'MQIsdp',  protocolVersion: 3,  will: 42,  clean: true,  keepalive: 30,  clientId: 'test',  username: 'username',  password: 'password'}) testGenerateError('Invalid will topic', {  cmd: 'connect',  retain: false,  qos: 0,  dup: false,  length: 54,  protocolId: 'MQIsdp',  protocolVersion: 3,  will: {    retain: true,    qos: 2,    payload: 'payload'  },  clean: true,  keepalive: 30,  clientId: 'test',  username: 'username',  password: 'password'}) testGenerateError('Invalid will payload', {  cmd: 'connect',  retain: false,  qos: 0,  dup: false,  length: 54,  protocolId: 'MQIsdp',  protocolVersion: 3,  will: {    retain: true,    qos: 2,    topic: 'topic',    payload: 42  },  clean: true,  keepalive: 30,  clientId: 'test',  username: 'username',  password: 'password'}) testGenerateError('Invalid username', {  cmd: 'connect',  retain: false,  qos: 0,  dup: false,  length: 54,  protocolId: 'MQIsdp',  protocolVersion: 3,  will: {    retain: true,    qos: 2,    topic: 'topic',    payload: 'payload'  },  clean: true,  keepalive: 30,  clientId: 'test',  username: 42,  password: 'password'}) testGenerateError('Invalid password', {  cmd: 'connect',  retain: false,  qos: 0,  dup: false,  length: 54,  protocolId: 'MQIsdp',  protocolVersion: 3,  will: {    retain: true,    qos: 2,    topic: 'topic',    payload: 'payload'  },  clean: true,  keepalive: 30,  clientId: 'test',  username: 'username',  password: 42}) testGenerateError('Username is required to use password', {  cmd: 'connect',  retain: false,  qos: 0,  dup: false,  length: 54,  protocolId: 'MQIsdp',  protocolVersion: 3,  will: {    retain: true,    qos: 2,    topic: 'topic',    payload: 'payload'  },  clean: true,  keepalive: 30,  clientId: 'test',  password: 'password'}) testGenerateError('Invalid messageExpiryInterval: -4321', {  cmd: 'publish',  retain: true,  qos: 2,  dup: true,  length: 60,  topic: 'test',  payload: Buffer.from('test'),  messageId: 10,  properties: {    payloadFormatIndicator: true,    messageExpiryInterval: -4321,    topicAlias: 100,    responseTopic: 'topic',    correlationData: Buffer.from([1, 2, 3, 4]),    userProperties: {      test: 'test'    },    subscriptionIdentifier: 120,    contentType: 'test'  }}, { protocolVersion: 5 }) testGenerateError('Invalid topicAlias: -100', {  cmd: 'publish',  retain: true,  qos: 2,  dup: true,  length: 60,  topic: 'test',  payload: Buffer.from('test'),  messageId: 10,  properties: {    payloadFormatIndicator: true,    messageExpiryInterval: 4321,    topicAlias: -100,    responseTopic: 'topic',    correlationData: Buffer.from([1, 2, 3, 4]),    userProperties: {      test: 'test'    },    subscriptionIdentifier: 120,    contentType: 'test'  }}, { protocolVersion: 5 }) testGenerateError('Invalid subscriptionIdentifier: -120', {  cmd: 'publish',  retain: true,  qos: 2,  dup: true,  length: 60,  topic: 'test',  payload: Buffer.from('test'),  messageId: 10,  properties: {    payloadFormatIndicator: true,    messageExpiryInterval: 4321,    topicAlias: 100,    responseTopic: 'topic',    correlationData: Buffer.from([1, 2, 3, 4]),    userProperties: {      test: 'test'    },    subscriptionIdentifier: -120,    contentType: 'test'  }}, { protocolVersion: 5 }) test('support cork', t => {  t.plan(9)   const dest = WS()   dest._write = (chunk, enc, cb) => {    t.pass('_write called')    cb()  }   mqtt.writeToStream({    cmd: 'connect',    retain: false,    qos: 0,    dup: false,    length: 18,    protocolId: 'MQIsdp',    protocolVersion: 3,    clean: false,    keepalive: 30,    clientId: 'test'  }, dest)   dest.end()}) // The following test case was designed after experiencing errors// when trying to connect with tls on a non tls mqtt port// the specific behaviour is:// - first byte suggests this is a connect message// - second byte suggests message length to be smaller than buffer length//   thus payload processing starts// - the first two bytes suggest a protocol identifier string length//   that leads the parser pointer close to the end of the buffer// - when trying to read further connect flags the buffer produces//   a "out of range" Error//testParseError('Packet too short', Buffer.from([  16, 9,  0, 6,  77, 81, 73, 115, 100, 112,  3])) // CONNECT Packets that show other protocol IDs than// the valid values MQTT and MQIsdp should cause an error// those packets are a hint that this is not a mqtt connectiontestParseError('Invalid protocolId', Buffer.from([  16, 18,  0, 6,  65, 65, 65, 65, 65, 65, // AAAAAA  3, // Protocol version  0, // Connect flags  0, 10, // Keepalive  0, 4, // Client ID length  116, 101, 115, 116 // Client ID])) // CONNECT Packets that contain an unsupported protocol version// Flag (i.e. not `3` or `4` or '5') should cause an errortestParseError('Invalid protocol version', Buffer.from([  16, 18,  0, 6,  77, 81, 73, 115, 100, 112, // Protocol ID  1, // Protocol version  0, // Connect flags  0, 10, // Keepalive  0, 4, // Client ID length  116, 101, 115, 116 // Client ID])) // When a packet contains a string in the variable header and the// given string length of this exceeds the overall length of the packet that// was specified in the fixed header, parsing must fail.// this case simulates this behavior with the protocol ID string of the// CONNECT packet. The fixed header suggests a remaining length of 8 bytes// which would be exceeded by the string length of 15// in this case, a protocol ID parse error is expectedtestParseError('Cannot parse protocolId', Buffer.from([  16, 8, // Fixed header  0, 15, // string length 15 --> 15 > 8 --> error!  77, 81, 73, 115, 100, 112,  77, 81, 73, 115, 100, 112,  77, 81, 73, 115, 100, 112,  77, 81, 73, 115, 100, 112,  77, 81, 73, 115, 100, 112,  77, 81, 73, 115, 100, 112,  77, 81, 73, 115, 100, 112,  77, 81, 73, 115, 100, 112])) testParseError('Unknown property', Buffer.from([  61, 60, // Header  0, 4, // Topic length  116, 101, 115, 116, // Topic (test)  0, 10, // Message ID  47, // properties length  126, 1, // unknown property  2, 0, 0, 16, 225, // message expiry interval  35, 0, 100, // topicAlias  8, 0, 5, 116, 111, 112, 105, 99, // response topic  9, 0, 4, 1, 2, 3, 4, // correlationData  38, 0, 4, 116, 101, 115, 116, 0, 4, 116, 101, 115, 116, // userProperties  11, 120, // subscriptionIdentifier  3, 0, 4, 116, 101, 115, 116, // content type  116, 101, 115, 116 // Payload (test)]), { protocolVersion: 5 }) testParseError('Not supported auth packet for this version MQTT', Buffer.from([  240, 36, // Header  0, // reason code  34, // properties length  21, 0, 4, 116, 101, 115, 116, // auth method  22, 0, 4, 0, 1, 2, 3, // auth data  31, 0, 4, 116, 101, 115, 116, // reasonString  38, 0, 4, 116, 101, 115, 116, 0, 4, 116, 101, 115, 116 // userProperties])) // When a Subscribe packet contains a topic_filter and the given// length is topic_filter.length + 1 then the last byte (requested QoS) is interpreted as topic_filter// reading the requested_qos at the end causes 'Index out of range' readtestParseError('Malformed Subscribe Payload', Buffer.from([  130, 14, // subscribe header and remaining length  0, 123, // packet ID  0, 10, // topic filter length  104, 105, 106, 107, 108, 47, 109, 110, 111, // topic filter with length of 9 bytes  0 // requested QoS])) test('Cannot parse property code type', t => {  const packets = Buffer.from([    16, 16, 0, 4, 77, 81, 84, 84, 5, 2, 0, 60, 3, 33, 0, 20, 0, 0, 98, 2, 211, 1, 224, 2, 0, 32  ])   t.plan(3)   const parser = mqtt.parser()   parser.on('error', err => {    t.equal(err.message, 'Cannot parse property code type', 'expected error message')    t.end()  })   parser.on('packet', (packet) => {    t.pass('Packet parsed')  })   parser.parse(packets)}) testWriteToStreamError('Invalid command', {  cmd: 'invalid'}) testWriteToStreamError('Invalid protocolId', {  cmd: 'connect',  protocolId: {}}) test('userProperties null prototype', t => {  t.plan(3)   const packet = mqtt.generate({    cmd: 'connect',    retain: false,    qos: 0,    dup: false,    length: 125,    protocolId: 'MQTT',    protocolVersion: 5,    will: {      retain: true,      qos: 2,      properties: {        willDelayInterval: 1234,        payloadFormatIndicator: false,        messageExpiryInterval: 4321,        contentType: 'test',        responseTopic: 'topic',        correlationData: Buffer.from([1, 2, 3, 4]),        userProperties: {          test: 'test'        }      },      topic: 'topic',      payload: Buffer.from([4, 3, 2, 1])    },    clean: true,    keepalive: 30,    properties: {      sessionExpiryInterval: 1234,      receiveMaximum: 432,      maximumPacketSize: 100,      topicAliasMaximum: 456,      requestResponseInformation: true,      requestProblemInformation: true,      userProperties: {        test: 'test'      },      authenticationMethod: 'test',      authenticationData: Buffer.from([1, 2, 3, 4])    },    clientId: 'test'  })   const parser = mqtt.parser()   parser.on('packet', packet => {    t.equal(packet.cmd, 'connect')    t.equal(Object.getPrototypeOf(packet.properties.userProperties), null)    t.equal(Object.getPrototypeOf(packet.will.properties.userProperties), null)  })   parser.parse(packet)}) test('stops parsing after first error', t => {  t.plan(4)   const parser = mqtt.parser()   let packetCount = 0  let errorCount = 0  let expectedPackets = 1  let expectedErrors = 1   parser.on('packet', packet => {    t.ok(++packetCount <= expectedPackets, `expected <= ${expectedPackets} packets`)  })   parser.on('error', erroneous => {    t.ok(++errorCount <= expectedErrors, `expected <= ${expectedErrors} errors`)  })   parser.parse(Buffer.from([    // First, a valid connect packet:     16, 12, // Header    0, 4, // Protocol ID length    77, 81, 84, 84, // Protocol ID    4, // Protocol version    2, // Connect flags    0, 30, // Keepalive    0, 0, // Client ID length     // Then an invalid subscribe packet:     128, 9, // Header (subscribeqos=0length=9)    0, 6, // Message ID (6)    0, 4, // Topic length,    116, 101, 115, 116, // Topic (test)    0, // Qos (0)     // And another invalid subscribe packet:     128, 9, // Header (subscribeqos=0length=9)    0, 6, // Message ID (6)    0, 4, // Topic length,    116, 101, 115, 116, // Topic (test)    0, // Qos (0)     // Finally, a valid disconnect packet:     224, 0 // Header  ]))   // Calling parse again clears the error and continues parsing  packetCount = 0  errorCount = 0  expectedPackets = 2  expectedErrors = 0   parser.parse(Buffer.from([    // Connect:     16, 12, // Header    0, 4, // Protocol ID length    77, 81, 84, 84, // Protocol ID    4, // Protocol version    2, // Connect flags    0, 30, // Keepalive    0, 0, // Client ID length     // Disconnect:     224, 0 // Header  ]))}) testGenerateErrorMultipleCmds([  'publish',  'puback',  'pubrec',  'pubrel',  'subscribe',  'suback',  'unsubscribe',  'unsuback'], 'Invalid messageId', {  qos: 1, // required for publish  topic: 'test', // required for publish  messageId: 'a'}, {})