From 05a939d1ed6922e2f8a7689bcb4c4e14e56137ff Mon Sep 17 00:00:00 2001 From: Daniel Lando Date: Mon, 18 Sep 2023 18:13:04 +0200 Subject: [PATCH 01/26] refactor: replace `mocha` with `node:test` --- .eslintrc.js | 1 - package-lock.json | 402 +--- package.json | 4 +- test/abstract_client.ts | 446 ++-- test/abstract_store.ts | 17 +- test/client.ts | 807 ++++---- test/client_mqtt5.ts | 2275 +++++++++++---------- test/message-id-provider.ts | 21 +- test/mqtt.ts | 39 +- test/mqtt_store.ts | 4 +- test/secure_client.ts | 13 +- test/store.ts | 1 + test/unique_message_id_provider_client.ts | 1 + test/websocket_client.ts | 124 +- 14 files changed, 2010 insertions(+), 2145 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index 0d1652d95..56275b1cb 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -6,7 +6,6 @@ module.exports = { commonjs: true, es2021: true, node: true, - mocha: true, }, extends: [ 'airbnb-base', diff --git a/package-lock.json b/package-lock.json index 8c8c8e64a..8e364e935 100644 --- a/package-lock.json +++ b/package-lock.json @@ -35,7 +35,6 @@ "@release-it/conventional-changelog": "^7.0.0", "@types/chai": "^4.3.5", "@types/duplexify": "^3.6.1", - "@types/mocha": "^10.0.1", "@types/node": "^20.5.0", "@types/sinon": "^10.0.16", "@types/tape": "^5.6.0", @@ -57,7 +56,6 @@ "eslint-plugin-prettier": "^5.0.0", "global": "^4.4.0", "mkdirp": "^3.0.1", - "mocha": "^10.2.0", "mqtt-connection": "^4.1.0", "mqtt-level-store": "^3.1.0", "nyc": "^15.1.0", @@ -1360,12 +1358,6 @@ "integrity": "sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ==", "dev": true }, - "node_modules/@types/mocha": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-10.0.1.tgz", - "integrity": "sha512-/fvYntiO1GeICvqbQ3doGDIP97vWmvFt83GKguJ6prmQM2iXZfFcq6YE8KteFyRtX2/h5Hf91BYvPodJKFYv5Q==", - "dev": true - }, "node_modules/@types/node": { "version": "20.5.1", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.5.1.tgz", @@ -2186,15 +2178,6 @@ "string-width": "^4.1.0" } }, - "node_modules/ansi-colors": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", - "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, "node_modules/ansi-escapes": { "version": "4.3.2", "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", @@ -2980,12 +2963,6 @@ "resolve": "^1.17.0" } }, - "node_modules/browser-stdout": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", - "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", - "dev": true - }, "node_modules/browserify": { "version": "17.0.0", "resolved": "https://registry.npmjs.org/browserify/-/browserify-17.0.0.tgz", @@ -4763,15 +4740,6 @@ "node": ">=0.8.0" } }, - "node_modules/diff": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", - "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", - "dev": true, - "engines": { - "node": ">=0.3.1" - } - }, "node_modules/diffie-hellman": { "version": "5.0.3", "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", @@ -6182,15 +6150,6 @@ "node": ">=10" } }, - "node_modules/flat": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", - "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", - "dev": true, - "bin": { - "flat": "cli.js" - } - }, "node_modules/flat-cache": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", @@ -6341,6 +6300,20 @@ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, "node_modules/function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", @@ -7012,15 +6985,6 @@ "node": ">=8" } }, - "node_modules/he": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", - "dev": true, - "bin": { - "he": "bin/he" - } - }, "node_modules/help-me": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/help-me/-/help-me-4.2.0.tgz", @@ -7961,15 +7925,6 @@ "node": ">=8" } }, - "node_modules/is-plain-obj": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", - "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/is-plain-object": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", @@ -9707,103 +9662,6 @@ "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", "dev": true }, - "node_modules/mocha": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.2.0.tgz", - "integrity": "sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg==", - "dev": true, - "dependencies": { - "ansi-colors": "4.1.1", - "browser-stdout": "1.3.1", - "chokidar": "3.5.3", - "debug": "4.3.4", - "diff": "5.0.0", - "escape-string-regexp": "4.0.0", - "find-up": "5.0.0", - "glob": "7.2.0", - "he": "1.2.0", - "js-yaml": "4.1.0", - "log-symbols": "4.1.0", - "minimatch": "5.0.1", - "ms": "2.1.3", - "nanoid": "3.3.3", - "serialize-javascript": "6.0.0", - "strip-json-comments": "3.1.1", - "supports-color": "8.1.1", - "workerpool": "6.2.1", - "yargs": "16.2.0", - "yargs-parser": "20.2.4", - "yargs-unparser": "2.0.0" - }, - "bin": { - "_mocha": "bin/_mocha", - "mocha": "bin/mocha.js" - }, - "engines": { - "node": ">= 14.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/mochajs" - } - }, - "node_modules/mocha/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/mocha/node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/mocha/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/mocha/node_modules/minimatch": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", - "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/mocha/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - }, - "node_modules/mocha/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/modify-values": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/modify-values/-/modify-values-1.0.1.tgz", @@ -10124,18 +9982,6 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/nanoid": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz", - "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==", - "dev": true, - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, "node_modules/nanoresource": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/nanoresource/-/nanoresource-1.3.0.tgz", @@ -13069,15 +12915,6 @@ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "dev": true }, - "node_modules/serialize-javascript": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", - "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", - "dev": true, - "dependencies": { - "randombytes": "^2.1.0" - } - }, "node_modules/serve-static": { "version": "1.15.0", "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", @@ -15370,12 +15207,6 @@ "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", "dev": true }, - "node_modules/workerpool": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz", - "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==", - "dev": true - }, "node_modules/wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", @@ -15589,39 +15420,6 @@ "node": ">=10" } }, - "node_modules/yargs-unparser": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", - "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", - "dev": true, - "dependencies": { - "camelcase": "^6.0.0", - "decamelize": "^4.0.0", - "flat": "^5.0.2", - "is-plain-obj": "^2.1.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/yargs-unparser/node_modules/camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/yargs-unparser/node_modules/decamelize": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", - "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", - "dev": true, - "engines": { - "node": ">=10" - } - }, "node_modules/yeast": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz", @@ -16662,12 +16460,6 @@ "integrity": "sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ==", "dev": true }, - "@types/mocha": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-10.0.1.tgz", - "integrity": "sha512-/fvYntiO1GeICvqbQ3doGDIP97vWmvFt83GKguJ6prmQM2iXZfFcq6YE8KteFyRtX2/h5Hf91BYvPodJKFYv5Q==", - "dev": true - }, "@types/node": { "version": "20.5.1", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.5.1.tgz", @@ -17322,12 +17114,6 @@ "string-width": "^4.1.0" } }, - "ansi-colors": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", - "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", - "dev": true - }, "ansi-escapes": { "version": "4.3.2", "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", @@ -17946,12 +17732,6 @@ "resolve": "^1.17.0" } }, - "browser-stdout": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", - "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", - "dev": true - }, "browserify": { "version": "17.0.0", "resolved": "https://registry.npmjs.org/browserify/-/browserify-17.0.0.tgz", @@ -19381,12 +19161,6 @@ "minimist": "^1.1.1" } }, - "diff": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", - "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", - "dev": true - }, "diffie-hellman": { "version": "5.0.3", "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", @@ -20493,12 +20267,6 @@ "path-exists": "^4.0.0" } }, - "flat": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", - "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", - "dev": true - }, "flat-cache": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", @@ -20615,6 +20383,13 @@ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" }, + "fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "optional": true + }, "function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", @@ -21140,12 +20915,6 @@ "type-fest": "^0.8.0" } }, - "he": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", - "dev": true - }, "help-me": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/help-me/-/help-me-4.2.0.tgz", @@ -21868,12 +21637,6 @@ "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", "dev": true }, - "is-plain-obj": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", - "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", - "dev": true - }, "is-plain-object": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", @@ -23243,82 +23006,6 @@ "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", "dev": true }, - "mocha": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.2.0.tgz", - "integrity": "sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg==", - "dev": true, - "requires": { - "ansi-colors": "4.1.1", - "browser-stdout": "1.3.1", - "chokidar": "3.5.3", - "debug": "4.3.4", - "diff": "5.0.0", - "escape-string-regexp": "4.0.0", - "find-up": "5.0.0", - "glob": "7.2.0", - "he": "1.2.0", - "js-yaml": "4.1.0", - "log-symbols": "4.1.0", - "minimatch": "5.0.1", - "ms": "2.1.3", - "nanoid": "3.3.3", - "serialize-javascript": "6.0.0", - "strip-json-comments": "3.1.1", - "supports-color": "8.1.1", - "workerpool": "6.2.1", - "yargs": "16.2.0", - "yargs-parser": "20.2.4", - "yargs-unparser": "2.0.0" - }, - "dependencies": { - "brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "requires": { - "balanced-match": "^1.0.0" - } - }, - "escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "minimatch": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", - "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==", - "dev": true, - "requires": { - "brace-expansion": "^2.0.1" - } - }, - "ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - }, - "supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, "modify-values": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/modify-values/-/modify-values-1.0.1.tgz", @@ -23615,12 +23302,6 @@ "integrity": "sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA==", "dev": true }, - "nanoid": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz", - "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==", - "dev": true - }, "nanoresource": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/nanoresource/-/nanoresource-1.3.0.tgz", @@ -25855,15 +25536,6 @@ } } }, - "serialize-javascript": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", - "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", - "dev": true, - "requires": { - "randombytes": "^2.1.0" - } - }, "serve-static": { "version": "1.15.0", "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", @@ -27713,12 +27385,6 @@ "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", "dev": true }, - "workerpool": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz", - "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==", - "dev": true - }, "wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", @@ -27873,32 +27539,6 @@ "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", "dev": true }, - "yargs-unparser": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", - "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", - "dev": true, - "requires": { - "camelcase": "^6.0.0", - "decamelize": "^4.0.0", - "flat": "^5.0.2", - "is-plain-obj": "^2.1.0" - }, - "dependencies": { - "camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "dev": true - }, - "decamelize": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", - "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", - "dev": true - } - } - }, "yeast": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz", diff --git a/package.json b/package.json index ec1090fb4..8868937e8 100644 --- a/package.json +++ b/package.json @@ -56,7 +56,7 @@ "build:browser": "rimraf dist/ && mkdirp dist/ && browserify build/mqtt.js --standalone mqtt > dist/mqtt.js && terser dist/mqtt.js --compress --mangle --output dist/mqtt.min.js", "build": "npm run build:ts && npm run build:browser", "prepare": "npm run build", - "unit-test:node": "node_modules/.bin/nyc --reporter=lcov --reporter=text ./node_modules/mocha/bin/_mocha -r ts-node/register test/*.ts --exit", + "unit-test:node": "node_modules/.bin/nyc --reporter=lcov --reporter=text node --test --loader tsx test/*.ts", "unit-test:browser": "airtap --server test/browser/server.js test/browser/test.js", "test:node": "npm run unit-test:node && codecov", "test:browser": "npm run build && npm run unit-test:browser", @@ -122,7 +122,6 @@ "@release-it/conventional-changelog": "^7.0.0", "@types/chai": "^4.3.5", "@types/duplexify": "^3.6.1", - "@types/mocha": "^10.0.1", "@types/node": "^20.5.0", "@types/sinon": "^10.0.16", "@types/tape": "^5.6.0", @@ -144,7 +143,6 @@ "eslint-plugin-prettier": "^5.0.0", "global": "^4.4.0", "mkdirp": "^3.0.1", - "mocha": "^10.2.0", "mqtt-connection": "^4.1.0", "mqtt-level-store": "^3.1.0", "nyc": "^15.1.0", diff --git a/test/abstract_client.ts b/test/abstract_client.ts index 5d0325a90..b4697cbd3 100644 --- a/test/abstract_client.ts +++ b/test/abstract_client.ts @@ -22,6 +22,7 @@ import { import { IPublishPacket, IPubrelPacket, ISubackPacket, QoS } from 'mqtt-packet' import { DoneCallback, ErrorWithReasonCode } from 'src/lib/shared' import { fail } from 'assert' +import { describe, it, beforeEach, afterEach } from 'node:test' /** * These tests try to be consistent with names for servers (brokers) and clients, @@ -56,7 +57,7 @@ export default function abstractTest(server, config) { } describe('closing', () => { - it('should emit close if stream closes', function _test(done) { + it('should emit close if stream closes', function _test(t, done) { const client = connect() client.once('connect', () => { @@ -67,7 +68,7 @@ export default function abstractTest(server, config) { }) }) - it('should mark the client as disconnected', function _test(done) { + it('should mark the client as disconnected', function _test(t, done) { const client = connect() client.once('close', () => { @@ -85,7 +86,7 @@ export default function abstractTest(server, config) { }) }) - it('should stop ping timer if stream closes', function _test(done) { + it('should stop ping timer if stream closes', function _test(t, done) { const client = connect() client.once('close', () => { @@ -99,7 +100,7 @@ export default function abstractTest(server, config) { }) }) - it('should emit close after end called', function _test(done) { + it('should emit close after end called', function _test(t, done) { const client = connect() client.once('close', () => { @@ -111,7 +112,7 @@ export default function abstractTest(server, config) { }) }) - it('should emit end after end called and client must be disconnected', function _test(done) { + it('should emit end after end called and client must be disconnected', function _test(t, done) { const client = connect() client.once('end', () => { @@ -126,7 +127,7 @@ export default function abstractTest(server, config) { }) }) - it('should pass store close error to end callback but not to end listeners (incomingStore)', function _test(done) { + it('should pass store close error to end callback but not to end listeners (incomingStore)', function _test(t, done) { const store = new Store() const client = connect({ incomingStore: store }) @@ -150,7 +151,7 @@ export default function abstractTest(server, config) { }) }) - it('should pass store close error to end callback but not to end listeners (outgoingStore)', function _test(done) { + it('should pass store close error to end callback but not to end listeners (outgoingStore)', function _test(t, done) { const store = new Store() const client = connect({ outgoingStore: store }) @@ -174,7 +175,7 @@ export default function abstractTest(server, config) { }) }) - it('should return `this` if end called twice', function _test(done) { + it('should return `this` if end called twice', function _test(t, done) { const client = connect() client.once('connect', () => { @@ -188,7 +189,7 @@ export default function abstractTest(server, config) { }) }) - it('should emit end only on first client end', function _test(done) { + it('should emit end only on first client end', function _test(t, done) { const client = connect() client.once('end', () => { @@ -205,7 +206,7 @@ export default function abstractTest(server, config) { }) }) - it('should stop ping timer after end called', function _test(done) { + it('should stop ping timer after end called', function _test(t, done) { const client = connect() client.once('connect', () => { @@ -217,7 +218,7 @@ export default function abstractTest(server, config) { }) }) - it('should be able to end even on a failed connection', function _test(done) { + it('should be able to end even on a failed connection', function _test(t, done) { const client = connect({ host: 'this_hostname_should_not_exist' }) const timeout = setTimeout(() => { @@ -232,7 +233,7 @@ export default function abstractTest(server, config) { }, 200) }) - it('should emit end even on a failed connection', function _test(done) { + it('should emit end even on a failed connection', function _test(t, done) { const client = connect({ host: 'this_hostname_should_not_exist' }) const timeout = setTimeout(() => { @@ -250,7 +251,7 @@ export default function abstractTest(server, config) { }, 200) }) - it.skip('should emit end only once for a reconnecting client', function _test(done) { + it.skip('should emit end only once for a reconnecting client', function _test(t, done) { // I want to fix this test, but it will take signficant work, so I am marking it as a skipping test right now. // Reason for it is that there are overlaps in the reconnectTimer and connectTimer. In the PR for this code // there will be gists showing the difference between a successful test here and a failed test. For now we @@ -278,7 +279,7 @@ export default function abstractTest(server, config) { }) describe('connecting', () => { - it('should connect to the broker', function _test(done) { + it('should connect to the broker', function _test(t, done) { const client = connect() client.on('error', done) @@ -287,7 +288,7 @@ export default function abstractTest(server, config) { }) }) - it('should send a default client id', function _test(done) { + it('should send a default client id', function _test(t, done) { const client = connect() client.on('error', done) @@ -299,7 +300,7 @@ export default function abstractTest(server, config) { }) }) - it('should send be clean by default', function _test(done) { + it('should send be clean by default', function _test(t, done) { const client = connect() client.on('error', done) @@ -311,7 +312,7 @@ export default function abstractTest(server, config) { }) }) - it('should connect with the given client id', function _test(done) { + it('should connect with the given client id', function _test(t, done) { const client = connect({ clientId: 'testclient' }) client.on('error', (err) => { throw err @@ -325,7 +326,7 @@ export default function abstractTest(server, config) { }) }) - it('should connect with the client id and unclean state', function _test(done) { + it('should connect with the client id and unclean state', function _test(t, done) { const client = connect({ clientId: 'testclient', clean: false }) client.on('error', (err) => { throw err @@ -340,7 +341,7 @@ export default function abstractTest(server, config) { }) }) - it('should require a clientId with clean=false', function _test(done) { + it('should require a clientId with clean=false', function _test(t, done) { try { const client = connect({ clean: false }) client.on('error', (err) => { @@ -355,7 +356,7 @@ export default function abstractTest(server, config) { } }) - it('should default to localhost', function _test(done) { + it('should default to localhost', function _test(t, done) { const client = connect({ clientId: 'testclient' }) client.on('error', (err) => { throw err @@ -369,7 +370,7 @@ export default function abstractTest(server, config) { }) }) - it('should emit connect', function _test(done) { + it('should emit connect', function _test(t, done) { const client = connect() client.once('connect', (packet: mqtt.IConnackPacket) => { assert.equal(packet.cmd, 'connack') @@ -378,7 +379,7 @@ export default function abstractTest(server, config) { client.once('error', done) }) - it('should provide connack packet with connect event', function _test(done) { + it('should provide connack packet with connect event', function _test(t, done) { const connack = version === 5 ? { reasonCode: 0, sessionPresent: undefined } @@ -402,7 +403,7 @@ export default function abstractTest(server, config) { }) }) - it('should mark the client as connected', function _test(done) { + it('should mark the client as connected', function _test(t, done) { const client = connect() client.once('connect', () => { assert.isTrue(client.connected) @@ -410,7 +411,7 @@ export default function abstractTest(server, config) { }) }) - it('should emit error on invalid clientId', function _test(done) { + it('should emit error on invalid clientId', function _test(t, done) { const client = connect({ clientId: 'invalid' }) client.once('connect', () => { done(new Error('Should not emit connect')) @@ -422,7 +423,7 @@ export default function abstractTest(server, config) { }) }) - it('should emit error event if the socket refuses the connection', function _test(done) { + it('should emit error event if the socket refuses the connection', function _test(t, done) { // fake a port const client = connect({ port: 4557 }) @@ -432,7 +433,7 @@ export default function abstractTest(server, config) { }) }) - it('should have different client ids', function _test(done) { + it('should have different client ids', function _test(t, done) { // bug identified in this test: the client.end callback is invoked twice, once when the `end` // method completes closing the stores and invokes the callback, and another time when the // stream is closed. When the stream is closed, for some reason the closeStores method is called @@ -453,7 +454,7 @@ export default function abstractTest(server, config) { }) describe('handling offline states', () => { - it('should emit offline event once when the client transitions from connected states to disconnected ones', function _test(done) { + it('should emit offline event once when the client transitions from connected states to disconnected ones', function _test(t, done) { const client = connect({ reconnectPeriod: 20 }) client.on('connect', () => { @@ -465,7 +466,7 @@ export default function abstractTest(server, config) { }) }) - it('should emit offline event once when the client (at first) can NOT connect to servers', function _test(done) { + it('should emit offline event once when the client (at first) can NOT connect to servers', function _test(t, done) { // fake a port const client = connect({ reconnectPeriod: 20, port: 4557 }) @@ -478,7 +479,7 @@ export default function abstractTest(server, config) { }) describe('topic validations when subscribing', () => { - it('should be ok for well-formated topics', function _test(done) { + it('should be ok for well-formated topics', function _test(t, done) { const client = connect() client.subscribe( [ @@ -505,7 +506,7 @@ export default function abstractTest(server, config) { ) }) - it('should return an error (via callbacks) for topic #/event', function _test(done) { + it('should return an error (via callbacks) for topic #/event', function _test(t, done) { const client = connect() client.subscribe(['#/event', 'event#', 'event+'], (err) => { client.end(false, () => { @@ -517,7 +518,7 @@ export default function abstractTest(server, config) { }) }) - it('should return an empty array for duplicate subs', function _test(done) { + it('should return an empty array for duplicate subs', function _test(t, done) { const client = connect() client.subscribe('event', (err, granted1) => { if (err) { @@ -534,7 +535,7 @@ export default function abstractTest(server, config) { }) }) - it('should return an error (via callbacks) for topic #/event', function _test(done) { + it('should return an error (via callbacks) for topic #/event', function _test(t, done) { const client = connect() client.subscribe('#/event', (err) => { client.end(() => { @@ -546,7 +547,7 @@ export default function abstractTest(server, config) { }) }) - it('should return an error (via callbacks) for topic event#', function _test(done) { + it('should return an error (via callbacks) for topic event#', function _test(t, done) { const client = connect() client.subscribe('event#', (err) => { client.end(() => { @@ -558,7 +559,7 @@ export default function abstractTest(server, config) { }) }) - it('should return an error (via callbacks) for topic system/#/event', function _test(done) { + it('should return an error (via callbacks) for topic system/#/event', function _test(t, done) { const client = connect() client.subscribe('system/#/event', (err) => { client.end(() => { @@ -570,7 +571,7 @@ export default function abstractTest(server, config) { }) }) - it('should return an error (via callbacks) for empty topic list', function _test(done) { + it('should return an error (via callbacks) for empty topic list', function _test(t, done) { const client = connect() client.subscribe([], (subErr) => { client.end((endErr) => { @@ -582,7 +583,7 @@ export default function abstractTest(server, config) { }) }) - it('should return an error (via callbacks) for topic system/+/#/event', function _test(done) { + it('should return an error (via callbacks) for topic system/+/#/event', function _test(t, done) { const client = connect() client.subscribe('system/+/#/event', (subErr) => { client.end(true, (endErr) => { @@ -596,7 +597,7 @@ export default function abstractTest(server, config) { }) describe('offline messages', () => { - it('should queue message until connected', function _test(done) { + it('should queue message until connected', function _test(t, done) { const client = connect() client.publish('test', 'test') @@ -612,7 +613,7 @@ export default function abstractTest(server, config) { }) }) - it('should not queue qos 0 messages if queueQoSZero is false', function _test(done) { + it('should not queue qos 0 messages if queueQoSZero is false', function _test(t, done) { const client = connect({ queueQoSZero: false }) client.publish('test', 'test', { qos: 0 }) @@ -624,7 +625,7 @@ export default function abstractTest(server, config) { }) }) - it('should queue qos != 0 messages', function _test(done) { + it('should queue qos != 0 messages', function _test(t, done) { const client = connect({ queueQoSZero: false }) client.publish('test', 'test', { qos: 1 }) @@ -639,7 +640,7 @@ export default function abstractTest(server, config) { }) }) - it('should not interrupt messages', function _test(done) { + it('should not interrupt messages', function _test(t, done) { let client = null let publishCount = 0 const incomingStore = new mqtt.Store({ clean: false }) @@ -709,7 +710,7 @@ export default function abstractTest(server, config) { }) }) - it('should not overtake the messages stored in the level-db-store', function _test(done) { + it('should not overtake the messages stored in the level-db-store', function _test(t, done) { const storePath = fs.mkdtempSync('test-store_') const store = levelStore(storePath) let client = null @@ -793,7 +794,7 @@ export default function abstractTest(server, config) { }) }) - it('should call cb if an outgoing QoS 0 message is not sent', function _test(done) { + it('should call cb if an outgoing QoS 0 message is not sent', function _test(t, done) { const client = connect({ queueQoSZero: false }) let called = false @@ -809,7 +810,7 @@ export default function abstractTest(server, config) { }) }) - it('should delay ending up until all inflight messages are delivered', function _test(done) { + it('should delay ending up until all inflight messages are delivered', function _test(t, done) { const client = connect() let subscribeCalled = false @@ -826,7 +827,7 @@ export default function abstractTest(server, config) { }) }) - it('wait QoS 1 publish messages', function _test(done) { + it('wait QoS 1 publish messages', function _test(t, done) { const client = connect() let messageReceived = false @@ -852,14 +853,14 @@ export default function abstractTest(server, config) { }) }) - it('does not wait acks when force-closing', function _test(done) { + it('does not wait acks when force-closing', function _test(t, done) { // non-running broker const client = connect('mqtt://localhost:8993') client.publish('test', 'test', { qos: 1 }) client.end(true, done) }) - it('should call cb if store.put fails', function _test(done) { + it('should call cb if store.put fails', function _test(t, done) { const store = new Store() store.put = (packet, cb) => { process.nextTick(cb, new Error('oops there is an error')) @@ -878,7 +879,7 @@ export default function abstractTest(server, config) { }) describe('publishing', () => { - it('should publish a message (offline)', function _test(done) { + it('should publish a message (offline)', function _test(t, done) { const client = connect() const payload = 'test' const topic = 'test' @@ -902,7 +903,7 @@ export default function abstractTest(server, config) { } }) - it('should publish a message (online)', function _test(done) { + it('should publish a message (online)', function _test(t, done) { const client = connect() const payload = 'test' const topic = 'test' @@ -928,7 +929,7 @@ export default function abstractTest(server, config) { } }) - it('should publish a message (retain, offline)', function _test(done) { + it('should publish a message (retain, offline)', function _test(t, done) { const client = connect({ queueQoSZero: true }) const payload = 'test' const topic = 'test' @@ -950,7 +951,7 @@ export default function abstractTest(server, config) { }) }) - it('should emit a packetsend event', function _test(done) { + it('should emit a packetsend event', function _test(t, done) { const client = connect() const payload = 'test_payload' const topic = 'testTopic' @@ -970,7 +971,7 @@ export default function abstractTest(server, config) { client.publish(topic, payload) }) - it('should accept options', function _test(done) { + it('should accept options', function _test(t, done) { const client = connect() const payload = 'test' const topic = 'test' @@ -1005,7 +1006,7 @@ export default function abstractTest(server, config) { }) }) - it('should publish with the default options for an empty parameter', function _test(done) { + it('should publish with the default options for an empty parameter', function _test(t, done) { const client = connect() const payload = 'test' const topic = 'test' @@ -1039,7 +1040,7 @@ export default function abstractTest(server, config) { }) }) - it('should mark a message as duplicate when "dup" option is set', function _test(done) { + it('should mark a message as duplicate when "dup" option is set', function _test(t, done) { const client = connect() const payload = 'duplicated-test' const topic = 'test' @@ -1075,7 +1076,7 @@ export default function abstractTest(server, config) { }) }) - it('should fire a callback (qos 0)', function _test(done) { + it('should fire a callback (qos 0)', function _test(t, done) { const client = connect() client.once('connect', () => { @@ -1087,7 +1088,7 @@ export default function abstractTest(server, config) { }) }) - it('should fire a callback (qos 1)', function _test(done) { + it('should fire a callback (qos 1)', function _test(t, done) { const client = connect() const opts: IClientPublishOptions = { qos: 1 } @@ -1099,7 +1100,7 @@ export default function abstractTest(server, config) { }) }) - it('should fire a callback (qos 1) on error', function _test(done) { + it('should fire a callback (qos 1) on error', function _test(t, done) { // 145 = Packet Identifier in use const pubackReasonCode = 145 const pubOpts = { qos: 1 } @@ -1157,7 +1158,7 @@ export default function abstractTest(server, config) { }) }) - it('should fire a callback (qos 2)', function _test(done) { + it('should fire a callback (qos 2)', function _test(t, done) { const client = connect() const opts: IClientPublishOptions = { qos: 2 } @@ -1169,7 +1170,7 @@ export default function abstractTest(server, config) { }) }) - it('should fire a callback (qos 2) on error', function _test(done) { + it('should fire a callback (qos 2) on error', function _test(t, done) { // 145 = Packet Identifier in use const pubrecReasonCode = 145 const pubOpts = { qos: 2 } @@ -1231,7 +1232,7 @@ export default function abstractTest(server, config) { }) }) - it('should support UTF-8 characters in topic', function _test(done) { + it('should support UTF-8 characters in topic', function _test(t, done) { const client = connect() client.once('connect', () => { @@ -1241,7 +1242,7 @@ export default function abstractTest(server, config) { }) }) - it('should support UTF-8 characters in payload', function _test(done) { + it('should support UTF-8 characters in payload', function _test(t, done) { const client = connect() client.once('connect', () => { @@ -1251,7 +1252,7 @@ export default function abstractTest(server, config) { }) }) - it('should publish 10 QoS 2 and receive them', function _test(done) { + it('should publish 10 QoS 2 and receive them', function _test(t, done) { const client = connect() let countSent = 0 let countReceived = 0 @@ -1343,12 +1344,12 @@ export default function abstractTest(server, config) { const qosTests = [0, 1, 2] qosTests.forEach((qos) => { - it(`should publish 10 QoS ${qos}and receive them only when \`handleMessage\` finishes`, function _test(done) { + it(`should publish 10 QoS ${qos}and receive them only when \`handleMessage\` finishes`, function _test(t, done) { testQosHandleMessage(qos, done) }) }) - it('should not send a `puback` if the execution of `handleMessage` fails for messages with QoS `1`', function _test(done) { + it('should not send a `puback` if the execution of `handleMessage` fails for messages with QoS `1`', function _test(t, done) { const client = connect() client.handleMessage = (packet, callback) => { @@ -1385,7 +1386,7 @@ export default function abstractTest(server, config) { it( 'should silently ignore errors thrown by `handleMessage` and return when no callback is passed ' + 'into `handlePublish` method', - function _test(done) { + function _test(t, done) { const client = connect() client.handleMessage = (packet, callback) => { @@ -1411,7 +1412,7 @@ export default function abstractTest(server, config) { }, ) - it('should handle error with async incoming store in QoS 1 `handlePublish` method', function _test(done) { + it('should handle error with async incoming store in QoS 1 `handlePublish` method', function _test(t, done) { class AsyncStore extends Store { put(packet, cb) { process.nextTick(() => { @@ -1446,7 +1447,7 @@ export default function abstractTest(server, config) { ) }) - it('should handle error with async incoming store in QoS 2 `handlePublish` method', function _test(done) { + it('should handle error with async incoming store in QoS 2 `handlePublish` method', function _test(t, done) { class AsyncStore extends Store { put(packet, cb) { process.nextTick(() => { @@ -1496,7 +1497,7 @@ export default function abstractTest(server, config) { ) }) - it('should handle error with async incoming store in QoS 2 `handlePubrel` method', function _test(done) { + it('should handle error with async incoming store in QoS 2 `handlePubrel` method', function _test(t, done) { class AsyncStore extends Store { put(packet, cb) { process.nextTick(() => { @@ -1543,7 +1544,7 @@ export default function abstractTest(server, config) { ) }) - it('should handle success with async incoming store in QoS 2 `handlePubrel` method', function _test(done) { + it('should handle success with async incoming store in QoS 2 `handlePubrel` method', function _test(t, done) { let delComplete = false class AsyncStore extends Store { put(packet, cb) { @@ -1592,7 +1593,7 @@ export default function abstractTest(server, config) { ) }) - it('should not send a `pubcomp` if the execution of `handleMessage` fails for messages with QoS `2`', function _test(done) { + it('should not send a `pubcomp` if the execution of `handleMessage` fails for messages with QoS `2`', function _test(t, done) { const store = new Store() const client = connect({ incomingStore: store }) @@ -1639,7 +1640,7 @@ export default function abstractTest(server, config) { it( 'should silently ignore errors thrown by `handleMessage` and return when no callback is passed ' + 'into `handlePubrel` method', - function _test(done) { + function _test(t, done) { const store = new Store() const client = connect({ incomingStore: store }) @@ -1683,7 +1684,7 @@ export default function abstractTest(server, config) { }, ) - it('should keep message order', function _test(done) { + it('should keep message order', function _test(t, done) { let publishCount = 0 let reconnect = false let client: mqtt.MqttClient @@ -1806,7 +1807,7 @@ export default function abstractTest(server, config) { callbackStorePutByQoSParameters.forEach((test) => { if (test.args[0] === 0) { // QoS 0 - it(`should not call cbStorePut when publishing message with QoS \`${test.args[0]}\` and clean \`${test.args[1]}\``, function _test(done) { + it(`should not call cbStorePut when publishing message with QoS \`${test.args[0]}\` and clean \`${test.args[1]}\``, function _test(t, done) { testCallbackStorePutByQoS( test.args[0] as number, test.args[1] as boolean, @@ -1816,7 +1817,7 @@ export default function abstractTest(server, config) { }) } else { // QoS 1 and 2 - it(`should call cbStorePut before publish completes when publishing message with QoS \`${test.args[0]}\` and clean \`${test.args[1]}\``, function _test(done) { + it(`should call cbStorePut before publish completes when publishing message with QoS \`${test.args[0]}\` and clean \`${test.args[1]}\``, function _test(t, done) { testCallbackStorePutByQoS( test.args[0] as number, test.args[1] as boolean, @@ -1829,7 +1830,7 @@ export default function abstractTest(server, config) { }) describe('unsubscribing', () => { - it('should send an unsubscribe packet (offline)', function _test(done) { + it('should send an unsubscribe packet (offline)', function _test(t, done) { const client = connect() let received = false @@ -1847,7 +1848,7 @@ export default function abstractTest(server, config) { }) }) - it('should send an unsubscribe packet', function _test(done) { + it('should send an unsubscribe packet', function _test(t, done) { const client = connect() const topic = 'topic' let received = false @@ -1868,7 +1869,7 @@ export default function abstractTest(server, config) { }) }) - it('should emit a packetsend event', function _test(done) { + it('should emit a packetsend event', function _test(t, done) { const client = connect() const testTopic = 'testTopic' @@ -1883,7 +1884,7 @@ export default function abstractTest(server, config) { }) }) - it('should emit a packetreceive event', function _test(done) { + it('should emit a packetreceive event', function _test(t, done) { const client = connect() const testTopic = 'testTopic' @@ -1898,7 +1899,7 @@ export default function abstractTest(server, config) { }) }) - it('should accept an array of unsubs', function _test(done) { + it('should accept an array of unsubs', function _test(t, done) { const client = connect() const topics = ['topic1', 'topic2'] let received = false @@ -1919,7 +1920,7 @@ export default function abstractTest(server, config) { }) }) - it('should fire a callback on unsuback', function _test(done) { + it('should fire a callback on unsuback', function _test(t, done) { const client = connect() const topic = 'topic' @@ -1938,7 +1939,7 @@ export default function abstractTest(server, config) { }) }) - it('should unsubscribe from a chinese topic', function _test(done) { + it('should unsubscribe from a chinese topic', function _test(t, done) { const client = connect() const topic = '中国' @@ -1959,7 +1960,7 @@ export default function abstractTest(server, config) { }) describe('keepalive', () => { - let clock + let clock: sinon.SinonFakeTimers // eslint-disable-next-line beforeEach(() => { @@ -1970,7 +1971,7 @@ export default function abstractTest(server, config) { clock.restore() }) - it('should checkPing at keepalive interval', function _test(done) { + it('should checkPing at keepalive interval', function _test(t, done) { const interval = 3 const client = connect({ keepalive: interval }) @@ -1991,7 +1992,7 @@ export default function abstractTest(server, config) { }) }) - it('should not checkPing if publishing at a higher rate than keepalive', function _test(done) { + it('should not checkPing if publishing at a higher rate than keepalive', function _test(t, done) { const intervalMs = 3000 const client = connect({ keepalive: intervalMs / 1000 }) @@ -2009,7 +2010,7 @@ export default function abstractTest(server, config) { }) }) - it('should checkPing if publishing at a higher rate than keepalive and reschedulePings===false', function _test(done) { + it('should checkPing if publishing at a higher rate than keepalive and reschedulePings===false', function _test(t, done) { const intervalMs = 3000 const client = connect({ keepalive: intervalMs / 1000, @@ -2032,7 +2033,7 @@ export default function abstractTest(server, config) { }) describe('pinging', () => { - it('should set a ping timer', function _test(done) { + it('should set a ping timer', function _test(t, done) { const client = connect({ keepalive: 3 }) client.once('connect', () => { assert.exists(client.pingTimer) @@ -2040,7 +2041,7 @@ export default function abstractTest(server, config) { }) }) - it('should not set a ping timer keepalive=0', function _test(done) { + it('should not set a ping timer keepalive=0', function _test(t, done) { const client = connect({ keepalive: 0 }) client.on('connect', () => { assert.notExists(client.pingTimer) @@ -2048,27 +2049,32 @@ export default function abstractTest(server, config) { }) }) - it('should reconnect if pingresp is not sent', function _test(done) { - this.timeout(4000) - const client = connect({ keepalive: 1, reconnectPeriod: 100 }) + it( + 'should reconnect if pingresp is not sent', + { + timeout: 4000, + }, + function _test(t, done) { + const client = connect({ keepalive: 1, reconnectPeriod: 100 }) - // Fake no pingresp being send by stubbing the _handlePingresp function - client.on('packetreceive', (packet) => { - if (packet.cmd === 'pingresp') { - setImmediate(() => { - client.pingResp = false - }) - } - }) + // Fake no pingresp being send by stubbing the _handlePingresp function + client.on('packetreceive', (packet) => { + if (packet.cmd === 'pingresp') { + setImmediate(() => { + client.pingResp = false + }) + } + }) - client.once('connect', () => { client.once('connect', () => { - client.end(true, done) + client.once('connect', () => { + client.end(true, done) + }) }) - }) - }) + }, + ) - it('should not reconnect if pingresp is successful', function _test(done) { + it('should not reconnect if pingresp is successful', function _test(t, done) { const client = connect({ keepalive: 100 }) client.once('close', () => { done(new Error('Client closed connection')) @@ -2079,7 +2085,7 @@ export default function abstractTest(server, config) { }, 1000) }) - it('should defer the next ping when sending a control packet', function _test(done) { + it('should defer the next ping when sending a control packet', function _test(t, done) { const client = connect({ keepalive: 1 }) client.once('connect', () => { @@ -2106,7 +2112,7 @@ export default function abstractTest(server, config) { }) describe('subscribing', () => { - it('should send a subscribe message (offline)', function _test(done) { + it('should send a subscribe message (offline)', function _test(t, done) { const client = connect() client.subscribe('test') @@ -2118,7 +2124,7 @@ export default function abstractTest(server, config) { }) }) - it('should send a subscribe message', function _test(done) { + it('should send a subscribe message', function _test(t, done) { const client = connect() const topic = 'test' @@ -2143,7 +2149,7 @@ export default function abstractTest(server, config) { }) }) - it('should emit a packetsend event', function _test(done) { + it('should emit a packetsend event', function _test(t, done) { const client = connect() const testTopic = 'testTopic' @@ -2158,7 +2164,7 @@ export default function abstractTest(server, config) { }) }) - it('should emit a packetreceive event', function _test(done) { + it('should emit a packetreceive event', function _test(t, done) { const client = connect() const testTopic = 'testTopic' @@ -2173,7 +2179,7 @@ export default function abstractTest(server, config) { }) }) - it('should accept an array of subscriptions', function _test(done) { + it('should accept an array of subscriptions', function _test(t, done) { const client = connect() const subs = ['test1', 'test2'] @@ -2203,7 +2209,7 @@ export default function abstractTest(server, config) { }) }) - it('should accept a hash of subscriptions', function _test(done) { + it('should accept a hash of subscriptions', function _test(t, done) { const client = connect() const topics: ISubscriptionMap = { test1: { qos: 0 }, @@ -2239,7 +2245,7 @@ export default function abstractTest(server, config) { }) }) - it('should accept an options parameter', function _test(done) { + it('should accept an options parameter', function _test(t, done) { const client = connect() const topic = 'test' const opts: IClientSubscribeOptions = { qos: 1 } @@ -2269,7 +2275,7 @@ export default function abstractTest(server, config) { }) }) - it('should subscribe with the default options for an empty options parameter', function _test(done) { + it('should subscribe with the default options for an empty options parameter', function _test(t, done) { const client = connect() const topic = 'test' const defaultOpts = { qos: 0 } @@ -2296,7 +2302,7 @@ export default function abstractTest(server, config) { }) }) - it('should fire a callback on suback', function _test(done) { + it('should fire a callback on suback', function _test(t, done) { const client = connect() const topic = 'test' @@ -2323,7 +2329,7 @@ export default function abstractTest(server, config) { }) }) - it('should fire a callback with error if disconnected (options provided)', function _test(done) { + it('should fire a callback with error if disconnected (options provided)', function _test(t, done) { const client = connect() const topic = 'test' client.once('connect', () => { @@ -2337,7 +2343,7 @@ export default function abstractTest(server, config) { }) }) - it('should fire a callback with error if disconnected (options not provided)', function _test(done) { + it('should fire a callback with error if disconnected (options not provided)', function _test(t, done) { const client = connect() const topic = 'test' @@ -2352,7 +2358,7 @@ export default function abstractTest(server, config) { }) }) - it('should subscribe with a chinese topic', function _test(done) { + it('should subscribe with a chinese topic', function _test(t, done) { const client = connect() const topic = '中国' @@ -2379,7 +2385,7 @@ export default function abstractTest(server, config) { }) describe('receiving messages', () => { - it('should fire the message event', function _test(done) { + it('should fire the message event', function _test(t, done) { const client = connect() const testPacket = { topic: 'test', @@ -2408,7 +2414,7 @@ export default function abstractTest(server, config) { }) }) - it('should emit a packetreceive event', function _test(done) { + it('should emit a packetreceive event', function _test(t, done) { const client = connect() const testPacket = { topic: 'test', @@ -2439,7 +2445,7 @@ export default function abstractTest(server, config) { }) }) - it('should support binary data', function _test(done) { + it('should support binary data', function _test(t, done) { const client = connect({ encoding: 'binary' }) const testPacket = { topic: 'test', @@ -2465,7 +2471,7 @@ export default function abstractTest(server, config) { }) }) - it('should emit a message event (qos=2)', function _test(done) { + it('should emit a message event (qos=2)', function _test(t, done) { const client = connect() const testPacket = { topic: 'test', @@ -2493,7 +2499,7 @@ export default function abstractTest(server, config) { }) }) - it('should emit a message event (qos=2) - repeated publish', function _test(done) { + it('should emit a message event (qos=2) - repeated publish', function _test(t, done) { const client = connect() const testPacket = { topic: 'test', @@ -2529,7 +2535,7 @@ export default function abstractTest(server, config) { }) }) - it('should support a chinese topic', function _test(done) { + it('should support a chinese topic', function _test(t, done) { const client = connect({ encoding: 'binary' }) const testPacket = { topic: '国', @@ -2558,7 +2564,7 @@ export default function abstractTest(server, config) { }) describe('qos handling', () => { - it('should follow qos 0 semantics (trivial)', function _test(done) { + it('should follow qos 0 semantics (trivial)', function _test(t, done) { const client = connect() const testTopic = 'test' const testMessage = 'message' @@ -2581,7 +2587,7 @@ export default function abstractTest(server, config) { }) }) - it('should follow qos 1 semantics', function _test(done) { + it('should follow qos 1 semantics', function _test(t, done) { const client = connect() const testTopic = 'test' const testMessage = 'message' @@ -2608,7 +2614,7 @@ export default function abstractTest(server, config) { }) }) - it('should follow qos 2 semantics', function _test(done) { + it('should follow qos 2 semantics', function _test(t, done) { const client = connect() const testTopic = 'test' const testMessage = 'message' @@ -2705,7 +2711,7 @@ export default function abstractTest(server, config) { }) }) - it('should should empty the incoming store after a qos 2 handshake is completed', function _test(done) { + it('should should empty the incoming store after a qos 2 handshake is completed', function _test(t, done) { const client = connect() const testTopic = 'test' const testMessage = 'message' @@ -2842,17 +2848,17 @@ export default function abstractTest(server, config) { }) } - it('handle qos 2 messages exactly once when multiple pubrel received', function _test(done) { + it('handle qos 2 messages exactly once when multiple pubrel received', function _test(t, done) { testMultiplePubrel(false, done) }) - it('handle qos 2 messages exactly once when multiple pubrel received and sending pubcomp fails on client', function _test(done) { + it('handle qos 2 messages exactly once when multiple pubrel received and sending pubcomp fails on client', function _test(t, done) { testMultiplePubrel(true, done) }) }) describe('auto reconnect', () => { - it('should mark the client disconnecting if #end called', function _test(done) { + it('should mark the client disconnecting if #end called', function _test(t, done) { const client = connect() client.end(true, (err) => { @@ -2861,7 +2867,7 @@ export default function abstractTest(server, config) { }) }) - it('should reconnect after stream disconnect', function _test(done) { + it('should reconnect after stream disconnect', function _test(t, done) { const client = connect() let tryReconnect = true @@ -2876,7 +2882,7 @@ export default function abstractTest(server, config) { }) }) - it("should emit 'reconnect' when reconnecting", function _test(done) { + it("should emit 'reconnect' when reconnecting", function _test(t, done) { const client = connect() let tryReconnect = true let reconnectEvent = false @@ -2896,7 +2902,7 @@ export default function abstractTest(server, config) { }) }) - it("should emit 'offline' after going offline", function _test(done) { + it("should emit 'offline' after going offline", function _test(t, done) { const client = connect() let tryReconnect = true @@ -2917,7 +2923,7 @@ export default function abstractTest(server, config) { }) }) - it('should not reconnect if it was ended by the user', function _test(done) { + it('should not reconnect if it was ended by the user', function _test(t, done) { const client = connect() client.on('connect', () => { @@ -2926,7 +2932,7 @@ export default function abstractTest(server, config) { }) }) - it('should setup a reconnect timer on disconnect', function _test(done) { + it('should setup a reconnect timer on disconnect', function _test(t, done) { const client = connect() client.once('connect', () => { @@ -2946,44 +2952,49 @@ export default function abstractTest(server, config) { { period: 4000 }, ] reconnectPeriodTests.forEach((test) => { - it(`should allow specification of a reconnect period (${test.period}ms)`, function _test(done) { - this.timeout(10000) - let end - const reconnectSlushTime = 200 - const client = connect({ reconnectPeriod: test.period }) - let reconnect = false - const start = Date.now() - - client.on('connect', () => { - if (!reconnect) { - client.stream.end() - reconnect = true - } else { - end = Date.now() - client.end(() => { - const reconnectPeriodDuringTest = end - start - if ( - reconnectPeriodDuringTest >= - test.period - reconnectSlushTime && - reconnectPeriodDuringTest <= - test.period + reconnectSlushTime - ) { - // give the connection a 200 ms slush window - done() - } else { - done( - new Error( - `Strange reconnect period: ${reconnectPeriodDuringTest}`, - ), - ) - } - }) - } - }) - }) + it( + `should allow specification of a reconnect period (${test.period}ms)`, + { + timeout: 10000, + }, + function _test(t, done) { + let end + const reconnectSlushTime = 200 + const client = connect({ reconnectPeriod: test.period }) + let reconnect = false + const start = Date.now() + + client.on('connect', () => { + if (!reconnect) { + client.stream.end() + reconnect = true + } else { + end = Date.now() + client.end(() => { + const reconnectPeriodDuringTest = end - start + if ( + reconnectPeriodDuringTest >= + test.period - reconnectSlushTime && + reconnectPeriodDuringTest <= + test.period + reconnectSlushTime + ) { + // give the connection a 200 ms slush window + done() + } else { + done( + new Error( + `Strange reconnect period: ${reconnectPeriodDuringTest}`, + ), + ) + } + }) + } + }) + }, + ) }) - it('should always cleanup successfully on reconnection', function _test(done) { + it('should always cleanup successfully on reconnection', function _test(t, done) { const client = connect({ host: 'this_hostname_should_not_exist', connectTimeout: 0, @@ -2995,40 +3006,45 @@ export default function abstractTest(server, config) { }, 50) }) - it('should resend in-flight QoS 1 publish messages from the client', function _test(done) { - this.timeout(4000) - const client = connect({ reconnectPeriod: 200 }) - let serverPublished = false - let clientCalledBack = false + it( + 'should resend in-flight QoS 1 publish messages from the client', + { + timeout: 4000, + }, + function _test(t, done) { + const client = connect({ reconnectPeriod: 200 }) + let serverPublished = false + let clientCalledBack = false - server.once('client', (serverClient) => { - serverClient.on('connect', () => { - setImmediate(() => { - serverClient.stream.destroy() + server.once('client', (serverClient) => { + serverClient.on('connect', () => { + setImmediate(() => { + serverClient.stream.destroy() + }) }) - }) - server.once('client', (serverClientNew) => { - serverClientNew.on('publish', () => { - serverPublished = true - check() + server.once('client', (serverClientNew) => { + serverClientNew.on('publish', () => { + serverPublished = true + check() + }) }) }) - }) - client.publish('hello', 'world', { qos: 1 }, () => { - clientCalledBack = true - check() - }) + client.publish('hello', 'world', { qos: 1 }, () => { + clientCalledBack = true + check() + }) - function check() { - if (serverPublished && clientCalledBack) { - client.end(true, done) + function check() { + if (serverPublished && clientCalledBack) { + client.end(true, done) + } } - } - }) + }, + ) - it('should not resend in-flight publish messages if disconnecting', function _test(done) { + it('should not resend in-flight publish messages if disconnecting', function _test(t, done) { const client = connect({ reconnectPeriod: 200 }) let serverPublished = false let clientCalledBack = false @@ -3054,7 +3070,7 @@ export default function abstractTest(server, config) { }) }) - it('should resend in-flight QoS 2 publish messages from the client', function _test(done) { + it('should resend in-flight QoS 2 publish messages from the client', function _test(t, done) { const client = connect({ reconnectPeriod: 200 }) let serverPublished = false let clientCalledBack = false @@ -3088,7 +3104,7 @@ export default function abstractTest(server, config) { } }) - it('should not resend in-flight QoS 1 removed publish messages from the client', function _test(done) { + it('should not resend in-flight QoS 1 removed publish messages from the client', function _test(t, done) { const client = connect({ reconnectPeriod: 200 }) let clientCalledBack = false @@ -3127,7 +3143,7 @@ export default function abstractTest(server, config) { }) }) - it('should not resend in-flight QoS 2 removed publish messages from the client', function _test(done) { + it('should not resend in-flight QoS 2 removed publish messages from the client', function _test(t, done) { const client = connect({ reconnectPeriod: 200 }) let clientCalledBack = false @@ -3159,7 +3175,7 @@ export default function abstractTest(server, config) { client.end(true, done) }) - it('should resubscribe when reconnecting', function _test(done) { + it('should resubscribe when reconnecting', function _test(t, done) { const client = connect({ reconnectPeriod: 100 }) let tryReconnect = true let reconnectEvent = false @@ -3187,7 +3203,7 @@ export default function abstractTest(server, config) { }) }) - it('should resubscribe when clean=false and sessionPresent=false', function _test(done) { + it('should resubscribe when clean=false and sessionPresent=false', function _test(t, done) { const client = connect({ clientId: 'test', reconnectPeriod: 100, @@ -3220,7 +3236,7 @@ export default function abstractTest(server, config) { }) }) - it('should not resubscribe when reconnecting if resubscribe is disabled', function _test(done) { + it('should not resubscribe when reconnecting if resubscribe is disabled', function _test(t, done) { const client = connect({ reconnectPeriod: 100, resubscribe: false }) let tryReconnect = true let reconnectEvent = false @@ -3253,7 +3269,7 @@ export default function abstractTest(server, config) { }) }) - it('should not resubscribe when reconnecting if suback is error', function _test(done) { + it('should not resubscribe when reconnecting if suback is error', function _test(t, done) { let tryReconnect = true let reconnectEvent = false const server2 = serverBuilder(config.protocol, (serverClient) => { @@ -3310,7 +3326,7 @@ export default function abstractTest(server, config) { }) }) - it('should preserved incomingStore after disconnecting if clean is false', function _test(done) { + it('should preserved incomingStore after disconnecting if clean is false', function _test(t, done) { let reconnect = false let client: mqtt.MqttClient const incomingStore = new mqtt.Store({ clean: false }) @@ -3376,7 +3392,7 @@ export default function abstractTest(server, config) { }) }) - it('should clear outgoing if close from server', function _test(done) { + it('should clear outgoing if close from server', function _test(t, done) { let reconnect = false let client: mqtt.MqttClient const server2 = serverBuilder(config.protocol, (serverClient) => { @@ -3430,7 +3446,7 @@ export default function abstractTest(server, config) { }) }) - it('should resend in-flight QoS 1 publish messages from the client if clean is false', function _test(done) { + it('should resend in-flight QoS 1 publish messages from the client if clean is false', function _test(t, done) { let reconnect = false let client: mqtt.MqttClient const incomingStore = new mqtt.Store({ clean: false }) @@ -3478,7 +3494,7 @@ export default function abstractTest(server, config) { }) }) - it('should resend in-flight QoS 2 publish messages from the client if clean is false', function _test(done) { + it('should resend in-flight QoS 2 publish messages from the client if clean is false', function _test(t, done) { let reconnect = false let client: mqtt.MqttClient const incomingStore = new mqtt.Store({ clean: false }) @@ -3526,7 +3542,7 @@ export default function abstractTest(server, config) { }) }) - it('should resend in-flight QoS 2 pubrel messages from the client if clean is false', function _test(done) { + it('should resend in-flight QoS 2 pubrel messages from the client if clean is false', function _test(t, done) { let reconnect = false let client: mqtt.MqttClient const incomingStore = new mqtt.Store({ clean: false }) @@ -3588,7 +3604,7 @@ export default function abstractTest(server, config) { }) }) - it('should resend in-flight publish messages by published order', function _test(done) { + it('should resend in-flight publish messages by published order', function _test(t, done) { let publishCount = 0 let reconnect = false let disconnectOnce = true @@ -3668,7 +3684,7 @@ export default function abstractTest(server, config) { }) }) - it('should be able to pub/sub if reconnect() is called at close handler', function _test(done) { + it('should be able to pub/sub if reconnect() is called at close handler', function _test(t, done) { const client = connect({ reconnectPeriod: 0 }) let tryReconnect = true let reconnectEvent = false @@ -3698,7 +3714,7 @@ export default function abstractTest(server, config) { }) }) - it('should be able to pub/sub if reconnect() is called at out of close handler', function _test(done) { + it('should be able to pub/sub if reconnect() is called at out of close handler', function _test(t, done) { const client = connect({ reconnectPeriod: 0 }) let tryReconnect = true let reconnectEvent = false @@ -3730,7 +3746,7 @@ export default function abstractTest(server, config) { }) }) - context('with alternate server client', () => { + describe('with alternate server client', () => { let cachedClientListeners const connack = version === 5 ? { reasonCode: 0 } : { returnCode: 0 } @@ -3747,7 +3763,7 @@ export default function abstractTest(server, config) { }) }) - it('should resubscribe even if disconnect is before suback', function _test(done) { + it('should resubscribe even if disconnect is before suback', function _test(t, done) { const client = connect({ reconnectPeriod: 100, ...config }) let subscribeCount = 0 let connectCount = 0 @@ -3778,7 +3794,7 @@ export default function abstractTest(server, config) { client.subscribe('hello') }) - it('should resubscribe exactly once', function _test(done) { + it('should resubscribe exactly once', function _test(t, done) { const client = connect({ reconnectPeriod: 100, ...config }) let subscribeCount = 0 @@ -3809,7 +3825,7 @@ export default function abstractTest(server, config) { }) describe('message id to subscription topic mapping', () => { - it('should not create a mapping if resubscribe is disabled', function _test(done) { + it('should not create a mapping if resubscribe is disabled', function _test(t, done) { const client = connect({ resubscribe: false }) client.subscribe('test1') client.subscribe('test2') @@ -3817,7 +3833,7 @@ export default function abstractTest(server, config) { client.end(true, done) }) - it('should create a mapping for each subscribe call', function _test(done) { + it('should create a mapping for each subscribe call', function _test(t, done) { const client = connect() client.subscribe('test1') assert.strictEqual(Object.keys(client.messageIdToTopic).length, 1) @@ -3832,7 +3848,7 @@ export default function abstractTest(server, config) { client.end(true, done) }) - it('should remove the mapping after suback', function _test(done) { + it('should remove the mapping after suback', function _test(t, done) { const client = connect() client.once('connect', () => { client.subscribe('test1', { qos: 2 }, () => { diff --git a/test/abstract_store.ts b/test/abstract_store.ts index 1823344dc..07c154059 100644 --- a/test/abstract_store.ts +++ b/test/abstract_store.ts @@ -1,6 +1,7 @@ import { IPublishPacket, IPubrelPacket } from 'mqtt-packet' import { IStore } from '../src/lib/store' import 'should' +import { it, beforeEach, afterEach } from 'node:test' export default function abstractStoreTest( build: (cb: (err?: Error, store?: IStore) => void) => void, @@ -8,18 +9,18 @@ export default function abstractStoreTest( let store: IStore // eslint-disable-next-line - beforeEach(function (done) { + beforeEach((done) => { build((err, _store) => { store = _store done(err) }) }) - afterEach(function test(done) { + afterEach((done) => { store.close(done) }) - it('should put and stream in-flight packets', function test(done) { + it('should put and stream in-flight packets', function _test(t, done) { const packet: IPublishPacket = { topic: 'hello', payload: 'world', @@ -38,7 +39,7 @@ export default function abstractStoreTest( }) }) - it('should support destroying the stream', function test(done) { + it('should support destroying the stream', function _test(t, done) { const packet: IPublishPacket = { topic: 'hello', payload: 'world', @@ -56,7 +57,7 @@ export default function abstractStoreTest( }) }) - it('should add and del in-flight packets', function test(done) { + it('should add and del in-flight packets', function _test(t, done) { const packet: IPublishPacket = { topic: 'hello', payload: 'world', @@ -79,7 +80,7 @@ export default function abstractStoreTest( }) }) - it('should replace a packet when doing put with the same messageId', function test(done) { + it('should replace a packet when doing put with the same messageId', function _test(t, done) { const packet1: IPublishPacket = { cmd: 'publish', // added topic: 'hello', @@ -105,7 +106,7 @@ export default function abstractStoreTest( }) }) - it('should return the original packet on del', function test(done) { + it('should return the original packet on del', function _test(t, done) { const packet: IPublishPacket = { topic: 'hello', payload: 'world', @@ -127,7 +128,7 @@ export default function abstractStoreTest( }) }) - it('should get a packet with the same messageId', function test(done) { + it('should get a packet with the same messageId', function _test(t, done) { const packet: IPublishPacket = { topic: 'hello', payload: 'world', diff --git a/test/client.ts b/test/client.ts index a1fe30787..52b973718 100644 --- a/test/client.ts +++ b/test/client.ts @@ -14,6 +14,7 @@ import _debug from 'debug' import { MqttServer } from './server' import abstractClientTests from './abstract_client' import { IClientOptions } from 'src/lib/client' +import { describe, it } from 'node:test' const debug = _debug('mqttjs:client-test') @@ -33,7 +34,7 @@ describe('MqttClient', () => { abstractClientTests(server, config) describe('creating', () => { - it('should allow instantiation of MqttClient', function test(done) { + it('should allow instantiation of MqttClient', function _test(t, done) { try { client = new mqtt.MqttClient(() => { throw Error('break') @@ -45,7 +46,7 @@ describe('MqttClient', () => { } }) - it('should disable number cache if specified in options', function test(done) { + it('should disable number cache if specified in options', function _test(t, done) { try { assert.isTrue(mqttPacket.writeToStream.cacheNumbers) client = new mqtt.MqttClient( @@ -63,7 +64,7 @@ describe('MqttClient', () => { }) describe('message ids', () => { - it('should increment the message id', function test(done) { + it('should increment the message id', function _test(t, done) { client = mqtt.connect(config) const currentId = client['_nextId']() @@ -71,7 +72,7 @@ describe('MqttClient', () => { client.end((err) => done(err)) }) - it("should not throw an error if packet's messageId is not found when receiving a pubrel packet", function test(done) { + it("should not throw an error if packet's messageId is not found when receiving a pubrel packet", function _test(t, done) { const server2 = new MqttServer((serverClient) => { serverClient.on('connect', (packet) => { serverClient.connack({ returnCode: 0 }) @@ -99,7 +100,7 @@ describe('MqttClient', () => { }) }) - it('should not go overflow if the TCP frame contains a lot of PUBLISH packets', function test(done) { + it('should not go overflow if the TCP frame contains a lot of PUBLISH packets', function _test(t, done) { const parser = mqttPacket.parser() const max = 1000 let count = 0 @@ -112,7 +113,7 @@ describe('MqttClient', () => { }) client = new mqtt.MqttClient(() => duplex, {}) - client.on('message', (t, p, packet) => { + client.on('message', (topic, p, packet) => { if (++count === max) { // BUGBUG: the client.end callback never gets called here // client.end((err) => done(err)) @@ -154,440 +155,502 @@ describe('MqttClient', () => { }) describe('flushing', () => { - it('should attempt to complete pending unsub and send on ping timeout', function test(done) { - this.timeout(10000) - const server2 = new MqttServer((serverClient) => { - serverClient.on('connect', (packet) => { - serverClient.connack({ returnCode: 0 }) - }) - }).listen(ports.PORTAND72) + it( + 'should attempt to complete pending unsub and send on ping timeout', + { + timeout: 10000, + }, + function _test(t, done) { + const server2 = new MqttServer((serverClient) => { + serverClient.on('connect', (packet) => { + serverClient.connack({ returnCode: 0 }) + }) + }).listen(ports.PORTAND72) - let pubCallbackCalled = false - let unsubscribeCallbackCalled = false - client = mqtt.connect({ - port: ports.PORTAND72, - host: 'localhost', - keepalive: 1, - connectTimeout: 350, - reconnectPeriod: 0, - }) - client.once('connect', () => { - client.publish( - 'fakeTopic', - 'fakeMessage', - { qos: 1 }, - (err) => { - assert.exists(err) - pubCallbackCalled = true - }, - ) - client.unsubscribe('fakeTopic', (err, result) => { - assert.exists(err) - unsubscribeCallbackCalled = true + let pubCallbackCalled = false + let unsubscribeCallbackCalled = false + client = mqtt.connect({ + port: ports.PORTAND72, + host: 'localhost', + keepalive: 1, + connectTimeout: 350, + reconnectPeriod: 0, }) - setTimeout(() => { - client.end((err1) => { - assert.strictEqual( - pubCallbackCalled && unsubscribeCallbackCalled, - true, - 'callbacks not invoked', - ) - server2.close((err2) => { - done(err1 || err2) - }) + client.once('connect', () => { + client.publish( + 'fakeTopic', + 'fakeMessage', + { qos: 1 }, + (err) => { + assert.exists(err) + pubCallbackCalled = true + }, + ) + client.unsubscribe('fakeTopic', (err, result) => { + assert.exists(err) + unsubscribeCallbackCalled = true }) - }, 5000) - }) - }) + setTimeout(() => { + client.end((err1) => { + assert.strictEqual( + pubCallbackCalled && unsubscribeCallbackCalled, + true, + 'callbacks not invoked', + ) + server2.close((err2) => { + done(err1 || err2) + }) + }) + }, 5000) + }) + }, + ) }) describe('reconnecting', () => { - it('should attempt to reconnect once server is down', function test(done) { - this.timeout(30000) - - const innerServer = fork( - path.join(__dirname, 'helpers', 'server_process.ts'), - { - execArgv: ['--inspect', '-r', 'ts-node/register'], - }, - ) - innerServer.on('close', (code) => { - if (code) { - done(util.format('child process closed with code %d', code)) - } - }) - - innerServer.on('exit', (code) => { - if (code) { - done(util.format('child process exited with code %d', code)) - } - }) - - client = mqtt.connect({ - port: 3481, - host: 'localhost', - keepalive: 1, - }) - client.once('connect', () => { - innerServer.kill('SIGINT') // mocks server shutdown - client.once('close', () => { - assert.exists(client['reconnectTimer']) - client.end(true, (err) => done(err)) + it( + 'should attempt to reconnect once server is down', + { + timeout: 30000, + }, + function _test(t, done) { + const innerServer = fork( + path.join(__dirname, 'helpers', 'server_process.ts'), + { + execArgv: ['--inspect', '-r', 'ts-node/register'], + }, + ) + innerServer.on('close', (code) => { + if (code) { + done( + util.format( + 'child process closed with code %d', + code, + ), + ) + } }) - }) - }) - - it('should reconnect if a connack is not received in an interval', function test(done) { - this.timeout(2000) - const server2 = net.createServer().listen(ports.PORTAND43) - - server2.on('connection', (c) => { - eos(c, () => { - server2.close() + innerServer.on('exit', (code) => { + if (code) { + done( + util.format( + 'child process exited with code %d', + code, + ), + ) + } }) - }) - server2.on('listening', () => { client = mqtt.connect({ - servers: [ - { port: ports.PORTAND43, host: 'localhost_fake' }, - { port: ports.PORT, host: 'localhost' }, - ], - connectTimeout: 500, + port: 3481, + host: 'localhost', + keepalive: 1, }) - - server.once('client', () => { - client.end(false, (err) => { - done(err) + client.once('connect', () => { + innerServer.kill('SIGINT') // mocks server shutdown + client.once('close', () => { + assert.exists(client['reconnectTimer']) + client.end(true, (err) => done(err)) }) }) - - client.once('connect', () => { - client.stream.destroy() + }, + ) + + it( + 'should reconnect if a connack is not received in an interval', + { + timeout: 2000, + }, + function _test(t, done) { + const server2 = net.createServer().listen(ports.PORTAND43) + + server2.on('connection', (c) => { + eos(c, () => { + server2.close() + }) }) - }) - }) - it('should not be cleared by the connack timer', function test(done) { - this.timeout(4000) - - const server2 = net.createServer().listen(ports.PORTAND44) + server2.on('listening', () => { + client = mqtt.connect({ + servers: [ + { port: ports.PORTAND43, host: 'localhost_fake' }, + { port: ports.PORT, host: 'localhost' }, + ], + connectTimeout: 500, + }) - server2.on('connection', (c) => { - c.destroy() - }) + server.once('client', () => { + client.end(false, (err) => { + done(err) + }) + }) - server2.once('listening', () => { - const connectTimeout = 1000 - const reconnectPeriod = 100 - const expectedReconnects = Math.floor( - connectTimeout / reconnectPeriod, - ) - let reconnects = 0 - client = mqtt.connect({ - port: ports.PORTAND44, - host: 'localhost', - connectTimeout, - reconnectPeriod, + client.once('connect', () => { + client.stream.destroy() + }) }) - - client.on('reconnect', () => { - reconnects++ - if (reconnects >= expectedReconnects) { - client.end(true, (err) => done(err)) - } + }, + ) + + it( + 'should not be cleared by the connack timer', + { + timeout: 4000, + }, + function _test(t, done) { + const server2 = net.createServer().listen(ports.PORTAND44) + + server2.on('connection', (c) => { + c.destroy() }) - }) - }) - - it('should not keep requeueing the first message when offline', function test(done) { - this.timeout(2500) - const server2 = serverBuilder('mqtt').listen(ports.PORTAND45) - client = mqtt.connect({ - port: ports.PORTAND45, - host: 'localhost', - connectTimeout: 350, - reconnectPeriod: 300, - }) - - server2.on('client', (serverClient) => { - client.publish('hello', 'world', { qos: 1 }, () => { - serverClient.destroy() - server2.close(() => { - debug('now publishing message in an offline state') - client.publish('hello', 'world', { qos: 1 }) + server2.once('listening', () => { + const connectTimeout = 1000 + const reconnectPeriod = 100 + const expectedReconnects = Math.floor( + connectTimeout / reconnectPeriod, + ) + let reconnects = 0 + client = mqtt.connect({ + port: ports.PORTAND44, + host: 'localhost', + connectTimeout, + reconnectPeriod, }) - }) - }) - - setTimeout(() => { - if (client.queue.length === 0) { - debug('calling final client.end()') - client.end(true, (err) => done(err)) - } else { - debug('calling client.end()') - // Do not call done. We want to trigger a reconnect here. - client.end(true) - } - }, 2000) - }) - - it('should not send the same subscribe multiple times on a flaky connection', function test(done) { - this.timeout(3500) - - const KILL_COUNT = 4 - const subIds = {} - let killedConnections = 0 - client = mqtt.connect({ - port: ports.PORTAND46, - host: 'localhost', - connectTimeout: 350, - reconnectPeriod: 300, - }) - const server2 = new MqttServer((serverClient) => { - debug('client received on server2.') - debug('subscribing to topic `topic`') - client.subscribe('topic', () => { - debug( - 'once subscribed to topic, end client, destroy serverClient, and close server.', - ) - serverClient.destroy() - server2.close(() => { - client.end(true, (err) => done(err)) + client.on('reconnect', () => { + reconnects++ + if (reconnects >= expectedReconnects) { + client.end(true, (err) => done(err)) + } }) }) + }, + ) + + it( + 'should not keep requeueing the first message when offline', + { + timeout: 2500, + }, + function _test(t, done) { + const server2 = serverBuilder('mqtt').listen(ports.PORTAND45) + client = mqtt.connect({ + port: ports.PORTAND45, + host: 'localhost', + connectTimeout: 350, + reconnectPeriod: 300, + }) - serverClient.on('subscribe', (packet) => { - if (killedConnections < KILL_COUNT) { - // Kill the first few sub attempts to simulate a flaky connection - killedConnections++ + server2.on('client', (serverClient) => { + client.publish('hello', 'world', { qos: 1 }, () => { serverClient.destroy() - } else { - // Keep track of acks - if (!subIds[packet.messageId]) { - subIds[packet.messageId] = 0 - } - subIds[packet.messageId]++ - if (subIds[packet.messageId] > 1) { - done( - new Error( - `Multiple duplicate acked subscriptions received for messageId ${packet.messageId}`, - ), - ) - client.end(true) - serverClient.end() - server2.close() - } - - serverClient.suback({ - messageId: packet.messageId, - granted: packet.subscriptions.map((e) => e.qos), + server2.close(() => { + debug('now publishing message in an offline state') + client.publish('hello', 'world', { qos: 1 }) }) - } - }) - }).listen(ports.PORTAND46) - }) - - it('should not fill the queue of subscribes if it cannot connect', function test(done) { - this.timeout(2500) - const server2 = net.createServer((stream) => { - const serverClient = new Connection(stream) - - serverClient.on('error', (e) => { - /* do nothing */ - }) - serverClient.on('connect', (packet) => { - serverClient.connack({ returnCode: 0 }) - serverClient.destroy() + }) }) - }) - server2.listen(ports.PORTAND48, () => { + setTimeout(() => { + if (client.queue.length === 0) { + debug('calling final client.end()') + client.end(true, (err) => done(err)) + } else { + debug('calling client.end()') + // Do not call done. We want to trigger a reconnect here. + client.end(true) + } + }, 2000) + }, + ) + + it( + 'should not send the same subscribe multiple times on a flaky connection', + { + timeout: 3500, + }, + function _test(t, done) { + const KILL_COUNT = 4 + const subIds = {} + let killedConnections = 0 client = mqtt.connect({ - port: ports.PORTAND48, + port: ports.PORTAND46, host: 'localhost', connectTimeout: 350, reconnectPeriod: 300, }) - client.subscribe('hello') - - setTimeout(() => { - assert.equal(client.queue.length, 1) - client.end(true, (err) => done(err)) - }, 1000) - }) - }) - - it('should not send the same publish multiple times on a flaky connection', function test(done) { - this.timeout(3500) - - const KILL_COUNT = 4 - let killedConnections = 0 - const pubIds = {} - client = mqtt.connect({ - port: ports.PORTAND47, - host: 'localhost', - connectTimeout: 350, - reconnectPeriod: 300, - }) + const server2 = new MqttServer((serverClient) => { + debug('client received on server2.') + debug('subscribing to topic `topic`') + client.subscribe('topic', () => { + debug( + 'once subscribed to topic, end client, destroy serverClient, and close server.', + ) + serverClient.destroy() + server2.close(() => { + client.end(true, (err) => done(err)) + }) + }) - const server2 = net - .createServer((stream) => { - const serverClient = new Connection(stream) - serverClient.on('error', () => {}) - serverClient.on('connect', (packet) => { - if (packet.clientId === 'invalid') { - serverClient.connack({ returnCode: 2 }) + serverClient.on('subscribe', (packet) => { + if (killedConnections < KILL_COUNT) { + // Kill the first few sub attempts to simulate a flaky connection + killedConnections++ + serverClient.destroy() } else { - serverClient.connack({ returnCode: 0 }) + // Keep track of acks + if (!subIds[packet.messageId]) { + subIds[packet.messageId] = 0 + } + subIds[packet.messageId]++ + if (subIds[packet.messageId] > 1) { + done( + new Error( + `Multiple duplicate acked subscriptions received for messageId ${packet.messageId}`, + ), + ) + client.end(true) + serverClient.end() + server2.close() + } + + serverClient.suback({ + messageId: packet.messageId, + granted: packet.subscriptions.map((e) => e.qos), + }) } }) + }).listen(ports.PORTAND46) + }, + ) + + it( + 'should not fill the queue of subscribes if it cannot connect', + { + timeout: 2500, + }, + function _test(t, done) { + const server2 = net.createServer((stream) => { + const serverClient = new Connection(stream) - server2.emit('client', serverClient) + serverClient.on('error', (e) => { + /* do nothing */ + }) + serverClient.on('connect', (packet) => { + serverClient.connack({ returnCode: 0 }) + serverClient.destroy() + }) }) - .listen(ports.PORTAND47) - server2.on('client', (serverClient) => { - client.publish('topic', 'data', { qos: 1 }, () => { - client.end(true, (err1) => { - server2.close((err2) => { - done(err1 || err2) - }) + server2.listen(ports.PORTAND48, () => { + client = mqtt.connect({ + port: ports.PORTAND48, + host: 'localhost', + connectTimeout: 350, + reconnectPeriod: 300, }) + + client.subscribe('hello') + + setTimeout(() => { + assert.equal(client.queue.length, 1) + client.end(true, (err) => done(err)) + }, 1000) + }) + }, + ) + + it( + 'should not send the same publish multiple times on a flaky connection', + { + timeout: 3500, + }, + function _test(t, done) { + const KILL_COUNT = 4 + let killedConnections = 0 + const pubIds = {} + client = mqtt.connect({ + port: ports.PORTAND47, + host: 'localhost', + connectTimeout: 350, + reconnectPeriod: 300, }) - serverClient.on('publish', function onPublish(packet) { - if (killedConnections < KILL_COUNT) { - // Kill the first few pub attempts to simulate a flaky connection - killedConnections++ - serverClient.destroy() + const server2 = net + .createServer((stream) => { + const serverClient = new Connection(stream) + serverClient.on('error', () => {}) + serverClient.on('connect', (packet) => { + if (packet.clientId === 'invalid') { + serverClient.connack({ returnCode: 2 }) + } else { + serverClient.connack({ returnCode: 0 }) + } + }) - // to avoid receiving inflight messages - serverClient.removeListener('publish', onPublish) - } else { - // Keep track of acks - if (!pubIds[packet.messageId]) { - pubIds[packet.messageId] = 0 - } + server2.emit('client', serverClient) + }) + .listen(ports.PORTAND47) - pubIds[packet.messageId]++ + server2.on('client', (serverClient) => { + client.publish('topic', 'data', { qos: 1 }, () => { + client.end(true, (err1) => { + server2.close((err2) => { + done(err1 || err2) + }) + }) + }) - if (pubIds[packet.messageId] > 1) { - done( - new Error( - `Multiple duplicate acked publishes received for messageId ${packet.messageId}`, - ), - ) - client.end(true) + serverClient.on('publish', function onPublish(packet) { + if (killedConnections < KILL_COUNT) { + // Kill the first few pub attempts to simulate a flaky connection + killedConnections++ serverClient.destroy() - server2.close() - } - serverClient.puback(packet) - } + // to avoid receiving inflight messages + serverClient.removeListener('publish', onPublish) + } else { + // Keep track of acks + if (!pubIds[packet.messageId]) { + pubIds[packet.messageId] = 0 + } + + pubIds[packet.messageId]++ + + if (pubIds[packet.messageId] > 1) { + done( + new Error( + `Multiple duplicate acked publishes received for messageId ${packet.messageId}`, + ), + ) + client.end(true) + serverClient.destroy() + server2.close() + } + + serverClient.puback(packet) + } + }) }) - }) - }) + }, + ) }) - it('check emit error on checkDisconnection w/o callback', function test(done) { - this.timeout(15000) - - const server2 = new MqttServer((c) => { - c.on('connect', (packet) => { - c.connack({ - reasonCode: 0, + it( + 'check emit error on checkDisconnection w/o callback', + { + timeout: 15000, + }, + function _test(t, done) { + const server2 = new MqttServer((c) => { + c.on('connect', (packet) => { + c.connack({ + reasonCode: 0, + }) }) - }) - c.on('publish', (packet) => { - setImmediate(() => { - packet.reasonCode = 0 - c.puback(packet) + c.on('publish', (packet) => { + setImmediate(() => { + packet.reasonCode = 0 + c.puback(packet) + }) }) - }) - }).listen(ports.PORTAND118) + }).listen(ports.PORTAND118) - const opts: IClientOptions = { - host: 'localhost', - port: ports.PORTAND118, - protocolVersion: 5, - } - client = mqtt.connect(opts) + const opts: IClientOptions = { + host: 'localhost', + port: ports.PORTAND118, + protocolVersion: 5, + } + client = mqtt.connect(opts) - // wait for the client to receive an error... - client.on('error', (error) => { - assert.equal(error.message, 'client disconnecting') - server2.close((err) => done(err)) - }) - client.on('connect', () => { - client.end(() => { - client['_checkDisconnecting']() + // wait for the client to receive an error... + client.on('error', (error) => { + assert.equal(error.message, 'client disconnecting') + server2.close((err) => done(err)) }) - }) - }) + client.on('connect', () => { + client.end(() => { + client['_checkDisconnecting']() + }) + }) + }, + ) describe('async methods', () => { - it('connect-subscribe-unsubscribe-end', function test() { - this.timeout(5000) - - // eslint-disable-next-line no-async-promise-executor - return new Promise(async (resolve, reject) => { - server.once('client', (serverClient) => { - serverClient.on('publish', async (packet) => { - assert.equal(packet.topic, 'hello') - assert.equal(packet.payload.toString(), 'world') - await client.unsubscribeAsync('hello') - await client.endAsync() - resolve() + it( + 'connect-subscribe-unsubscribe-end', + { + timeout: 15000, + }, + function _test(t, done) { + // eslint-disable-next-line no-async-promise-executor + return new Promise(async (resolve, reject) => { + server.once('client', (serverClient) => { + serverClient.on('publish', async (packet) => { + assert.equal(packet.topic, 'hello') + assert.equal(packet.payload.toString(), 'world') + await client.unsubscribeAsync('hello') + await client.endAsync() + resolve() + }) }) - }) - - client = await mqtt.connectAsync(config) - - const sub = await client.subscribeAsync('hello') - assert.equal(sub[0].topic, 'hello') - assert.equal(sub[0].qos, 0) + client = await mqtt.connectAsync(config) - await client.publishAsync('hello', 'world') - }) - }) + const sub = await client.subscribeAsync('hello') - it('connect should throw error', async function test() { - this.timeout(5000) - let error = false + assert.equal(sub[0].topic, 'hello') + assert.equal(sub[0].qos, 0) - try { - await mqtt.connectAsync({ - port: 1000, - host: '127.0.0.1', + await client.publishAsync('hello', 'world') }) - } catch (err) { - error = true - assert.isTrue(err.message.includes('ECONNREFUSED')) - } - - assert.isTrue(error) - }) - - it('publish should throw error', async function test() { - this.timeout(5000) - let error = false + }, + ) + + it( + 'connect should throw error', + { + timeout: 5000, + }, + async function _test(t, done) { + let error = false + + try { + await mqtt.connectAsync({ + port: 1000, + host: '127.0.0.1', + }) + } catch (err) { + error = true + assert.isTrue(err.message.includes('ECONNREFUSED')) + } - try { - client = await mqtt.connectAsync(config) - client.disconnecting = true - await client.publishAsync('#/#', 'world') - } catch (err) { - error = true - assert.equal(err.message, 'client disconnecting') - } + assert.isTrue(error) + }, + ) + + it( + 'publish should throw error', + { + timeout: 5000, + }, + async function _test(t, done) { + let error = false + + try { + client = await mqtt.connectAsync(config) + client.disconnecting = true + await client.publishAsync('#/#', 'world') + } catch (err) { + error = true + assert.equal(err.message, 'client disconnecting') + } - assert.isTrue(error) - }) + assert.isTrue(error) + }, + ) }) }) diff --git a/test/client_mqtt5.ts b/test/client_mqtt5.ts index d17c48266..66950b951 100644 --- a/test/client_mqtt5.ts +++ b/test/client_mqtt5.ts @@ -5,6 +5,7 @@ import { MqttServer } from './server' import serverBuilder from './server_helpers_for_client_tests' import ports from './helpers/port_list' import { ErrorWithReasonCode } from '../src/lib/shared' +import { describe, it } from 'node:test' describe('MQTT 5.0', () => { const server = serverBuilder('mqtt').listen(ports.PORTAND115) @@ -17,193 +18,84 @@ describe('MQTT 5.0', () => { abstractClientTests(server, config) - it('topic should be complemented on receive', function test(done) { - this.timeout(15000) - - const opts: mqtt.IClientOptions = { - host: 'localhost', - port: ports.PORTAND103, - protocolVersion: 5, - properties: { - topicAliasMaximum: 3, - }, - } - const client = mqtt.connect(opts) - let publishCount = 0 - const server2 = new MqttServer((serverClient) => { - serverClient.on('connect', (packet) => { - assert.strictEqual(packet.properties.topicAliasMaximum, 3) - serverClient.connack({ - reasonCode: 0, - }) - // register topicAlias - serverClient.publish({ - messageId: 0, - topic: 'test1', - payload: 'Message', - qos: 0, - properties: { topicAlias: 1 }, - }) - // use topicAlias - serverClient.publish({ - messageId: 0, - topic: '', - payload: 'Message', - qos: 0, - properties: { topicAlias: 1 }, - }) - // overwrite registered topicAlias - serverClient.publish({ - messageId: 0, - topic: 'test2', - payload: 'Message', - qos: 0, - properties: { topicAlias: 1 }, - }) - // use topicAlias - serverClient.publish({ - messageId: 0, - topic: '', - payload: 'Message', - qos: 0, - properties: { topicAlias: 1 }, - }) - }) - }).listen(ports.PORTAND103) - - client.on('message', (topic, messagee, packet) => { - switch (publishCount++) { - case 0: - assert.strictEqual(topic, 'test1') - assert.strictEqual(packet.topic, 'test1') - assert.strictEqual(packet.properties.topicAlias, 1) - break - case 1: - assert.strictEqual(topic, 'test1') - assert.strictEqual(packet.topic, '') - assert.strictEqual(packet.properties.topicAlias, 1) - break - case 2: - assert.strictEqual(topic, 'test2') - assert.strictEqual(packet.topic, 'test2') - assert.strictEqual(packet.properties.topicAlias, 1) - break - case 3: - assert.strictEqual(topic, 'test2') - assert.strictEqual(packet.topic, '') - assert.strictEqual(packet.properties.topicAlias, 1) - client.end(true, (err1) => { - server2.close((err2) => { - done(err1 || err2) - }) - }) - break + it( + 'topic should be complemented on receive', + { + timeout: 15000, + }, + function _test(t, done) { + const opts: mqtt.IClientOptions = { + host: 'localhost', + port: ports.PORTAND103, + protocolVersion: 5, + properties: { + topicAliasMaximum: 3, + }, } - }) - }) - - it('registered topic alias should automatically used if autoUseTopicAlias is true', function test(done) { - this.timeout(15000) - - const opts: mqtt.IClientOptions = { - host: 'localhost', - port: ports.PORTAND103, - protocolVersion: 5, - autoUseTopicAlias: true, - } - const client = mqtt.connect(opts) - - let publishCount = 0 - const server2 = new MqttServer((serverClient) => { - serverClient.on('connect', (packet) => { - serverClient.connack({ - reasonCode: 0, - properties: { - topicAliasMaximum: 3, - }, + const client = mqtt.connect(opts) + let publishCount = 0 + const server2 = new MqttServer((serverClient) => { + serverClient.on('connect', (packet) => { + assert.strictEqual(packet.properties.topicAliasMaximum, 3) + serverClient.connack({ + reasonCode: 0, + }) + // register topicAlias + serverClient.publish({ + messageId: 0, + topic: 'test1', + payload: 'Message', + qos: 0, + properties: { topicAlias: 1 }, + }) + // use topicAlias + serverClient.publish({ + messageId: 0, + topic: '', + payload: 'Message', + qos: 0, + properties: { topicAlias: 1 }, + }) + // overwrite registered topicAlias + serverClient.publish({ + messageId: 0, + topic: 'test2', + payload: 'Message', + qos: 0, + properties: { topicAlias: 1 }, + }) + // use topicAlias + serverClient.publish({ + messageId: 0, + topic: '', + payload: 'Message', + qos: 0, + properties: { topicAlias: 1 }, + }) }) - }) - serverClient.on('publish', (packet) => { + }).listen(ports.PORTAND103) + + client.on('message', (topic, messagee, packet) => { switch (publishCount++) { case 0: + assert.strictEqual(topic, 'test1') assert.strictEqual(packet.topic, 'test1') assert.strictEqual(packet.properties.topicAlias, 1) break case 1: + assert.strictEqual(topic, 'test1') assert.strictEqual(packet.topic, '') assert.strictEqual(packet.properties.topicAlias, 1) break case 2: - assert.strictEqual(packet.topic, '') - assert.strictEqual(packet.properties.topicAlias, 1) - client.end(true, (err1) => { - server2.close((err2) => { - done(err1 || err2) - }) - }) - break - } - }) - }).listen(ports.PORTAND103) - - client.on('connect', () => { - // register topicAlias - client.publish('test1', 'Message', { - properties: { topicAlias: 1 }, - }) - // use topicAlias - client.publish('', 'Message', { properties: { topicAlias: 1 } }) - // use topicAlias by autoApplyTopicAlias - client.publish('test1', 'Message') - }) - }) - - it('topicAlias is automatically used if autoAssignTopicAlias is true', function test(done) { - this.timeout(15000) - - const opts: mqtt.IClientOptions = { - host: 'localhost', - port: ports.PORTAND103, - protocolVersion: 5, - autoAssignTopicAlias: true, - } - const client = mqtt.connect(opts) - - let publishCount = 0 - const server2 = new MqttServer((serverClient) => { - serverClient.on('connect', (packet) => { - serverClient.connack({ - reasonCode: 0, - properties: { - topicAliasMaximum: 3, - }, - }) - }) - serverClient.on('publish', (packet) => { - switch (publishCount++) { - case 0: - assert.strictEqual(packet.topic, 'test1') - assert.strictEqual(packet.properties.topicAlias, 1) - break - case 1: + assert.strictEqual(topic, 'test2') assert.strictEqual(packet.topic, 'test2') - assert.strictEqual(packet.properties.topicAlias, 2) - break - case 2: - assert.strictEqual(packet.topic, 'test3') - assert.strictEqual(packet.properties.topicAlias, 3) + assert.strictEqual(packet.properties.topicAlias, 1) break case 3: + assert.strictEqual(topic, 'test2') assert.strictEqual(packet.topic, '') assert.strictEqual(packet.properties.topicAlias, 1) - break - case 4: - assert.strictEqual(packet.topic, '') - assert.strictEqual(packet.properties.topicAlias, 3) - break - case 5: - assert.strictEqual(packet.topic, 'test4') - assert.strictEqual(packet.properties.topicAlias, 2) client.end(true, (err1) => { server2.close((err2) => { done(err1 || err2) @@ -212,562 +104,803 @@ describe('MQTT 5.0', () => { break } }) - }).listen(ports.PORTAND103) + }, + ) + + it( + 'registered topic alias should automatically used if autoUseTopicAlias is true', + { + timeout: 15000, + }, + function _test(t, done) { + const opts: mqtt.IClientOptions = { + host: 'localhost', + port: ports.PORTAND103, + protocolVersion: 5, + autoUseTopicAlias: true, + } + const client = mqtt.connect(opts) + + let publishCount = 0 + const server2 = new MqttServer((serverClient) => { + serverClient.on('connect', (packet) => { + serverClient.connack({ + reasonCode: 0, + properties: { + topicAliasMaximum: 3, + }, + }) + }) + serverClient.on('publish', (packet) => { + switch (publishCount++) { + case 0: + assert.strictEqual(packet.topic, 'test1') + assert.strictEqual(packet.properties.topicAlias, 1) + break + case 1: + assert.strictEqual(packet.topic, '') + assert.strictEqual(packet.properties.topicAlias, 1) + break + case 2: + assert.strictEqual(packet.topic, '') + assert.strictEqual(packet.properties.topicAlias, 1) + client.end(true, (err1) => { + server2.close((err2) => { + done(err1 || err2) + }) + }) + break + } + }) + }).listen(ports.PORTAND103) - client.on('connect', () => { - // register topicAlias - client.publish('test1', 'Message') - client.publish('test2', 'Message') - client.publish('test3', 'Message') + client.on('connect', () => { + // register topicAlias + client.publish('test1', 'Message', { + properties: { topicAlias: 1 }, + }) + // use topicAlias + client.publish('', 'Message', { properties: { topicAlias: 1 } }) + // use topicAlias by autoApplyTopicAlias + client.publish('test1', 'Message') + }) + }, + ) + + it( + 'topicAlias is automatically used if autoAssignTopicAlias is true', + { + timeout: 15000, + }, + function _test(t, done) { + const opts: mqtt.IClientOptions = { + host: 'localhost', + port: ports.PORTAND103, + protocolVersion: 5, + autoAssignTopicAlias: true, + } + const client = mqtt.connect(opts) + + let publishCount = 0 + const server2 = new MqttServer((serverClient) => { + serverClient.on('connect', (packet) => { + serverClient.connack({ + reasonCode: 0, + properties: { + topicAliasMaximum: 3, + }, + }) + }) + serverClient.on('publish', (packet) => { + switch (publishCount++) { + case 0: + assert.strictEqual(packet.topic, 'test1') + assert.strictEqual(packet.properties.topicAlias, 1) + break + case 1: + assert.strictEqual(packet.topic, 'test2') + assert.strictEqual(packet.properties.topicAlias, 2) + break + case 2: + assert.strictEqual(packet.topic, 'test3') + assert.strictEqual(packet.properties.topicAlias, 3) + break + case 3: + assert.strictEqual(packet.topic, '') + assert.strictEqual(packet.properties.topicAlias, 1) + break + case 4: + assert.strictEqual(packet.topic, '') + assert.strictEqual(packet.properties.topicAlias, 3) + break + case 5: + assert.strictEqual(packet.topic, 'test4') + assert.strictEqual(packet.properties.topicAlias, 2) + client.end(true, (err1) => { + server2.close((err2) => { + done(err1 || err2) + }) + }) + break + } + }) + }).listen(ports.PORTAND103) - // use topicAlias - client.publish('test1', 'Message') - client.publish('test3', 'Message') + client.on('connect', () => { + // register topicAlias + client.publish('test1', 'Message') + client.publish('test2', 'Message') + client.publish('test3', 'Message') - // renew LRU topicAlias - client.publish('test4', 'Message') - }) - }) + // use topicAlias + client.publish('test1', 'Message') + client.publish('test3', 'Message') - it('topicAlias should be removed and topic restored on resend', function test(done) { - this.timeout(15000) - - const incomingStore = new mqtt.Store({ clean: false }) - const outgoingStore = new mqtt.Store({ clean: false }) - const opts: mqtt.IClientOptions = { - host: 'localhost', - port: ports.PORTAND103, - protocolVersion: 5, - clientId: 'cid1', - incomingStore, - outgoingStore, - clean: false, - reconnectPeriod: 100, - } - const client = mqtt.connect(opts) - - let connectCount = 0 - let publishCount = 0 - const server2 = new MqttServer((serverClient) => { - serverClient.on('connect', (packet) => { - switch (connectCount++) { - case 0: - serverClient.connack({ - reasonCode: 0, - sessionPresent: false, - properties: { - topicAliasMaximum: 3, - }, - }) - break - case 1: - serverClient.connack({ - reasonCode: 0, - sessionPresent: true, - properties: { - topicAliasMaximum: 3, - }, - }) - break - } + // renew LRU topicAlias + client.publish('test4', 'Message') }) - serverClient.on('publish', (packet) => { - switch (publishCount++) { - case 0: - assert.strictEqual(packet.topic, 'test1') - assert.strictEqual(packet.properties.topicAlias, 1) - break - case 1: - assert.strictEqual(packet.topic, '') - assert.strictEqual(packet.properties.topicAlias, 1) - setImmediate(() => { - serverClient.stream.destroy() - }) - break - case 2: { - assert.strictEqual(packet.topic, 'test1') - let alias1 - if (packet.properties) { - alias1 = packet.properties.topicAlias - } - assert.strictEqual(alias1, undefined) - serverClient.puback({ messageId: packet.messageId }) - break + }, + ) + + it( + 'topicAlias should be removed and topic restored on resend', + { + timeout: 15000, + }, + function _test(t, done) { + const incomingStore = new mqtt.Store({ clean: false }) + const outgoingStore = new mqtt.Store({ clean: false }) + const opts: mqtt.IClientOptions = { + host: 'localhost', + port: ports.PORTAND103, + protocolVersion: 5, + clientId: 'cid1', + incomingStore, + outgoingStore, + clean: false, + reconnectPeriod: 100, + } + const client = mqtt.connect(opts) + + let connectCount = 0 + let publishCount = 0 + const server2 = new MqttServer((serverClient) => { + serverClient.on('connect', (packet) => { + switch (connectCount++) { + case 0: + serverClient.connack({ + reasonCode: 0, + sessionPresent: false, + properties: { + topicAliasMaximum: 3, + }, + }) + break + case 1: + serverClient.connack({ + reasonCode: 0, + sessionPresent: true, + properties: { + topicAliasMaximum: 3, + }, + }) + break } - case 3: { - assert.strictEqual(packet.topic, 'test1') - let alias2 - if (packet.properties) { - alias2 = packet.properties.topicAlias + }) + serverClient.on('publish', (packet) => { + switch (publishCount++) { + case 0: + assert.strictEqual(packet.topic, 'test1') + assert.strictEqual(packet.properties.topicAlias, 1) + break + case 1: + assert.strictEqual(packet.topic, '') + assert.strictEqual(packet.properties.topicAlias, 1) + setImmediate(() => { + serverClient.stream.destroy() + }) + break + case 2: { + assert.strictEqual(packet.topic, 'test1') + let alias1 + if (packet.properties) { + alias1 = packet.properties.topicAlias + } + assert.strictEqual(alias1, undefined) + serverClient.puback({ messageId: packet.messageId }) + break } - assert.strictEqual(alias2, undefined) - serverClient.puback({ messageId: packet.messageId }) - client.end(true, (err1) => { - server2.close((err2) => { - done(err1 || err2) + case 3: { + assert.strictEqual(packet.topic, 'test1') + let alias2 + if (packet.properties) { + alias2 = packet.properties.topicAlias + } + assert.strictEqual(alias2, undefined) + serverClient.puback({ messageId: packet.messageId }) + client.end(true, (err1) => { + server2.close((err2) => { + done(err1 || err2) + }) }) - }) - break + break + } } - } - }) - }).listen(ports.PORTAND103) - - client.once('connect', () => { - // register topicAlias - client.publish('test1', 'Message', { - qos: 1, - properties: { topicAlias: 1 }, - }) - // use topicAlias - client.publish('', 'Message', { - qos: 1, - properties: { topicAlias: 1 }, - }) - }) - }) + }) + }).listen(ports.PORTAND103) - it('topicAlias should be removed and topic restored on offline publish', function test(done) { - this.timeout(15000) - - const incomingStore = new mqtt.Store({ clean: false }) - const outgoingStore = new mqtt.Store({ clean: false }) - const opts: mqtt.IClientOptions = { - host: 'localhost', - port: ports.PORTAND103, - protocolVersion: 5, - clientId: 'cid1', - incomingStore, - outgoingStore, - clean: false, - reconnectPeriod: 100, - } - const client = mqtt.connect(opts) - - let connectCount = 0 - let publishCount = 0 - const server2 = new MqttServer((serverClient) => { - serverClient.on('connect', (packet) => { - switch (connectCount++) { - case 0: - serverClient.connack({ - reasonCode: 0, - sessionPresent: false, - properties: { - topicAliasMaximum: 3, - }, - }) - setImmediate(() => { - serverClient.stream.destroy() - }) - break - case 1: - serverClient.connack({ - reasonCode: 0, - sessionPresent: true, - properties: { - topicAliasMaximum: 3, - }, - }) - break - } + client.once('connect', () => { + // register topicAlias + client.publish('test1', 'Message', { + qos: 1, + properties: { topicAlias: 1 }, + }) + // use topicAlias + client.publish('', 'Message', { + qos: 1, + properties: { topicAlias: 1 }, + }) }) - serverClient.on('publish', (packet) => { - switch (publishCount++) { - case 0: { - assert.strictEqual(packet.topic, 'test1') - let alias1 - if (packet.properties) { - alias1 = packet.properties.topicAlias - } - assert.strictEqual(alias1, undefined) - assert.strictEqual(packet.qos, 1) - serverClient.puback({ messageId: packet.messageId }) - break + }, + ) + + it( + 'topicAlias should be removed and topic restored on offline publish', + { + timeout: 15000, + }, + function _test(t, done) { + const incomingStore = new mqtt.Store({ clean: false }) + const outgoingStore = new mqtt.Store({ clean: false }) + const opts: mqtt.IClientOptions = { + host: 'localhost', + port: ports.PORTAND103, + protocolVersion: 5, + clientId: 'cid1', + incomingStore, + outgoingStore, + clean: false, + reconnectPeriod: 100, + } + const client = mqtt.connect(opts) + + let connectCount = 0 + let publishCount = 0 + const server2 = new MqttServer((serverClient) => { + serverClient.on('connect', (packet) => { + switch (connectCount++) { + case 0: + serverClient.connack({ + reasonCode: 0, + sessionPresent: false, + properties: { + topicAliasMaximum: 3, + }, + }) + setImmediate(() => { + serverClient.stream.destroy() + }) + break + case 1: + serverClient.connack({ + reasonCode: 0, + sessionPresent: true, + properties: { + topicAliasMaximum: 3, + }, + }) + break } - case 1: { - assert.strictEqual(packet.topic, 'test1') - let alias2 - if (packet.properties) { - alias2 = packet.properties.topicAlias + }) + serverClient.on('publish', (packet) => { + switch (publishCount++) { + case 0: { + assert.strictEqual(packet.topic, 'test1') + let alias1 + if (packet.properties) { + alias1 = packet.properties.topicAlias + } + assert.strictEqual(alias1, undefined) + assert.strictEqual(packet.qos, 1) + serverClient.puback({ messageId: packet.messageId }) + break } - assert.strictEqual(alias2, undefined) - assert.strictEqual(packet.qos, 0) - break - } - case 2: { - assert.strictEqual(packet.topic, 'test1') - let alias3 - if (packet.properties) { - alias3 = packet.properties.topicAlias + case 1: { + assert.strictEqual(packet.topic, 'test1') + let alias2 + if (packet.properties) { + alias2 = packet.properties.topicAlias + } + assert.strictEqual(alias2, undefined) + assert.strictEqual(packet.qos, 0) + break + } + case 2: { + assert.strictEqual(packet.topic, 'test1') + let alias3 + if (packet.properties) { + alias3 = packet.properties.topicAlias + } + assert.strictEqual(alias3, undefined) + assert.strictEqual(packet.qos, 0) + client.end(true, (err1) => { + server2.close((err2) => { + done(err1 || err2) + }) + }) + break } - assert.strictEqual(alias3, undefined) - assert.strictEqual(packet.qos, 0) + } + }) + }).listen(ports.PORTAND103) + + client.once('close', () => { + // register topicAlias + client.publish('test1', 'Message', { + qos: 0, + properties: { topicAlias: 1 }, + }) + // use topicAlias + client.publish('', 'Message', { + qos: 0, + properties: { topicAlias: 1 }, + }) + client.publish('', 'Message', { + qos: 1, + properties: { topicAlias: 1 }, + }) + }) + }, + ) + + it( + 'should error cb call if PUBLISH out of range topicAlias', + { + timeout: 15000, + }, + function _test(t, done) { + const opts: mqtt.IClientOptions = { + host: 'localhost', + port: ports.PORTAND103, + protocolVersion: 5, + } + const client = mqtt.connect(opts) + const server2 = new MqttServer((serverClient) => { + serverClient.on('connect', (packet) => { + serverClient.connack({ + reasonCode: 0, + sessionPresent: false, + properties: { + topicAliasMaximum: 3, + }, + }) + }) + }).listen(ports.PORTAND103) + + client.on('connect', () => { + // register topicAlias + client.publish( + 'test1', + 'Message', + { properties: { topicAlias: 4 } }, + (error) => { + assert.strictEqual( + error.message, + 'Sending Topic Alias out of range', + ) client.end(true, (err1) => { server2.close((err2) => { done(err1 || err2) }) }) - break - } - } - }) - }).listen(ports.PORTAND103) - - client.once('close', () => { - // register topicAlias - client.publish('test1', 'Message', { - qos: 0, - properties: { topicAlias: 1 }, - }) - // use topicAlias - client.publish('', 'Message', { - qos: 0, - properties: { topicAlias: 1 }, - }) - client.publish('', 'Message', { - qos: 1, - properties: { topicAlias: 1 }, + }, + ) }) - }) - }) + }, + ) + + it( + 'should error cb call if PUBLISH out of range topicAlias on topicAlias disabled by broker', + { + timeout: 15000, + }, + function _test(t, done) { + const opts: mqtt.IClientOptions = { + host: 'localhost', + port: ports.PORTAND103, + protocolVersion: 5, + } + const client = mqtt.connect(opts) + const server2 = new MqttServer((serverClient) => { + serverClient.on('connect', (packet) => { + serverClient.connack({ + reasonCode: 0, + sessionPresent: false, + }) + }) + }).listen(ports.PORTAND103) - it('should error cb call if PUBLISH out of range topicAlias', function test(done) { - this.timeout(15000) - - const opts: mqtt.IClientOptions = { - host: 'localhost', - port: ports.PORTAND103, - protocolVersion: 5, - } - const client = mqtt.connect(opts) - const server2 = new MqttServer((serverClient) => { - serverClient.on('connect', (packet) => { - serverClient.connack({ - reasonCode: 0, - sessionPresent: false, - properties: { - topicAliasMaximum: 3, + client.on('connect', () => { + // register topicAlias + client.publish( + 'test1', + 'Message', + { properties: { topicAlias: 1 } }, + (error) => { + assert.strictEqual( + error.message, + 'Sending Topic Alias out of range', + ) + client.end(true, (err1) => { + server2.close((err2) => { + done(err1 || err2) + }) + }) }, - }) + ) }) - }).listen(ports.PORTAND103) - - client.on('connect', () => { - // register topicAlias - client.publish( - 'test1', - 'Message', - { properties: { topicAlias: 4 } }, - (error) => { - assert.strictEqual( - error.message, - 'Sending Topic Alias out of range', - ) - client.end(true, (err1) => { - server2.close((err2) => { - done(err1 || err2) - }) - }) + }, + ) + + it( + 'should throw an error if broker PUBLISH out of range topicAlias', + { + timeout: 15000, + }, + function _test(t, done) { + const opts: mqtt.IClientOptions = { + host: 'localhost', + port: ports.PORTAND103, + protocolVersion: 5, + properties: { + topicAliasMaximum: 3, }, - ) - }) - }) + } + const client = mqtt.connect(opts) + const server2 = new MqttServer((serverClient) => { + serverClient.on('connect', (packet) => { + serverClient.connack({ + reasonCode: 0, + sessionPresent: false, + }) + // register out of range topicAlias + serverClient.publish({ + messageId: 0, + topic: 'test1', + payload: 'Message', + qos: 0, + properties: { topicAlias: 4 }, + }) + }) + }).listen(ports.PORTAND103) - it('should error cb call if PUBLISH out of range topicAlias on topicAlias disabled by broker', function test(done) { - this.timeout(15000) - - const opts: mqtt.IClientOptions = { - host: 'localhost', - port: ports.PORTAND103, - protocolVersion: 5, - } - const client = mqtt.connect(opts) - const server2 = new MqttServer((serverClient) => { - serverClient.on('connect', (packet) => { - serverClient.connack({ - reasonCode: 0, - sessionPresent: false, + client.on('error', (error) => { + assert.strictEqual( + error.message, + 'Received Topic Alias is out of range', + ) + client.end(true, (err1) => { + server2.close((err2) => { + done(err1 || err2) + }) }) }) - }).listen(ports.PORTAND103) - - client.on('connect', () => { - // register topicAlias - client.publish( - 'test1', - 'Message', - { properties: { topicAlias: 1 } }, - (error) => { - assert.strictEqual( - error.message, - 'Sending Topic Alias out of range', - ) - client.end(true, (err1) => { - server2.close((err2) => { - done(err1 || err2) - }) - }) + }, + ) + + it( + 'should throw an error if broker PUBLISH topicAlias:0', + { + timeout: 15000, + }, + function _test(t, done) { + const opts: mqtt.IClientOptions = { + host: 'localhost', + port: ports.PORTAND103, + protocolVersion: 5, + properties: { + topicAliasMaximum: 3, }, - ) - }) - }) - - it('should throw an error if broker PUBLISH out of range topicAlias', function test(done) { - this.timeout(15000) - - const opts: mqtt.IClientOptions = { - host: 'localhost', - port: ports.PORTAND103, - protocolVersion: 5, - properties: { - topicAliasMaximum: 3, - }, - } - const client = mqtt.connect(opts) - const server2 = new MqttServer((serverClient) => { - serverClient.on('connect', (packet) => { - serverClient.connack({ - reasonCode: 0, - sessionPresent: false, - }) - // register out of range topicAlias - serverClient.publish({ - messageId: 0, - topic: 'test1', - payload: 'Message', - qos: 0, - properties: { topicAlias: 4 }, + } + const client = mqtt.connect(opts) + const server2 = new MqttServer((serverClient) => { + serverClient.on('connect', (packet) => { + serverClient.connack({ + reasonCode: 0, + sessionPresent: false, + }) + // register out of range topicAlias + serverClient.publish({ + messageId: 0, + topic: 'test1', + payload: 'Message', + qos: 0, + properties: { topicAlias: 0 }, + }) }) - }) - }).listen(ports.PORTAND103) + }).listen(ports.PORTAND103) - client.on('error', (error) => { - assert.strictEqual( - error.message, - 'Received Topic Alias is out of range', - ) - client.end(true, (err1) => { - server2.close((err2) => { - done(err1 || err2) + client.on('error', (error) => { + assert.strictEqual( + error.message, + 'Received Topic Alias is out of range', + ) + client.end(true, (err1) => { + server2.close((err2) => { + done(err1 || err2) + }) }) }) - }) - }) - - it('should throw an error if broker PUBLISH topicAlias:0', function test(done) { - this.timeout(15000) - - const opts: mqtt.IClientOptions = { - host: 'localhost', - port: ports.PORTAND103, - protocolVersion: 5, - properties: { - topicAliasMaximum: 3, - }, - } - const client = mqtt.connect(opts) - const server2 = new MqttServer((serverClient) => { - serverClient.on('connect', (packet) => { - serverClient.connack({ - reasonCode: 0, - sessionPresent: false, - }) - // register out of range topicAlias - serverClient.publish({ - messageId: 0, - topic: 'test1', - payload: 'Message', - qos: 0, - properties: { topicAlias: 0 }, + }, + ) + + it( + 'should throw an error if broker PUBLISH unregistered topicAlias', + { + timeout: 15000, + }, + function _test(t, done) { + const opts: mqtt.IClientOptions = { + host: 'localhost', + port: ports.PORTAND103, + protocolVersion: 5, + properties: { + topicAliasMaximum: 3, + }, + } + const client = mqtt.connect(opts) + const server2 = new MqttServer((serverClient) => { + serverClient.on('connect', (packet) => { + serverClient.connack({ + reasonCode: 0, + sessionPresent: false, + }) + // register out of range topicAlias + serverClient.publish({ + messageId: 0, + topic: '', // use topic alias + payload: 'Message', + qos: 0, + properties: { topicAlias: 1 }, // in range topic alias + }) }) - }) - }).listen(ports.PORTAND103) + }).listen(ports.PORTAND103) - client.on('error', (error) => { - assert.strictEqual( - error.message, - 'Received Topic Alias is out of range', - ) - client.end(true, (err1) => { - server2.close((err2) => { - done(err1 || err2) + client.on('error', (error) => { + assert.strictEqual( + error.message, + 'Received unregistered Topic Alias', + ) + client.end(true, (err1) => { + server2.close((err2) => { + done(err1 || err2) + }) }) }) - }) - }) - - it('should throw an error if broker PUBLISH unregistered topicAlias', function test(done) { - this.timeout(15000) - - const opts: mqtt.IClientOptions = { - host: 'localhost', - port: ports.PORTAND103, - protocolVersion: 5, - properties: { - topicAliasMaximum: 3, - }, - } - const client = mqtt.connect(opts) - const server2 = new MqttServer((serverClient) => { - serverClient.on('connect', (packet) => { - serverClient.connack({ - reasonCode: 0, - sessionPresent: false, - }) - // register out of range topicAlias - serverClient.publish({ - messageId: 0, - topic: '', // use topic alias - payload: 'Message', - qos: 0, - properties: { topicAlias: 1 }, // in range topic alias - }) + }, + ) + + it( + 'should throw an error if there is Auth Data with no Auth Method', + { + timeout: 5000, + }, + function _test(t, done) { + const opts: mqtt.IClientOptions = { + host: 'localhost', + port: ports.PORTAND115, + protocolVersion: 5, + properties: { authenticationData: Buffer.from([1, 2, 3, 4]) }, + } + console.log('client connecting') + const client = mqtt.connect(opts) + client.on('error', (error) => { + console.log('error hit') + assert.strictEqual( + error.message, + 'Packet has no Authentication Method', + ) + // client will not be connected, so we will call done. + assert.isTrue( + client.disconnected, + 'validate client is disconnected', + ) + client.end(true, done) }) - }).listen(ports.PORTAND103) - - client.on('error', (error) => { - assert.strictEqual( - error.message, - 'Received unregistered Topic Alias', - ) - client.end(true, (err1) => { - server2.close((err2) => { - done(err1 || err2) + }, + ) + + it( + 'auth packet', + { + timeout: 2500, + }, + function _test(t, done) { + const opts: mqtt.IClientOptions = { + host: 'localhost', + port: ports.PORTAND115, + protocolVersion: 5, + properties: { authenticationMethod: 'json' }, + authPacket: {}, + manualConnect: true, + } + let authSent = false + + const client = mqtt.connect(opts) + server.once('client', (c) => { + // this test is flaky, there is a race condition + // that could make the test fail as the auth packet + // is sent by the client even before connack so it could arrive before + // the clientServer is listening for the auth packet. To avoid this + // if the event is not emitted we simply check if + // the auth packet is sent after 1 second. + let closeTimeout = setTimeout(() => { + assert.isTrue(authSent) + closeTimeout = null + client.end(true, done) + }, 1000) + + c.on('auth', (packet) => { + if (closeTimeout) { + clearTimeout(closeTimeout) + client.end(done) + } }) }) - }) - }) - - it('should throw an error if there is Auth Data with no Auth Method', function test(done) { - this.timeout(5000) - const opts: mqtt.IClientOptions = { - host: 'localhost', - port: ports.PORTAND115, - protocolVersion: 5, - properties: { authenticationData: Buffer.from([1, 2, 3, 4]) }, - } - console.log('client connecting') - const client = mqtt.connect(opts) - client.on('error', (error) => { - console.log('error hit') - assert.strictEqual( - error.message, - 'Packet has no Authentication Method', - ) - // client will not be connected, so we will call done. - assert.isTrue( - client.disconnected, - 'validate client is disconnected', - ) - client.end(true, done) - }) - }) + client.on('packetsend', (packet) => { + if (packet.cmd === 'auth') { + authSent = true + } + }) - it('auth packet', function test(done) { - this.timeout(2500) - const opts: mqtt.IClientOptions = { - host: 'localhost', - port: ports.PORTAND115, - protocolVersion: 5, - properties: { authenticationMethod: 'json' }, - authPacket: {}, - manualConnect: true, - } - let authSent = false - - const client = mqtt.connect(opts) - server.once('client', (c) => { - // this test is flaky, there is a race condition - // that could make the test fail as the auth packet - // is sent by the client even before connack so it could arrive before - // the clientServer is listening for the auth packet. To avoid this - // if the event is not emitted we simply check if - // the auth packet is sent after 1 second. - let closeTimeout = setTimeout(() => { - assert.isTrue(authSent) - closeTimeout = null + client.connect() + }, + ) + + it( + 'Maximum Packet Size', + { + timeout: 15000, + }, + function _test(t, done) { + const opts: mqtt.IClientOptions = { + host: 'localhost', + port: ports.PORTAND115, + protocolVersion: 5, + properties: { maximumPacketSize: 1 }, + } + const client = mqtt.connect(opts) + client.on('error', (error) => { + assert.strictEqual( + error.message, + 'exceeding packets size connack', + ) client.end(true, done) - }, 1000) - - c.on('auth', (packet) => { - if (closeTimeout) { - clearTimeout(closeTimeout) - client.end(done) - } }) - }) - client.on('packetsend', (packet) => { - if (packet.cmd === 'auth') { - authSent = true + }, + ) + + it( + 'Change values of some properties by server response', + { + timeout: 15000, + }, + function _test(t, done) { + const server2 = new MqttServer((serverClient) => { + serverClient.on('connect', (packet) => { + serverClient.connack({ + reasonCode: 0, + properties: { + serverKeepAlive: 16, + maximumPacketSize: 95, + }, + }) + }) + }).listen(ports.PORTAND116) + const opts: mqtt.IClientOptions = { + host: 'localhost', + port: ports.PORTAND116, + protocolVersion: 5, + properties: { + topicAliasMaximum: 10, + // serverKeepAlive: 11, + maximumPacketSize: 100, + }, } - }) - - client.connect() - }) - - it('Maximum Packet Size', function test(done) { - this.timeout(15000) - const opts: mqtt.IClientOptions = { - host: 'localhost', - port: ports.PORTAND115, - protocolVersion: 5, - properties: { maximumPacketSize: 1 }, - } - const client = mqtt.connect(opts) - client.on('error', (error) => { - assert.strictEqual(error.message, 'exceeding packets size connack') - client.end(true, done) - }) - }) - - it('Change values of some properties by server response', function test(done) { - this.timeout(15000) - const server2 = new MqttServer((serverClient) => { - serverClient.on('connect', (packet) => { - serverClient.connack({ - reasonCode: 0, - properties: { - serverKeepAlive: 16, - maximumPacketSize: 95, - }, + const client = mqtt.connect(opts) + client.on('connect', () => { + assert.strictEqual(client.options.keepalive, 16) + assert.strictEqual( + client.options.properties.maximumPacketSize, + 95, + ) + client.end(true, (err1) => { + server2.close((err2) => { + done(err1 || err2) + }) }) }) - }).listen(ports.PORTAND116) - const opts: mqtt.IClientOptions = { - host: 'localhost', - port: ports.PORTAND116, - protocolVersion: 5, - properties: { - topicAliasMaximum: 10, - // serverKeepAlive: 11, - maximumPacketSize: 100, - }, - } - const client = mqtt.connect(opts) - client.on('connect', () => { - assert.strictEqual(client.options.keepalive, 16) - assert.strictEqual(client.options.properties.maximumPacketSize, 95) - client.end(true, (err1) => { - server2.close((err2) => { - done(err1 || err2) + }, + ) + + it( + 'should resubscribe when reconnecting with protocolVersion 5 and Session Present flag is false', + { + timeout: 15000, + }, + function _test(t, done) { + let tryReconnect = true + let reconnectEvent = false + const server2 = new MqttServer((serverClient) => { + serverClient.on('connect', (packet) => { + serverClient.connack({ + reasonCode: 0, + sessionPresent: false, + }) + serverClient.on('subscribe', () => { + if (!tryReconnect) { + client.end(true, (err1) => { + server2.close((err2) => { + done(err1 || err2) + }) + }) + } + }) }) + }).listen(ports.PORTAND316) + const opts: mqtt.IClientOptions = { + host: 'localhost', + port: ports.PORTAND316, + protocolVersion: 5, + } + const client = mqtt.connect(opts) + + client.on('reconnect', () => { + reconnectEvent = true }) - }) - }) - it('should resubscribe when reconnecting with protocolVersion 5 and Session Present flag is false', function test(done) { - this.timeout(15000) - let tryReconnect = true - let reconnectEvent = false - const server2 = new MqttServer((serverClient) => { - serverClient.on('connect', (packet) => { - serverClient.connack({ - reasonCode: 0, - sessionPresent: false, + client.on('connect', (connack) => { + assert.isFalse(connack.sessionPresent) + if (tryReconnect) { + client.subscribe('hello', () => { + client.stream.end() + }) + + tryReconnect = false + } else { + assert.isTrue(reconnectEvent) + } + }) + }, + ) + + it( + 'should resubscribe when reconnecting with protocolVersion 5 and properties', + { + // timeout: 15000, + }, + function _test(t, done) { + // this.timeout(15000) + let tryReconnect = true + let reconnectEvent = false + const server2 = new MqttServer((serverClient) => { + serverClient.on('connect', (packet) => { + serverClient.connack({ + reasonCode: 0, + sessionPresent: false, + }) }) - serverClient.on('subscribe', () => { - if (!tryReconnect) { + serverClient.on('subscribe', (packet) => { + if (!reconnectEvent) { + serverClient.suback({ + messageId: packet.messageId, + granted: packet.subscriptions.map((e) => e.qos), + }) + } else if (!tryReconnect) { + assert.strictEqual( + packet.properties.userProperties.test, + 'test', + ) client.end(true, (err1) => { server2.close((err2) => { done(err1 || err2) @@ -775,92 +908,37 @@ describe('MQTT 5.0', () => { }) } }) - }) - }).listen(ports.PORTAND316) - const opts: mqtt.IClientOptions = { - host: 'localhost', - port: ports.PORTAND316, - protocolVersion: 5, - } - const client = mqtt.connect(opts) - - client.on('reconnect', () => { - reconnectEvent = true - }) - - client.on('connect', (connack) => { - assert.isFalse(connack.sessionPresent) - if (tryReconnect) { - client.subscribe('hello', () => { - client.stream.end() - }) + }).listen(ports.PORTAND326) - tryReconnect = false - } else { - assert.isTrue(reconnectEvent) + const opts: mqtt.IClientOptions = { + host: 'localhost', + port: ports.PORTAND326, + protocolVersion: 5, } - }) - }) + const client = mqtt.connect(opts) - it('should resubscribe when reconnecting with protocolVersion 5 and properties', function test(done) { - // this.timeout(15000) - let tryReconnect = true - let reconnectEvent = false - const server2 = new MqttServer((serverClient) => { - serverClient.on('connect', (packet) => { - serverClient.connack({ - reasonCode: 0, - sessionPresent: false, - }) + client.on('reconnect', () => { + reconnectEvent = true }) - serverClient.on('subscribe', (packet) => { - if (!reconnectEvent) { - serverClient.suback({ - messageId: packet.messageId, - granted: packet.subscriptions.map((e) => e.qos), - }) - } else if (!tryReconnect) { - assert.strictEqual( - packet.properties.userProperties.test, - 'test', + + client.on('connect', (connack) => { + assert.isFalse(connack.sessionPresent) + if (tryReconnect) { + client.subscribe( + 'hello', + { properties: { userProperties: { test: 'test' } } }, + () => { + client.stream.end() + }, ) - client.end(true, (err1) => { - server2.close((err2) => { - done(err1 || err2) - }) - }) + + tryReconnect = false + } else { + assert.isTrue(reconnectEvent) } }) - }).listen(ports.PORTAND326) - - const opts: mqtt.IClientOptions = { - host: 'localhost', - port: ports.PORTAND326, - protocolVersion: 5, - } - const client = mqtt.connect(opts) - - client.on('reconnect', () => { - reconnectEvent = true - }) - - client.on('connect', (connack) => { - assert.isFalse(connack.sessionPresent) - if (tryReconnect) { - client.subscribe( - 'hello', - { properties: { userProperties: { test: 'test' } } }, - () => { - client.stream.end() - }, - ) - - tryReconnect = false - } else { - assert.isTrue(reconnectEvent) - } - }) - }) + }, + ) const serverThatSendsErrors = new MqttServer((serverClient) => { serverClient.on('connect', (packet) => { @@ -894,371 +972,428 @@ describe('MQTT 5.0', () => { }) }) - it('Subscribe properties', function test(done) { - this.timeout(15000) - const opts: mqtt.IClientOptions = { - host: 'localhost', - port: ports.PORTAND119, - protocolVersion: 5, - } - const subOptions = { properties: { subscriptionIdentifier: 1234 } } - const server2 = new MqttServer((serverClient) => { - serverClient.on('connect', (packet) => { - serverClient.connack({ - reasonCode: 0, + it( + 'Subscribe properties', + { + timeout: 15000, + }, + function _test(t, done) { + const opts: mqtt.IClientOptions = { + host: 'localhost', + port: ports.PORTAND119, + protocolVersion: 5, + } + const subOptions = { properties: { subscriptionIdentifier: 1234 } } + const server2 = new MqttServer((serverClient) => { + serverClient.on('connect', (packet) => { + serverClient.connack({ + reasonCode: 0, + }) }) + serverClient.on('subscribe', (packet) => { + assert.strictEqual( + packet.properties.subscriptionIdentifier, + subOptions.properties.subscriptionIdentifier, + ) + client.end(true, (err1) => { + server2.close((err2) => { + done(err1 || err2) + }) + }) + }) + }).listen(ports.PORTAND119) + + const client = mqtt.connect(opts) + client.on('connect', () => { + client.subscribe('a/b', subOptions) }) - serverClient.on('subscribe', (packet) => { - assert.strictEqual( - packet.properties.subscriptionIdentifier, - subOptions.properties.subscriptionIdentifier, + }, + ) + + it( + 'puback handling errors check', + { + timeout: 15000, + }, + function _test(t, done) { + serverThatSendsErrors.listen(ports.PORTAND117) + const opts: mqtt.IClientOptions = { + host: 'localhost', + port: ports.PORTAND117, + protocolVersion: 5, + } + const client = mqtt.connect(opts) + client.once('connect', () => { + client.publish( + 'a/b', + 'message', + { qos: 1 }, + (err: ErrorWithReasonCode) => { + assert.strictEqual( + err.message, + 'Publish error: Session taken over', + ) + assert.strictEqual(err.code, 142) + }, ) client.end(true, (err1) => { - server2.close((err2) => { + serverThatSendsErrors.close((err2) => { done(err1 || err2) }) }) }) - }).listen(ports.PORTAND119) - - const client = mqtt.connect(opts) - client.on('connect', () => { - client.subscribe('a/b', subOptions) - }) - }) - - it('puback handling errors check', function test(done) { - this.timeout(15000) - serverThatSendsErrors.listen(ports.PORTAND117) - const opts: mqtt.IClientOptions = { - host: 'localhost', - port: ports.PORTAND117, - protocolVersion: 5, - } - const client = mqtt.connect(opts) - client.once('connect', () => { - client.publish( - 'a/b', - 'message', - { qos: 1 }, - (err: ErrorWithReasonCode) => { - assert.strictEqual( - err.message, - 'Publish error: Session taken over', - ) - assert.strictEqual(err.code, 142) - }, - ) - client.end(true, (err1) => { - serverThatSendsErrors.close((err2) => { - done(err1 || err2) + }, + ) + + it( + 'pubrec handling errors check', + { + timeout: 15000, + }, + function _test(t, done) { + serverThatSendsErrors.listen(ports.PORTAND118) + const opts: mqtt.IClientOptions = { + host: 'localhost', + port: ports.PORTAND118, + protocolVersion: 5, + } + const client = mqtt.connect(opts) + client.once('connect', () => { + client.publish( + 'a/b', + 'message', + { qos: 2 }, + (err: ErrorWithReasonCode) => { + assert.strictEqual( + err.message, + 'Publish error: Session taken over', + ) + assert.strictEqual(err.code, 142) + }, + ) + client.end(true, (err1) => { + serverThatSendsErrors.close((err2) => { + done(err1 || err2) + }) }) }) - }) - }) - - it('pubrec handling errors check', function test(done) { - this.timeout(15000) - serverThatSendsErrors.listen(ports.PORTAND118) - const opts: mqtt.IClientOptions = { - host: 'localhost', - port: ports.PORTAND118, - protocolVersion: 5, - } - const client = mqtt.connect(opts) - client.once('connect', () => { - client.publish( - 'a/b', - 'message', - { qos: 2 }, - (err: ErrorWithReasonCode) => { - assert.strictEqual( - err.message, - 'Publish error: Session taken over', - ) - assert.strictEqual(err.code, 142) + }, + ) + + it( + 'puback handling custom reason code', + { + // timeout: 15000, + }, + function _test(t, done) { + // this.timeout(15000) + serverThatSendsErrors.listen(ports.PORTAND117) + const opts: mqtt.IClientOptions = { + host: 'localhost', + port: ports.PORTAND117, + protocolVersion: 5, + customHandleAcks(topic, message, packet, cb) { + let code = 0 + if (topic === 'a/b') { + code = 128 + } + cb(code) }, - ) - client.end(true, (err1) => { - serverThatSendsErrors.close((err2) => { - done(err1 || err2) + } + + serverThatSendsErrors.once('client', (serverClient) => { + serverClient.once('subscribe', () => { + serverClient.publish({ + topic: 'a/b', + payload: 'payload', + qos: 1, + messageId: 1, + }) }) - }) - }) - }) - it('puback handling custom reason code', function test(done) { - // this.timeout(15000) - serverThatSendsErrors.listen(ports.PORTAND117) - const opts: mqtt.IClientOptions = { - host: 'localhost', - port: ports.PORTAND117, - protocolVersion: 5, - customHandleAcks(topic, message, packet, cb) { - let code = 0 - if (topic === 'a/b') { - code = 128 - } - cb(code) - }, - } - - serverThatSendsErrors.once('client', (serverClient) => { - serverClient.once('subscribe', () => { - serverClient.publish({ - topic: 'a/b', - payload: 'payload', - qos: 1, - messageId: 1, + serverClient.on('puback', (packet) => { + assert.strictEqual(packet.reasonCode, 128) + client.end(true, (err1) => { + serverThatSendsErrors.close((err2) => { + done(err1 || err2) + }) + }) }) }) - serverClient.on('puback', (packet) => { - assert.strictEqual(packet.reasonCode, 128) - client.end(true, (err1) => { - serverThatSendsErrors.close((err2) => { - done(err1 || err2) + const client = mqtt.connect(opts) + client.once('connect', () => { + client.subscribe('a/b', { qos: 1 }) + }) + }, + ) + + it( + 'server side disconnect', + { + timeout: 15000, + }, + function _test(t, done) { + const server2 = new MqttServer((serverClient) => { + serverClient.on('connect', (packet) => { + serverClient.connack({ + reasonCode: 0, }) + serverClient.disconnect({ reasonCode: 128 }) + server2.close() }) }) - }) + server2.listen(ports.PORTAND327) + const opts: mqtt.IClientOptions = { + host: 'localhost', + port: ports.PORTAND327, + protocolVersion: 5, + } - const client = mqtt.connect(opts) - client.once('connect', () => { - client.subscribe('a/b', { qos: 1 }) - }) - }) + const client = mqtt.connect(opts) + client.once( + 'disconnect', + (disconnectPacket: mqtt.IDisconnectPacket) => { + assert.strictEqual(disconnectPacket.reasonCode, 128) + client.end(true, (err) => done(err)) + }, + ) + }, + ) + + it( + 'pubrec handling custom reason code', + { + timeout: 15000, + }, + function _test(t, done) { + serverThatSendsErrors.listen(ports.PORTAND117) + const opts: mqtt.IClientOptions = { + host: 'localhost', + port: ports.PORTAND117, + protocolVersion: 5, + customHandleAcks(topic, message, packet, cb) { + let code = 0 + if (topic === 'a/b') { + code = 128 + } + cb(code) + }, + } + const client = mqtt.connect(opts) + client.once('connect', () => { + client.subscribe('a/b', { qos: 1 }) + }) - it('server side disconnect', function test(done) { - this.timeout(15000) - const server2 = new MqttServer((serverClient) => { - serverClient.on('connect', (packet) => { - serverClient.connack({ - reasonCode: 0, + serverThatSendsErrors.once('client', (serverClient) => { + serverClient.once('subscribe', () => { + serverClient.publish({ + topic: 'a/b', + payload: 'payload', + qos: 2, + messageId: 1, + }) }) - serverClient.disconnect({ reasonCode: 128 }) - server2.close() - }) - }) - server2.listen(ports.PORTAND327) - const opts: mqtt.IClientOptions = { - host: 'localhost', - port: ports.PORTAND327, - protocolVersion: 5, - } - - const client = mqtt.connect(opts) - client.once( - 'disconnect', - (disconnectPacket: mqtt.IDisconnectPacket) => { - assert.strictEqual(disconnectPacket.reasonCode, 128) - client.end(true, (err) => done(err)) - }, - ) - }) - it('pubrec handling custom reason code', function test(done) { - this.timeout(15000) - serverThatSendsErrors.listen(ports.PORTAND117) - const opts: mqtt.IClientOptions = { - host: 'localhost', - port: ports.PORTAND117, - protocolVersion: 5, - customHandleAcks(topic, message, packet, cb) { - let code = 0 - if (topic === 'a/b') { - code = 128 - } - cb(code) - }, - } - const client = mqtt.connect(opts) - client.once('connect', () => { - client.subscribe('a/b', { qos: 1 }) - }) + serverClient.on('pubrec', (packet) => { + assert.strictEqual(packet.reasonCode, 128) + client.end(true, (err1) => { + serverThatSendsErrors.close((err2) => { + done(err1 || err2) + }) + }) + }) + }) + }, + ) + + it( + 'puback handling custom reason code with error', + { + timeout: 15000, + }, + function _test(t, done) { + serverThatSendsErrors.listen(ports.PORTAND117) + const opts: mqtt.IClientOptions = { + host: 'localhost', + port: ports.PORTAND117, + protocolVersion: 5, + customHandleAcks(topic, message, packet, cb) { + const code = 0 + if (topic === 'a/b') { + cb(new Error('a/b is not valid')) + } + cb(code) + }, + } - serverThatSendsErrors.once('client', (serverClient) => { - serverClient.once('subscribe', () => { - serverClient.publish({ - topic: 'a/b', - payload: 'payload', - qos: 2, - messageId: 1, + serverThatSendsErrors.once('client', (serverClient) => { + serverClient.once('subscribe', () => { + serverClient.publish({ + topic: 'a/b', + payload: 'payload', + qos: 1, + messageId: 1, + }) }) }) - serverClient.on('pubrec', (packet) => { - assert.strictEqual(packet.reasonCode, 128) + const client = mqtt.connect(opts) + client.on('error', (error) => { + assert.strictEqual(error.message, 'a/b is not valid') client.end(true, (err1) => { serverThatSendsErrors.close((err2) => { done(err1 || err2) }) }) }) - }) - }) - - it('puback handling custom reason code with error', function test(done) { - this.timeout(15000) - serverThatSendsErrors.listen(ports.PORTAND117) - const opts: mqtt.IClientOptions = { - host: 'localhost', - port: ports.PORTAND117, - protocolVersion: 5, - customHandleAcks(topic, message, packet, cb) { - const code = 0 - if (topic === 'a/b') { - cb(new Error('a/b is not valid')) - } - cb(code) - }, - } - - serverThatSendsErrors.once('client', (serverClient) => { - serverClient.once('subscribe', () => { - serverClient.publish({ - topic: 'a/b', - payload: 'payload', - qos: 1, - messageId: 1, - }) + client.once('connect', () => { + client.subscribe('a/b', { qos: 1 }) }) - }) + }, + ) + + it( + 'pubrec handling custom reason code with error', + { + timeout: 15000, + }, + function _test(t, done) { + serverThatSendsErrors.listen(ports.PORTAND117) + const opts: mqtt.IClientOptions = { + host: 'localhost', + port: ports.PORTAND117, + protocolVersion: 5, + customHandleAcks(topic, message, packet, cb) { + const code = 0 + if (topic === 'a/b') { + cb(new Error('a/b is not valid')) + } + cb(code) + }, + } - const client = mqtt.connect(opts) - client.on('error', (error) => { - assert.strictEqual(error.message, 'a/b is not valid') - client.end(true, (err1) => { - serverThatSendsErrors.close((err2) => { - done(err1 || err2) + serverThatSendsErrors.once('client', (serverClient) => { + serverClient.once('subscribe', () => { + serverClient.publish({ + topic: 'a/b', + payload: 'payload', + qos: 2, + messageId: 1, + }) }) }) - }) - client.once('connect', () => { - client.subscribe('a/b', { qos: 1 }) - }) - }) - it('pubrec handling custom reason code with error', function test(done) { - this.timeout(15000) - serverThatSendsErrors.listen(ports.PORTAND117) - const opts: mqtt.IClientOptions = { - host: 'localhost', - port: ports.PORTAND117, - protocolVersion: 5, - customHandleAcks(topic, message, packet, cb) { - const code = 0 - if (topic === 'a/b') { - cb(new Error('a/b is not valid')) - } - cb(code) - }, - } - - serverThatSendsErrors.once('client', (serverClient) => { - serverClient.once('subscribe', () => { - serverClient.publish({ - topic: 'a/b', - payload: 'payload', - qos: 2, - messageId: 1, + const client = mqtt.connect(opts) + client.on('error', (error) => { + assert.strictEqual(error.message, 'a/b is not valid') + client.end(true, (err1) => { + serverThatSendsErrors.close((err2) => { + done(err1 || err2) + }) }) }) - }) - - const client = mqtt.connect(opts) - client.on('error', (error) => { - assert.strictEqual(error.message, 'a/b is not valid') - client.end(true, (err1) => { - serverThatSendsErrors.close((err2) => { - done(err1 || err2) - }) + client.once('connect', () => { + client.subscribe('a/b', { qos: 1 }) }) - }) - client.once('connect', () => { - client.subscribe('a/b', { qos: 1 }) - }) - }) + }, + ) + + it( + 'puback handling custom invalid reason code', + { + timeout: 15000, + }, + function _test(t, done) { + serverThatSendsErrors.listen(ports.PORTAND117) + const opts: mqtt.IClientOptions = { + host: 'localhost', + port: ports.PORTAND117, + protocolVersion: 5, + customHandleAcks(topic, message, packet, cb) { + let code = 0 + if (topic === 'a/b') { + code = 124124 + } + cb(code) + }, + } - it('puback handling custom invalid reason code', function test(done) { - this.timeout(15000) - serverThatSendsErrors.listen(ports.PORTAND117) - const opts: mqtt.IClientOptions = { - host: 'localhost', - port: ports.PORTAND117, - protocolVersion: 5, - customHandleAcks(topic, message, packet, cb) { - let code = 0 - if (topic === 'a/b') { - code = 124124 - } - cb(code) - }, - } - - serverThatSendsErrors.once('client', (serverClient) => { - serverClient.once('subscribe', () => { - serverClient.publish({ - topic: 'a/b', - payload: 'payload', - qos: 1, - messageId: 1, + serverThatSendsErrors.once('client', (serverClient) => { + serverClient.once('subscribe', () => { + serverClient.publish({ + topic: 'a/b', + payload: 'payload', + qos: 1, + messageId: 1, + }) }) }) - }) - const client = mqtt.connect(opts) - client.on('error', (error) => { - assert.strictEqual(error.message, 'Wrong reason code for puback') - client.end(true, (err1) => { - serverThatSendsErrors.close((err2) => { - done(err1 || err2) + const client = mqtt.connect(opts) + client.on('error', (error) => { + assert.strictEqual( + error.message, + 'Wrong reason code for puback', + ) + client.end(true, (err1) => { + serverThatSendsErrors.close((err2) => { + done(err1 || err2) + }) }) }) - }) - client.once('connect', () => { - client.subscribe('a/b', { qos: 1 }) - }) - }) + client.once('connect', () => { + client.subscribe('a/b', { qos: 1 }) + }) + }, + ) + + it( + 'pubrec handling custom invalid reason code', + { + timeout: 15000, + }, + function _test(t, done) { + serverThatSendsErrors.listen(ports.PORTAND117) + const opts: mqtt.IClientOptions = { + host: 'localhost', + port: ports.PORTAND117, + protocolVersion: 5, + customHandleAcks(topic, message, packet, cb) { + let code = 0 + if (topic === 'a/b') { + code = 34535 + } + cb(code) + }, + } - it('pubrec handling custom invalid reason code', function test(done) { - this.timeout(15000) - serverThatSendsErrors.listen(ports.PORTAND117) - const opts: mqtt.IClientOptions = { - host: 'localhost', - port: ports.PORTAND117, - protocolVersion: 5, - customHandleAcks(topic, message, packet, cb) { - let code = 0 - if (topic === 'a/b') { - code = 34535 - } - cb(code) - }, - } - - serverThatSendsErrors.once('client', (serverClient) => { - serverClient.once('subscribe', () => { - serverClient.publish({ - topic: 'a/b', - payload: 'payload', - qos: 2, - messageId: 1, + serverThatSendsErrors.once('client', (serverClient) => { + serverClient.once('subscribe', () => { + serverClient.publish({ + topic: 'a/b', + payload: 'payload', + qos: 2, + messageId: 1, + }) }) }) - }) - const client = mqtt.connect(opts) - client.on('error', (error) => { - assert.strictEqual(error.message, 'Wrong reason code for pubrec') - client.end(true, (err1) => { - serverThatSendsErrors.close((err2) => { - done(err1 || err2) + const client = mqtt.connect(opts) + client.on('error', (error) => { + assert.strictEqual( + error.message, + 'Wrong reason code for pubrec', + ) + client.end(true, (err1) => { + serverThatSendsErrors.close((err2) => { + done(err1 || err2) + }) }) }) - }) - client.once('connect', () => { - client.subscribe('a/b', { qos: 1 }) - }) - }) + client.once('connect', () => { + client.subscribe('a/b', { qos: 1 }) + }) + }, + ) }) diff --git a/test/message-id-provider.ts b/test/message-id-provider.ts index 8068604aa..4192bb311 100644 --- a/test/message-id-provider.ts +++ b/test/message-id-provider.ts @@ -1,10 +1,11 @@ import { assert } from 'chai' import DefaultMessageIdProvider from '../src/lib/default-message-id-provider' import UniqueMessageIdProvider from '../src/lib/unique-message-id-provider' +import { describe, it } from 'node:test' describe('message id provider', () => { describe('default', () => { - it('should return 1 once the internal counter reached limit', () => { + it('should return 1 once the internal counter reached limit', (t, done) => { const provider = new DefaultMessageIdProvider() provider['nextId'] = 65535 @@ -12,7 +13,7 @@ describe('message id provider', () => { assert.equal(provider.allocate(), 1) }) - it('should return 65535 for last message id once the internal counter reached limit', () => { + it('should return 65535 for last message id once the internal counter reached limit', (t, done) => { const provider = new DefaultMessageIdProvider() provider['nextId'] = 65535 @@ -21,32 +22,32 @@ describe('message id provider', () => { assert.equal(provider.allocate(), 1) assert.equal(provider.getLastAllocated(), 1) }) - it('should return true when register with non allocated messageId', () => { + it('should return true when register with non allocated messageId', (t, done) => { const provider = new DefaultMessageIdProvider() assert.equal(provider.register(10), true) }) }) describe('unique', () => { - it('should return 1, 2, 3.., when allocate', () => { + it('should return 1, 2, 3.., when allocate', (t, done) => { const provider = new UniqueMessageIdProvider() assert.equal(provider.allocate(), 1) assert.equal(provider.allocate(), 2) assert.equal(provider.allocate(), 3) }) - it('should skip registerd messageId', () => { + it('should skip registerd messageId', (t, done) => { const provider = new UniqueMessageIdProvider() assert.equal(provider.register(2), true) assert.equal(provider.allocate(), 1) assert.equal(provider.allocate(), 3) }) - it('should return false register allocated messageId', () => { + it('should return false register allocated messageId', (t, done) => { const provider = new UniqueMessageIdProvider() assert.equal(provider.allocate(), 1) assert.equal(provider.register(1), false) assert.equal(provider.register(5), true) assert.equal(provider.register(5), false) }) - it('should retrun correct last messageId', () => { + it('should retrun correct last messageId', (t, done) => { const provider = new UniqueMessageIdProvider() assert.equal(provider.allocate(), 1) assert.equal(provider.getLastAllocated(), 1) @@ -55,7 +56,7 @@ describe('message id provider', () => { assert.equal(provider.allocate(), 3) assert.equal(provider.getLastAllocated(), 3) }) - it('should be reusable deallocated messageId', () => { + it('should be reusable deallocated messageId', (t, done) => { const provider = new UniqueMessageIdProvider() assert.equal(provider.allocate(), 1) assert.equal(provider.allocate(), 2) @@ -63,7 +64,7 @@ describe('message id provider', () => { provider.deallocate(2) assert.equal(provider.allocate(), 2) }) - it('should allocate all messageId and then return null', () => { + it('should allocate all messageId and then return null', (t, done) => { const provider = new UniqueMessageIdProvider() for (let i = 1; i <= 65535; i++) { assert.equal(provider.allocate(), i) @@ -73,7 +74,7 @@ describe('message id provider', () => { assert.equal(provider.allocate(), 10000) assert.equal(provider.allocate(), null) }) - it('should all messageId reallocatable after clear', () => { + it('should all messageId reallocatable after clear', (t, done) => { const provider = new UniqueMessageIdProvider() for (let i = 1; i <= 65535; i++) { assert.equal(provider.allocate(), i) diff --git a/test/mqtt.ts b/test/mqtt.ts index 52e97eca4..339381638 100644 --- a/test/mqtt.ts +++ b/test/mqtt.ts @@ -2,10 +2,11 @@ import fs from 'fs' import path from 'path' import * as mqtt from '../src/mqtt' import { IClientOptions } from '../src/lib/client' +import { describe, it } from 'node:test' describe('mqtt', () => { describe('#connect', () => { - it('should return an MqttClient when connect is called with mqtt:/ url', function test(done) { + it('should return an MqttClient when connect is called with mqtt:/ url', function _test(t, done) { const c = mqtt.connect('mqtt://localhost:1883') c.should.be.instanceOf(mqtt.MqttClient) @@ -24,7 +25,7 @@ describe('mqtt', () => { }).should.throw('Missing protocol') }) - it('should return an MqttClient with username option set', function test(done) { + it('should return an MqttClient with username option set', function _test(t, done) { const c = mqtt.connect('mqtt://user:pass@localhost:1883') c.should.be.instanceOf(mqtt.MqttClient) @@ -33,7 +34,7 @@ describe('mqtt', () => { c.end((err) => done(err)) }) - it('should return an MqttClient with username and password options set', function test(done) { + it('should return an MqttClient with username and password options set', function _test(t, done) { const c = mqtt.connect('mqtt://user@localhost:1883') c.should.be.instanceOf(mqtt.MqttClient) @@ -41,7 +42,7 @@ describe('mqtt', () => { c.end((err) => done(err)) }) - it('should return an MqttClient with the clientid with random value', function test(done) { + it('should return an MqttClient with the clientid with random value', function _test(t, done) { const c = mqtt.connect('mqtt://user@localhost:1883') c.should.be.instanceOf(mqtt.MqttClient) @@ -49,7 +50,7 @@ describe('mqtt', () => { c.end((err) => done(err)) }) - it('should return an MqttClient with the clientid with empty string', function test(done) { + it('should return an MqttClient with the clientid with empty string', function _test(t, done) { const c = mqtt.connect('mqtt://user@localhost:1883?clientId=') c.should.be.instanceOf(mqtt.MqttClient) @@ -57,7 +58,7 @@ describe('mqtt', () => { c.end((err) => done(err)) }) - it('should return an MqttClient with the clientid option set', function test(done) { + it('should return an MqttClient with the clientid option set', function _test(t, done) { const c = mqtt.connect('mqtt://user@localhost:1883?clientId=123') c.should.be.instanceOf(mqtt.MqttClient) @@ -65,14 +66,14 @@ describe('mqtt', () => { c.end((err) => done(err)) }) - it('should return an MqttClient when connect is called with tcp:/ url', function test(done) { + it('should return an MqttClient when connect is called with tcp:/ url', function _test(t, done) { const c = mqtt.connect('tcp://localhost') c.should.be.instanceOf(mqtt.MqttClient) c.end((err) => done(err)) }) - it('should return an MqttClient with correct host when called with a host and port', function test(done) { + it('should return an MqttClient with correct host when called with a host and port', function _test(t, done) { const c = mqtt.connect('tcp://user:pass@localhost:1883') c.options.should.have.property('hostname', 'localhost') @@ -86,7 +87,7 @@ describe('mqtt', () => { caPaths: [path.join(__dirname, 'helpers', 'public-cert.pem')], } - it('should return an MqttClient when connect is called with mqtts:/ url', function test(done) { + it('should return an MqttClient when connect is called with mqtts:/ url', function _test(t, done) { const c = mqtt.connect('mqtts://localhost', sslOpts) c.options.should.have.property('protocol', 'mqtts') @@ -97,7 +98,7 @@ describe('mqtt', () => { c.end((err) => done(err)) }) - it('should return an MqttClient when connect is called with ssl:/ url', function test(done) { + it('should return an MqttClient when connect is called with ssl:/ url', function _test(t, done) { const c = mqtt.connect('ssl://localhost', sslOpts) c.options.should.have.property('protocol', 'ssl') @@ -108,7 +109,7 @@ describe('mqtt', () => { c.end((err) => done(err)) }) - it('should return an MqttClient when connect is called with ws:/ url', function test(done) { + it('should return an MqttClient when connect is called with ws:/ url', function _test(t, done) { const c = mqtt.connect('ws://localhost', sslOpts) c.options.should.have.property('protocol', 'ws') @@ -119,7 +120,7 @@ describe('mqtt', () => { c.end((err) => done(err)) }) - it('should return an MqttClient when connect is called with wss:/ url', function test(done) { + it('should return an MqttClient when connect is called with wss:/ url', function _test(t, done) { const c = mqtt.connect('wss://localhost', sslOpts) c.options.should.have.property('protocol', 'wss') @@ -158,7 +159,7 @@ describe('mqtt', () => { }).should.throw() }) - it('should return a MqttClient with mqtts set when connect is called key and cert set and protocol mqtt', function test(done) { + it('should return a MqttClient with mqtts set when connect is called key and cert set and protocol mqtt', function _test(t, done) { sslOpts2.protocol = 'mqtt' const c = mqtt.connect(sslOpts2) @@ -170,7 +171,7 @@ describe('mqtt', () => { c.end((err) => done(err)) }) - it('should return a MqttClient with mqtts set when connect is called key and cert set and protocol mqtts', function test(done) { + it('should return a MqttClient with mqtts set when connect is called key and cert set and protocol mqtts', function _test(t, done) { sslOpts2.protocol = 'mqtts' const c = mqtt.connect(sslOpts2) @@ -182,7 +183,7 @@ describe('mqtt', () => { c.end((err) => done(err)) }) - it('should return a MqttClient with wss set when connect is called key and cert set and protocol ws', function test(done) { + it('should return a MqttClient with wss set when connect is called key and cert set and protocol ws', function _test(t, done) { sslOpts2.protocol = 'ws' const c = mqtt.connect(sslOpts2) @@ -194,7 +195,7 @@ describe('mqtt', () => { c.end((err) => done(err)) }) - it('should return a MqttClient with wss set when connect is called key and cert set and protocol wss', function test(done) { + it('should return a MqttClient with wss set when connect is called key and cert set and protocol wss', function _test(t, done) { sslOpts2.protocol = 'wss' const c = mqtt.connect(sslOpts2) @@ -206,7 +207,7 @@ describe('mqtt', () => { c.end((err) => done(err)) }) - it('should return an MqttClient with the clientid with option of clientId as empty string', function test(done) { + it('should return an MqttClient with the clientid with option of clientId as empty string', function _test(t, done) { const c = mqtt.connect('mqtt://localhost:1883', { clientId: '', }) @@ -216,7 +217,7 @@ describe('mqtt', () => { c.end((err) => done(err)) }) - it('should return an MqttClient with the clientid with option of clientId empty', function test(done) { + it('should return an MqttClient with the clientid with option of clientId empty', function _test(t, done) { const c = mqtt.connect('mqtt://localhost:1883') c.should.be.instanceOf(mqtt.MqttClient) @@ -224,7 +225,7 @@ describe('mqtt', () => { c.end((err) => done(err)) }) - it('should return an MqttClient with the clientid with option of with specific clientId', function test(done) { + it('should return an MqttClient with the clientid with option of with specific clientId', function _test(t, done) { const c = mqtt.connect('mqtt://localhost:1883', { clientId: '123', }) diff --git a/test/mqtt_store.ts b/test/mqtt_store.ts index 4e68b7091..62eeab752 100644 --- a/test/mqtt_store.ts +++ b/test/mqtt_store.ts @@ -1,7 +1,9 @@ import Store from '../src/lib/store' +import { describe, it } from 'node:test' +import 'should' describe('store in lib/connect/index.js (webpack entry point)', () => { - it('should create store', function test(done) { + it('should create store', function test(t, done) { const store = new Store() store.should.be.instanceOf(Store) done() diff --git a/test/secure_client.ts b/test/secure_client.ts index f0506734a..ca67ef055 100644 --- a/test/secure_client.ts +++ b/test/secure_client.ts @@ -5,6 +5,7 @@ import abstractClientTests from './abstract_client' import { MqttSecureServer, MqttServerListener } from './server' import { assert } from 'chai' import 'should' +import { describe, it, beforeEach, afterEach } from 'node:test' const port = 9899 const KEY = path.join(__dirname, 'helpers', 'tls-key.pem') @@ -81,7 +82,7 @@ describe('MqttSecureClient', () => { abstractClientTests(server, config) describe('with secure parameters', () => { - it('should validate successfully the CA', function test(done) { + it('should validate successfully the CA', function _test(t, done) { const client = mqtt.connect({ protocol: 'mqtts', port, @@ -98,7 +99,7 @@ describe('MqttSecureClient', () => { }) }) - it('should validate successfully the CA using URI', function test(done) { + it('should validate successfully the CA using URI', function _test(t, done) { const client = mqtt.connect(`mqtts://localhost:${port}`, { ca: [fs.readFileSync(CERT)], rejectUnauthorized: true, @@ -113,7 +114,7 @@ describe('MqttSecureClient', () => { }) }) - it('should validate successfully the CA using URI with path', function test(done) { + it('should validate successfully the CA using URI with path', function _test(t, done) { const client = mqtt.connect(`mqtts://localhost:${port}/`, { ca: [fs.readFileSync(CERT)], rejectUnauthorized: true, @@ -128,7 +129,7 @@ describe('MqttSecureClient', () => { }) }) - it('should validate unsuccessfully the CA', function test(done) { + it('should validate unsuccessfully the CA', function _test(t, done) { const client = mqtt.connect({ protocol: 'mqtts', port, @@ -142,7 +143,7 @@ describe('MqttSecureClient', () => { }) }) - it('should emit close on TLS error', function test(done) { + it('should emit close on TLS error', function _test(t, done) { const client = mqtt.connect({ protocol: 'mqtts', port, @@ -157,7 +158,7 @@ describe('MqttSecureClient', () => { }) }) - it('should support SNI on the TLS connection', function test(done) { + it('should support SNI on the TLS connection', function _test(t, done) { const hostname = 'localhost' server.removeAllListeners('secureConnection') // clear eventHandler diff --git a/test/store.ts b/test/store.ts index 5e37ef01e..24c6cd56f 100644 --- a/test/store.ts +++ b/test/store.ts @@ -1,5 +1,6 @@ import Store from '../src/lib/store' import abstractTest from './abstract_store' +import { describe } from 'node:test' describe('in-memory store', () => { abstractTest(function test(done) { diff --git a/test/unique_message_id_provider_client.ts b/test/unique_message_id_provider_client.ts index 7a11467ad..e1cc71b72 100644 --- a/test/unique_message_id_provider_client.ts +++ b/test/unique_message_id_provider_client.ts @@ -3,6 +3,7 @@ import serverBuilder from './server_helpers_for_client_tests' import UniqueMessageIdProvider from '../src/lib/unique-message-id-provider' import ports from './helpers/port_list' import { IClientOptions } from 'src/mqtt' +import { describe } from 'node:test' describe('UniqueMessageIdProviderMqttClient', () => { const server = serverBuilder('mqtt') diff --git a/test/websocket_client.ts b/test/websocket_client.ts index 52ea03a03..76cedca28 100644 --- a/test/websocket_client.ts +++ b/test/websocket_client.ts @@ -7,6 +7,7 @@ import ports from './helpers/port_list' import { MqttServerNoWait } from './server' import * as mqtt from '../src/mqtt' import { IClientOptions } from '../src/lib/client' +import { describe, it } from 'node:test' const port = 9999 const httpServer = http.createServer() @@ -93,7 +94,7 @@ describe('Websocket Client', () => { return { ...baseConfig, ...(custom || {}) } } - it('should use mqtt as the protocol by default', function test(done) { + it('should use mqtt as the protocol by default', function _test(t, done) { httpServer.once('client', (client) => { assert.strictEqual(client.protocol, 'mqtt') }) @@ -104,7 +105,7 @@ describe('Websocket Client', () => { }) }) - it('should be able to transform the url (for e.g. to sign it)', function test(done) { + it('should be able to transform the url (for e.g. to sign it)', function _test(t, done) { const baseUrl = 'ws://localhost:9999/mqtt' const sig = '?AUTH=token' const expected = baseUrl + sig @@ -132,7 +133,7 @@ describe('Websocket Client', () => { }) }) - it('should use mqttv3.1 as the protocol if using v3.1', function test(done) { + it('should use mqttv3.1 as the protocol if using v3.1', function _test(t, done) { httpServer.once('client', (client) => { assert.strictEqual(client.protocol, 'mqttv3.1') }) @@ -150,66 +151,71 @@ describe('Websocket Client', () => { }) describe('reconnecting', () => { - it('should reconnect to multiple host-ports-protocol combinations if servers is passed', function test(done) { - let serverPort42Connected = false - const handler = (serverClient) => { - serverClient.on('connect', (packet) => { - serverClient.connack({ returnCode: 0 }) - }) - } - this.timeout(15000) - const actualURL41 = 'wss://localhost:9917/' - const actualURL42 = 'ws://localhost:9918/' - const serverPort41 = new MqttServerNoWait(handler).listen( - ports.PORTAND41, - ) - const serverPort42 = new MqttServerNoWait(handler).listen( - ports.PORTAND42, - ) - - serverPort42.on('listening', () => { - const client = mqtt.connect({ - protocol: 'wss', - servers: [ - { - port: ports.PORTAND42, - host: 'localhost', - protocol: 'ws', - }, - { port: ports.PORTAND41, host: 'localhost' }, - ], - keepalive: 50, - }) - serverPort41.once('client', (c) => { - assert.equal( - (client.stream as any).url, - actualURL41, - 'Protocol for second client should use the default protocol: wss, on port: port + 41.', - ) - assert(serverPort42Connected) - c.stream.destroy() - client.end(true, (err1) => { - serverPort41.close((err2) => { - done(err1 || err2) + it( + 'should reconnect to multiple host-ports-protocol combinations if servers is passed', + { + timeout: 15000, + }, + function _test(t, done) { + let serverPort42Connected = false + const handler = (serverClient) => { + serverClient.on('connect', (packet) => { + serverClient.connack({ returnCode: 0 }) + }) + } + const actualURL41 = 'wss://localhost:9917/' + const actualURL42 = 'ws://localhost:9918/' + const serverPort41 = new MqttServerNoWait(handler).listen( + ports.PORTAND41, + ) + const serverPort42 = new MqttServerNoWait(handler).listen( + ports.PORTAND42, + ) + + serverPort42.on('listening', () => { + const client = mqtt.connect({ + protocol: 'wss', + servers: [ + { + port: ports.PORTAND42, + host: 'localhost', + protocol: 'ws', + }, + { port: ports.PORTAND41, host: 'localhost' }, + ], + keepalive: 50, + }) + serverPort41.once('client', (c) => { + assert.equal( + (client.stream as any).url, + actualURL41, + 'Protocol for second client should use the default protocol: wss, on port: port + 41.', + ) + assert(serverPort42Connected) + c.stream.destroy() + client.end(true, (err1) => { + serverPort41.close((err2) => { + done(err1 || err2) + }) }) }) - }) - serverPort42.once('client', (c) => { - serverPort42Connected = true - assert.equal( - (client.stream as any).url, - actualURL42, - 'Protocol for connection should use ws, on port: port + 42.', - ) - c.stream.destroy() - serverPort42.close() - }) + serverPort42.once('client', (c) => { + serverPort42Connected = true + assert.equal( + (client.stream as any).url, + actualURL42, + 'Protocol for connection should use ws, on port: port + 42.', + ) + c.stream.destroy() + serverPort42.close() + }) - client.once('connect', () => { - client.stream.destroy() + client.once('connect', () => { + client.stream.destroy() + }) }) - }) - }) + }, + ) }) abstractClientTests(httpServer, makeOptions()) From 98eae22186f0b981dd59f85b07407251e3a78fd8 Mon Sep 17 00:00:00 2001 From: Daniel Lando Date: Mon, 18 Sep 2023 18:13:45 +0200 Subject: [PATCH 02/26] fix: add timeout to ci --- .github/workflows/mqttjs-test.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/mqttjs-test.yml b/.github/workflows/mqttjs-test.yml index bf3fe168d..d44cd2cb6 100644 --- a/.github/workflows/mqttjs-test.yml +++ b/.github/workflows/mqttjs-test.yml @@ -39,6 +39,7 @@ jobs: - name: Test NodeJS run: npm run test:node # npx mocha test/unique_message_id_provider_client.js --exit + timeout-minutes: 3 env: CI: true DEBUG: "${{ runner.debug == '1' && 'mqttjs:*' || '' }}" From cf8029e4e7577eb77e9b96e2c7b2370412d6c016 Mon Sep 17 00:00:00 2001 From: Daniel Lando Date: Tue, 19 Sep 2023 09:51:50 +0200 Subject: [PATCH 03/26] fix: test run --- .mocharc.js | 10 ---------- package.json | 2 +- test/client.ts | 8 ++++---- test/mqtt.ts | 1 + test/runTests.ts | 14 ++++++++++++++ 5 files changed, 20 insertions(+), 15 deletions(-) delete mode 100644 .mocharc.js create mode 100644 test/runTests.ts diff --git a/.mocharc.js b/.mocharc.js deleted file mode 100644 index 3899769be..000000000 --- a/.mocharc.js +++ /dev/null @@ -1,10 +0,0 @@ -// --check-leaks -// --timeout 10000 -// --exit - -module.exports = { - checkLeaks: true, - exit: true, - timeout: 10000, -}; - diff --git a/package.json b/package.json index 8868937e8..f9fe1a678 100644 --- a/package.json +++ b/package.json @@ -56,7 +56,7 @@ "build:browser": "rimraf dist/ && mkdirp dist/ && browserify build/mqtt.js --standalone mqtt > dist/mqtt.js && terser dist/mqtt.js --compress --mangle --output dist/mqtt.min.js", "build": "npm run build:ts && npm run build:browser", "prepare": "npm run build", - "unit-test:node": "node_modules/.bin/nyc --reporter=lcov --reporter=text node --test --loader tsx test/*.ts", + "unit-test:node": "node_modules/.bin/nyc --reporter=lcov --reporter=text node -r ts-node/register test/runTests.ts", "unit-test:browser": "airtap --server test/browser/server.js test/browser/test.js", "test:node": "npm run unit-test:node && codecov", "test:browser": "npm run build && npm run unit-test:browser", diff --git a/test/client.ts b/test/client.ts index 52b973718..9dd4a3718 100644 --- a/test/client.ts +++ b/test/client.ts @@ -14,7 +14,7 @@ import _debug from 'debug' import { MqttServer } from './server' import abstractClientTests from './abstract_client' import { IClientOptions } from 'src/lib/client' -import { describe, it } from 'node:test' +import { describe, it, after } from 'node:test' const debug = _debug('mqttjs:client-test') @@ -585,7 +585,7 @@ describe('MqttClient', () => { { timeout: 15000, }, - function _test(t, done) { + function _test(t) { // eslint-disable-next-line no-async-promise-executor return new Promise(async (resolve, reject) => { server.once('client', (serverClient) => { @@ -615,7 +615,7 @@ describe('MqttClient', () => { { timeout: 5000, }, - async function _test(t, done) { + async function _test(t) { let error = false try { @@ -637,7 +637,7 @@ describe('MqttClient', () => { { timeout: 5000, }, - async function _test(t, done) { + async function _test(t) { let error = false try { diff --git a/test/mqtt.ts b/test/mqtt.ts index 339381638..77df013e6 100644 --- a/test/mqtt.ts +++ b/test/mqtt.ts @@ -3,6 +3,7 @@ import path from 'path' import * as mqtt from '../src/mqtt' import { IClientOptions } from '../src/lib/client' import { describe, it } from 'node:test' +import 'should' describe('mqtt', () => { describe('#connect', () => { diff --git a/test/runTests.ts b/test/runTests.ts new file mode 100644 index 000000000..0add7f6e8 --- /dev/null +++ b/test/runTests.ts @@ -0,0 +1,14 @@ +import { readdirSync } from 'node:fs' +import { run } from 'node:test' +import process from 'node:process' +import { tap } from 'node:test/reporters' + +const files = readdirSync(__dirname) + .filter((f) => f.endsWith('.ts')) + .map((f) => `${__dirname}/${f}`) + +console.log('Running tests:') + +run({ files, timeout: 60 * 1000 }) + .compose(tap) + .pipe(process.stdout) From e5461a03d3f60fc385f21c9e462707d8e5630872 Mon Sep 17 00:00:00 2001 From: Daniel Lando Date: Tue, 19 Sep 2023 10:02:02 +0200 Subject: [PATCH 04/26] fix: remove debugger and add missing `after` --- test/client.ts | 7 ++++++- test/unique_message_id_provider_client.ts | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/test/client.ts b/test/client.ts index 9dd4a3718..140fccaa6 100644 --- a/test/client.ts +++ b/test/client.ts @@ -214,10 +214,15 @@ describe('MqttClient', () => { timeout: 30000, }, function _test(t, done) { + const args = ['-r', 'ts-node/register'] + + if (process.env.DEBUG_SERVER) { + args.unshift('--inspect') + } const innerServer = fork( path.join(__dirname, 'helpers', 'server_process.ts'), { - execArgv: ['--inspect', '-r', 'ts-node/register'], + execArgv: args, }, ) innerServer.on('close', (code) => { diff --git a/test/unique_message_id_provider_client.ts b/test/unique_message_id_provider_client.ts index e1cc71b72..a65c35abf 100644 --- a/test/unique_message_id_provider_client.ts +++ b/test/unique_message_id_provider_client.ts @@ -3,7 +3,7 @@ import serverBuilder from './server_helpers_for_client_tests' import UniqueMessageIdProvider from '../src/lib/unique-message-id-provider' import ports from './helpers/port_list' import { IClientOptions } from 'src/mqtt' -import { describe } from 'node:test' +import { describe, after } from 'node:test' describe('UniqueMessageIdProviderMqttClient', () => { const server = serverBuilder('mqtt') From 5e45e8aa834b9f51fb55d6d0ed64f4f69317e1a9 Mon Sep 17 00:00:00 2001 From: Daniel Lando Date: Tue, 19 Sep 2023 10:08:08 +0200 Subject: [PATCH 05/26] fix: ts build --- .github/workflows/mqttjs-test.yml | 2 +- tsconfig.json | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/mqttjs-test.yml b/.github/workflows/mqttjs-test.yml index d44cd2cb6..c7cccafdb 100644 --- a/.github/workflows/mqttjs-test.yml +++ b/.github/workflows/mqttjs-test.yml @@ -38,7 +38,7 @@ jobs: npm run lint - name: Test NodeJS - run: npm run test:node # npx mocha test/unique_message_id_provider_client.js --exit + run: npm run test:node timeout-minutes: 3 env: CI: true diff --git a/tsconfig.json b/tsconfig.json index 827f3b0ed..5633fc730 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -20,7 +20,6 @@ ], "types": [ "node", - "mocha" ], }, "include": [ From 0fe0b09b1a49967c2fb1bc29cfe2362ed78c60f5 Mon Sep 17 00:00:00 2001 From: Daniel Lando Date: Tue, 19 Sep 2023 10:10:35 +0200 Subject: [PATCH 06/26] chore: drop nodejs 16 support --- .github/workflows/mqttjs-test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/mqttjs-test.yml b/.github/workflows/mqttjs-test.yml index c7cccafdb..0e9e6726d 100644 --- a/.github/workflows/mqttjs-test.yml +++ b/.github/workflows/mqttjs-test.yml @@ -17,7 +17,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - node-version: [16.x, 18.x, 20.x] + node-version: [18.x, 20.x] fail-fast: false steps: From 993af18fdd4abbed6a788af67ceffa99e381dec1 Mon Sep 17 00:00:00 2001 From: Daniel Lando Date: Tue, 19 Sep 2023 11:31:03 +0200 Subject: [PATCH 07/26] fix: leaked handles --- package-lock.json | 52 +++++++++++++++++++++++ package.json | 1 + test/abstract_client.ts | 8 ++-- test/client.ts | 11 ++++- test/client_mqtt5.ts | 11 ++++- test/helpers/leaked.ts | 8 ++++ test/secure_client.ts | 12 +++++- test/server_helpers_for_client_tests.ts | 24 +++++++++-- test/unique_message_id_provider_client.ts | 2 + test/websocket_client.ts | 11 ++++- 10 files changed, 129 insertions(+), 11 deletions(-) create mode 100644 test/helpers/leaked.ts diff --git a/package-lock.json b/package-lock.json index 8e364e935..5688a116d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -55,6 +55,7 @@ "eslint-plugin-import": "^2.28.0", "eslint-plugin-prettier": "^5.0.0", "global": "^4.4.0", + "leaked-handles": "^5.2.0", "mkdirp": "^3.0.1", "mqtt-connection": "^4.1.0", "mqtt-level-store": "^3.1.0", @@ -8537,6 +8538,26 @@ "node": ">=0.10.0" } }, + "node_modules/leaked-handles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/leaked-handles/-/leaked-handles-5.2.0.tgz", + "integrity": "sha512-H96tZP5iXGw/t34Hhb8+ttcPXb/w1y5d3T4DTb81021UNI6LbtxylQBtiOuUwCiPbnKggykEmHc38hX+E41eag==", + "dev": true, + "dependencies": { + "process": "^0.10.0", + "weakmap-shim": "^1.1.0", + "xtend": "^4.0.0" + } + }, + "node_modules/leaked-handles/node_modules/process": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/process/-/process-0.10.1.tgz", + "integrity": "sha512-dyIett8dgGIZ/TXKUzeYExt7WA6ldDzys9vTDU/cCA9L17Ypme+KzS+NjQCjpn9xsvi/shbMC+yP/BcFMBz0NA==", + "dev": true, + "engines": { + "node": ">= 0.6.0" + } + }, "node_modules/level": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/level/-/level-5.0.1.tgz", @@ -14947,6 +14968,12 @@ "defaults": "^1.0.3" } }, + "node_modules/weakmap-shim": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/weakmap-shim/-/weakmap-shim-1.1.1.tgz", + "integrity": "sha512-/wNyG+1FpiHhnfQo+TuA/XAUpvOOkKVl0A4qpT+oGcj5SlZCLmM+M1Py/3Sj8sy+YrEauCVITOxCsZKo6sPbQg==", + "dev": true + }, "node_modules/web-streams-polyfill": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz", @@ -22114,6 +22141,25 @@ "integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4=", "dev": true }, + "leaked-handles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/leaked-handles/-/leaked-handles-5.2.0.tgz", + "integrity": "sha512-H96tZP5iXGw/t34Hhb8+ttcPXb/w1y5d3T4DTb81021UNI6LbtxylQBtiOuUwCiPbnKggykEmHc38hX+E41eag==", + "dev": true, + "requires": { + "process": "^0.10.0", + "weakmap-shim": "^1.1.0", + "xtend": "^4.0.0" + }, + "dependencies": { + "process": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/process/-/process-0.10.1.tgz", + "integrity": "sha512-dyIett8dgGIZ/TXKUzeYExt7WA6ldDzys9vTDU/cCA9L17Ypme+KzS+NjQCjpn9xsvi/shbMC+yP/BcFMBz0NA==", + "dev": true + } + } + }, "level": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/level/-/level-5.0.1.tgz", @@ -27190,6 +27236,12 @@ "defaults": "^1.0.3" } }, + "weakmap-shim": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/weakmap-shim/-/weakmap-shim-1.1.1.tgz", + "integrity": "sha512-/wNyG+1FpiHhnfQo+TuA/XAUpvOOkKVl0A4qpT+oGcj5SlZCLmM+M1Py/3Sj8sy+YrEauCVITOxCsZKo6sPbQg==", + "dev": true + }, "web-streams-polyfill": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz", diff --git a/package.json b/package.json index f9fe1a678..20ff7fa73 100644 --- a/package.json +++ b/package.json @@ -142,6 +142,7 @@ "eslint-plugin-import": "^2.28.0", "eslint-plugin-prettier": "^5.0.0", "global": "^4.4.0", + "leaked-handles": "^5.2.0", "mkdirp": "^3.0.1", "mqtt-connection": "^4.1.0", "mqtt-level-store": "^3.1.0", diff --git a/test/abstract_client.ts b/test/abstract_client.ts index b4697cbd3..4076b7980 100644 --- a/test/abstract_client.ts +++ b/test/abstract_client.ts @@ -307,7 +307,7 @@ export default function abstractTest(server, config) { server.once('client', (serverClient) => { serverClient.once('connect', (packet) => { assert.strictEqual(packet.clean, true) - done() + client.end((err) => done(err)) }) }) }) @@ -343,7 +343,7 @@ export default function abstractTest(server, config) { it('should require a clientId with clean=false', function _test(t, done) { try { - const client = connect({ clean: false }) + const client = connect({ clean: false, reconnectPeriod: 0 }) client.on('error', (err) => { done(err) }) @@ -365,7 +365,7 @@ export default function abstractTest(server, config) { server.once('client', (serverClient) => { serverClient.once('connect', (packet) => { assert.include(packet.clientId, 'testclient') - done() + client.end((err) => done(err)) }) }) }) @@ -530,7 +530,7 @@ export default function abstractTest(server, config) { } assert.isArray(granted2) assert.isEmpty(granted2) - done() + client.end((err3) => done(err3)) }) }) }) diff --git a/test/client.ts b/test/client.ts index 140fccaa6..566b71829 100644 --- a/test/client.ts +++ b/test/client.ts @@ -21,7 +21,10 @@ const debug = _debug('mqttjs:client-test') describe('MqttClient', () => { let client: mqtt.MqttClient const server = serverBuilder('mqtt') - const config: IClientOptions = { protocol: 'mqtt', port: ports.PORT } + const config: IClientOptions = { + protocol: 'mqtt', + port: ports.PORT, + } server.listen(ports.PORT) after(() => { @@ -29,6 +32,8 @@ describe('MqttClient', () => { if (server.listening) { server.close() } + + process.exit(0) }) abstractClientTests(server, config) @@ -627,6 +632,7 @@ describe('MqttClient', () => { await mqtt.connectAsync({ port: 1000, host: '127.0.0.1', + reconnectPeriod: 0, }) } catch (err) { error = true @@ -651,9 +657,12 @@ describe('MqttClient', () => { await client.publishAsync('#/#', 'world') } catch (err) { error = true + client.disconnecting = false assert.equal(err.message, 'client disconnecting') } + await client.endAsync() + assert.isTrue(error) }, ) diff --git a/test/client_mqtt5.ts b/test/client_mqtt5.ts index 66950b951..1875dcf45 100644 --- a/test/client_mqtt5.ts +++ b/test/client_mqtt5.ts @@ -5,7 +5,7 @@ import { MqttServer } from './server' import serverBuilder from './server_helpers_for_client_tests' import ports from './helpers/port_list' import { ErrorWithReasonCode } from '../src/lib/shared' -import { describe, it } from 'node:test' +import { after, describe, it } from 'node:test' describe('MQTT 5.0', () => { const server = serverBuilder('mqtt').listen(ports.PORTAND115) @@ -16,6 +16,15 @@ describe('MQTT 5.0', () => { properties: { maximumPacketSize: 200 }, } + after(() => { + // clean up and make sure the server is no longer listening... + if (server.listening) { + server.close() + } + + process.exit(0) + }) + abstractClientTests(server, config) it( diff --git a/test/helpers/leaked.ts b/test/helpers/leaked.ts new file mode 100644 index 000000000..413497be6 --- /dev/null +++ b/test/helpers/leaked.ts @@ -0,0 +1,8 @@ +// include this as first module when looking for leaked handles +import leaked from 'leaked-handles' + +leaked.set({ + fullStack: true, + timeout: 15000, + debugSockets: true, +}) diff --git a/test/secure_client.ts b/test/secure_client.ts index ca67ef055..9781b284c 100644 --- a/test/secure_client.ts +++ b/test/secure_client.ts @@ -5,7 +5,7 @@ import abstractClientTests from './abstract_client' import { MqttSecureServer, MqttServerListener } from './server' import { assert } from 'chai' import 'should' -import { describe, it, beforeEach, afterEach } from 'node:test' +import { describe, it, beforeEach, afterEach, after } from 'node:test' const port = 9899 const KEY = path.join(__dirname, 'helpers', 'tls-key.pem') @@ -79,6 +79,16 @@ const server = new MqttSecureServer( describe('MqttSecureClient', () => { const config = { protocol: 'mqtts', port, rejectUnauthorized: false } + + after(() => { + // clean up and make sure the server is no longer listening... + if (server.listening) { + server.close() + } + + process.exit(0) + }) + abstractClientTests(server, config) describe('with secure parameters', () => { diff --git a/test/server_helpers_for_client_tests.ts b/test/server_helpers_for_client_tests.ts index 27b962cf5..b82a0ff34 100644 --- a/test/server_helpers_for_client_tests.ts +++ b/test/server_helpers_for_client_tests.ts @@ -24,7 +24,9 @@ export default function serverBuilder( protocol: string, handler?: MqttServerListener, ): Server { + const sockets = [] const defaultHandler: MqttServerListener = (serverClient) => { + sockets.push(serverClient) serverClient.on('auth', (packet) => { if (serverClient.writable) return false const rc = 'reasonCode' @@ -111,6 +113,10 @@ export default function serverBuilder( serverClient.on('end', () => { debug('disconnected from server') + const index = sockets.findIndex((s) => s === serverClient) + if (index !== -1) { + sockets.splice(index, 1) + } }) } @@ -118,11 +124,13 @@ export default function serverBuilder( handler = defaultHandler } + let mqttServer = null + if (protocol === 'mqtt') { - return new MqttServer(handler) + mqttServer = new MqttServer(handler) } if (protocol === 'mqtts') { - return new MqttSecureServer( + mqttServer = new MqttSecureServer( { key: fs.readFileSync(KEY), cert: fs.readFileSync(CERT), @@ -153,6 +161,16 @@ export default function serverBuilder( // httpServer.connectionList = [] attachWebsocketServer(httpServer) httpServer.on('client', handler) - return httpServer + mqttServer = httpServer + } + + const originalClose = mqttServer.close + mqttServer.close = (cb) => { + sockets.forEach((socket) => { + socket.destroy() + }) + originalClose.call(mqttServer, cb) } + + return mqttServer } diff --git a/test/unique_message_id_provider_client.ts b/test/unique_message_id_provider_client.ts index a65c35abf..659d5e0f4 100644 --- a/test/unique_message_id_provider_client.ts +++ b/test/unique_message_id_provider_client.ts @@ -19,6 +19,8 @@ describe('UniqueMessageIdProviderMqttClient', () => { if (server.listening) { server.close() } + + process.exit(0) }) abstractClientTests(server, config) diff --git a/test/websocket_client.ts b/test/websocket_client.ts index 8409d9f0f..aecd88c56 100644 --- a/test/websocket_client.ts +++ b/test/websocket_client.ts @@ -7,7 +7,7 @@ import ports from './helpers/port_list' import { MqttServerNoWait } from './server' import * as mqtt from '../src/mqtt' import { IClientOptions } from '../src/lib/client' -import { describe, it } from 'node:test' +import { after, describe, it } from 'node:test' const port = 9999 const httpServer = http.createServer() @@ -98,6 +98,15 @@ describe('Websocket Client', () => { return { ...baseConfig, ...(custom || {}) } } + after(() => { + // clean up and make sure the server is no longer listening... + if (httpServer.listening) { + httpServer.close() + } + + process.exit(0) + }) + it('should use mqtt as the protocol by default', function _test(t, done) { httpServer.once('client', (client) => { assert.strictEqual(client.protocol, 'mqtt') From df6824388bc945dd7b3f134de646914da10870d0 Mon Sep 17 00:00:00 2001 From: Daniel Lando Date: Tue, 19 Sep 2023 11:41:37 +0200 Subject: [PATCH 08/26] fix: revert abstract test changes --- test/abstract_client.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/abstract_client.ts b/test/abstract_client.ts index 4076b7980..b4697cbd3 100644 --- a/test/abstract_client.ts +++ b/test/abstract_client.ts @@ -307,7 +307,7 @@ export default function abstractTest(server, config) { server.once('client', (serverClient) => { serverClient.once('connect', (packet) => { assert.strictEqual(packet.clean, true) - client.end((err) => done(err)) + done() }) }) }) @@ -343,7 +343,7 @@ export default function abstractTest(server, config) { it('should require a clientId with clean=false', function _test(t, done) { try { - const client = connect({ clean: false, reconnectPeriod: 0 }) + const client = connect({ clean: false }) client.on('error', (err) => { done(err) }) @@ -365,7 +365,7 @@ export default function abstractTest(server, config) { server.once('client', (serverClient) => { serverClient.once('connect', (packet) => { assert.include(packet.clientId, 'testclient') - client.end((err) => done(err)) + done() }) }) }) @@ -530,7 +530,7 @@ export default function abstractTest(server, config) { } assert.isArray(granted2) assert.isEmpty(granted2) - client.end((err3) => done(err3)) + done() }) }) }) From 62ba02096c811046d32e8142de4863121880801b Mon Sep 17 00:00:00 2001 From: Daniel Lando Date: Tue, 19 Sep 2023 11:43:56 +0200 Subject: [PATCH 09/26] chore: update engines --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 20ff7fa73..faf02b5d4 100644 --- a/package.json +++ b/package.json @@ -92,7 +92,7 @@ "lint" ], "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" }, "browser": { "./mqtt.js": "./build/mqtt.js", From 86a70f07fc852c0b3be695a883ec98ec62e2468f Mon Sep 17 00:00:00 2001 From: Daniel Lando Date: Tue, 19 Sep 2023 11:47:06 +0200 Subject: [PATCH 10/26] chore: increese timeout minutes --- .github/workflows/mqttjs-test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/mqttjs-test.yml b/.github/workflows/mqttjs-test.yml index 0e9e6726d..917924be1 100644 --- a/.github/workflows/mqttjs-test.yml +++ b/.github/workflows/mqttjs-test.yml @@ -39,7 +39,7 @@ jobs: - name: Test NodeJS run: npm run test:node - timeout-minutes: 3 + timeout-minutes: 5 env: CI: true DEBUG: "${{ runner.debug == '1' && 'mqttjs:*' || '' }}" From a2b696b4205d4df5968132e68f2b4be000862379 Mon Sep 17 00:00:00 2001 From: Daniel Lando Date: Tue, 19 Sep 2023 14:41:39 +0200 Subject: [PATCH 11/26] chore: use esbuild-register --- package-lock.json | 643 +++++++++++++++++++++++++++++++++++++++++++++- package.json | 3 +- test/runTests.ts | 4 +- 3 files changed, 645 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 5688a116d..85d6c0c62 100644 --- a/package-lock.json +++ b/package-lock.json @@ -48,6 +48,7 @@ "codecov": "^3.8.2", "conventional-changelog-cli": "^3.0.0", "end-of-stream": "^1.4.4", + "esbuild-register": "^3.5.0", "eslint": "^8.46.0", "eslint-config-airbnb-base": "^15.0.0", "eslint-config-airbnb-typescript": "^17.1.0", @@ -73,7 +74,7 @@ "typescript": "^5.1.6" }, "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" } }, "node_modules/@aashutoshrathi/word-wrap": { @@ -432,6 +433,380 @@ "@jridgewell/sourcemap-codec": "^1.4.10" } }, + "node_modules/@esbuild/android-arm": { + "version": "0.19.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.19.3.tgz", + "integrity": "sha512-Lemgw4io4VZl9GHJmjiBGzQ7ONXRfRPHcUEerndjwiSkbxzrpq0Uggku5MxxrXdwJ+pTj1qyw4jwTu7hkPsgIA==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "peer": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.19.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.19.3.tgz", + "integrity": "sha512-w+Akc0vv5leog550kjJV9Ru+MXMR2VuMrui3C61mnysim0gkFCPOUTAfzTP0qX+HpN9Syu3YA3p1hf3EPqObRw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "peer": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.19.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.19.3.tgz", + "integrity": "sha512-FKQJKkK5MXcBHoNZMDNUAg1+WcZlV/cuXrWCoGF/TvdRiYS4znA0m5Il5idUwfxrE20bG/vU1Cr5e1AD6IEIjQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "peer": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.19.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.19.3.tgz", + "integrity": "sha512-kw7e3FXU+VsJSSSl2nMKvACYlwtvZB8RUIeVShIEY6PVnuZ3c9+L9lWB2nWeeKWNNYDdtL19foCQ0ZyUL7nqGw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "peer": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.19.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.19.3.tgz", + "integrity": "sha512-tPfZiwF9rO0jW6Jh9ipi58N5ZLoSjdxXeSrAYypy4psA2Yl1dAMhM71KxVfmjZhJmxRjSnb29YlRXXhh3GqzYw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "peer": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.19.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.3.tgz", + "integrity": "sha512-ERDyjOgYeKe0Vrlr1iLrqTByB026YLPzTytDTz1DRCYM+JI92Dw2dbpRHYmdqn6VBnQ9Bor6J8ZlNwdZdxjlSg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "peer": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.19.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.19.3.tgz", + "integrity": "sha512-nXesBZ2Ad1qL+Rm3crN7NmEVJ5uvfLFPLJev3x1j3feCQXfAhoYrojC681RhpdOph8NsvKBBwpYZHR7W0ifTTA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "peer": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.19.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.19.3.tgz", + "integrity": "sha512-zr48Cg/8zkzZCzDHNxXO/89bf9e+r4HtzNUPoz4GmgAkF1gFAFmfgOdCbR8zMbzFDGb1FqBBhdXUpcTQRYS1cQ==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.19.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.19.3.tgz", + "integrity": "sha512-qXvYKmXj8GcJgWq3aGvxL/JG1ZM3UR272SdPU4QSTzD0eymrM7leiZH77pvY3UetCy0k1xuXZ+VPvoJNdtrsWQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.19.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.19.3.tgz", + "integrity": "sha512-7XlCKCA0nWcbvYpusARWkFjRQNWNGlt45S+Q18UeS///K6Aw8bB2FKYe9mhVWy/XLShvCweOLZPrnMswIaDXQA==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.19.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.19.3.tgz", + "integrity": "sha512-qGTgjweER5xqweiWtUIDl9OKz338EQqCwbS9c2Bh5jgEH19xQ1yhgGPNesugmDFq+UUSDtWgZ264st26b3de8A==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.19.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.19.3.tgz", + "integrity": "sha512-gy1bFskwEyxVMFRNYSvBauDIWNggD6pyxUksc0MV9UOBD138dKTzr8XnM2R4mBsHwVzeuIH8X5JhmNs2Pzrx+A==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.19.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.19.3.tgz", + "integrity": "sha512-UrYLFu62x1MmmIe85rpR3qou92wB9lEXluwMB/STDzPF9k8mi/9UvNsG07Tt9AqwPQXluMQ6bZbTzYt01+Ue5g==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.19.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.19.3.tgz", + "integrity": "sha512-9E73TfyMCbE+1AwFOg3glnzZ5fBAFK4aawssvuMgCRqCYzE0ylVxxzjEfut8xjmKkR320BEoMui4o/t9KA96gA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.19.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.19.3.tgz", + "integrity": "sha512-LlmsbuBdm1/D66TJ3HW6URY8wO6IlYHf+ChOUz8SUAjVTuaisfuwCOAgcxo3Zsu3BZGxmI7yt//yGOxV+lHcEA==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.19.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.19.3.tgz", + "integrity": "sha512-ogV0+GwEmvwg/8ZbsyfkYGaLACBQWDvO0Kkh8LKBGKj9Ru8VM39zssrnu9Sxn1wbapA2qNS6BiLdwJZGouyCwQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.19.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.19.3.tgz", + "integrity": "sha512-o1jLNe4uzQv2DKXMlmEzf66Wd8MoIhLNO2nlQBHLtWyh2MitDG7sMpfCO3NTcoTMuqHjfufgUQDFRI5C+xsXQw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "peer": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.19.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.19.3.tgz", + "integrity": "sha512-AZJCnr5CZgZOdhouLcfRdnk9Zv6HbaBxjcyhq0StNcvAdVZJSKIdOiPB9az2zc06ywl0ePYJz60CjdKsQacp5Q==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "peer": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.19.3", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.19.3.tgz", + "integrity": "sha512-Acsujgeqg9InR4glTRvLKGZ+1HMtDm94ehTIHKhJjFpgVzZG9/pIcWW/HA/DoMfEyXmANLDuDZ2sNrWcjq1lxw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "peer": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.19.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.19.3.tgz", + "integrity": "sha512-FSrAfjVVy7TifFgYgliiJOyYynhQmqgPj15pzLyJk8BUsnlWNwP/IAy6GAiB1LqtoivowRgidZsfpoYLZH586A==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "peer": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.19.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.19.3.tgz", + "integrity": "sha512-xTScXYi12xLOWZ/sc5RBmMN99BcXp/eEf7scUC0oeiRoiT5Vvo9AycuqCp+xdpDyAU+LkrCqEpUS9fCSZF8J3Q==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "peer": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.19.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.19.3.tgz", + "integrity": "sha512-FbUN+0ZRXsypPyWE2IwIkVjDkDnJoMJARWOcFZn4KPPli+QnKqF0z1anvfaYe3ev5HFCpRDLLBDHyOALLppWHw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "peer": true, + "engines": { + "node": ">=12" + } + }, "node_modules/@eslint-community/eslint-utils": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", @@ -5244,6 +5619,56 @@ "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==", "dev": true }, + "node_modules/esbuild": { + "version": "0.19.3", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.19.3.tgz", + "integrity": "sha512-UlJ1qUUA2jL2nNib1JTSkifQTcYTroFqRjwCFW4QYEKEsixXD5Tik9xML7zh2gTxkYTBKGHNH9y7txMwVyPbjw==", + "dev": true, + "hasInstallScript": true, + "peer": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/android-arm": "0.19.3", + "@esbuild/android-arm64": "0.19.3", + "@esbuild/android-x64": "0.19.3", + "@esbuild/darwin-arm64": "0.19.3", + "@esbuild/darwin-x64": "0.19.3", + "@esbuild/freebsd-arm64": "0.19.3", + "@esbuild/freebsd-x64": "0.19.3", + "@esbuild/linux-arm": "0.19.3", + "@esbuild/linux-arm64": "0.19.3", + "@esbuild/linux-ia32": "0.19.3", + "@esbuild/linux-loong64": "0.19.3", + "@esbuild/linux-mips64el": "0.19.3", + "@esbuild/linux-ppc64": "0.19.3", + "@esbuild/linux-riscv64": "0.19.3", + "@esbuild/linux-s390x": "0.19.3", + "@esbuild/linux-x64": "0.19.3", + "@esbuild/netbsd-x64": "0.19.3", + "@esbuild/openbsd-x64": "0.19.3", + "@esbuild/sunos-x64": "0.19.3", + "@esbuild/win32-arm64": "0.19.3", + "@esbuild/win32-ia32": "0.19.3", + "@esbuild/win32-x64": "0.19.3" + } + }, + "node_modules/esbuild-register": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/esbuild-register/-/esbuild-register-3.5.0.tgz", + "integrity": "sha512-+4G/XmakeBAsvJuDugJvtyF1x+XJT4FMocynNpxrvEBViirpfUn2PgNpCHedfWhF4WokNsO/OvMKrmJOIJsI5A==", + "dev": true, + "dependencies": { + "debug": "^4.3.4" + }, + "peerDependencies": { + "esbuild": ">=0.12 <1" + } + }, "node_modules/escalade": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", @@ -15758,6 +16183,182 @@ } } }, + "@esbuild/android-arm": { + "version": "0.19.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.19.3.tgz", + "integrity": "sha512-Lemgw4io4VZl9GHJmjiBGzQ7ONXRfRPHcUEerndjwiSkbxzrpq0Uggku5MxxrXdwJ+pTj1qyw4jwTu7hkPsgIA==", + "dev": true, + "optional": true, + "peer": true + }, + "@esbuild/android-arm64": { + "version": "0.19.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.19.3.tgz", + "integrity": "sha512-w+Akc0vv5leog550kjJV9Ru+MXMR2VuMrui3C61mnysim0gkFCPOUTAfzTP0qX+HpN9Syu3YA3p1hf3EPqObRw==", + "dev": true, + "optional": true, + "peer": true + }, + "@esbuild/android-x64": { + "version": "0.19.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.19.3.tgz", + "integrity": "sha512-FKQJKkK5MXcBHoNZMDNUAg1+WcZlV/cuXrWCoGF/TvdRiYS4znA0m5Il5idUwfxrE20bG/vU1Cr5e1AD6IEIjQ==", + "dev": true, + "optional": true, + "peer": true + }, + "@esbuild/darwin-arm64": { + "version": "0.19.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.19.3.tgz", + "integrity": "sha512-kw7e3FXU+VsJSSSl2nMKvACYlwtvZB8RUIeVShIEY6PVnuZ3c9+L9lWB2nWeeKWNNYDdtL19foCQ0ZyUL7nqGw==", + "dev": true, + "optional": true, + "peer": true + }, + "@esbuild/darwin-x64": { + "version": "0.19.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.19.3.tgz", + "integrity": "sha512-tPfZiwF9rO0jW6Jh9ipi58N5ZLoSjdxXeSrAYypy4psA2Yl1dAMhM71KxVfmjZhJmxRjSnb29YlRXXhh3GqzYw==", + "dev": true, + "optional": true, + "peer": true + }, + "@esbuild/freebsd-arm64": { + "version": "0.19.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.3.tgz", + "integrity": "sha512-ERDyjOgYeKe0Vrlr1iLrqTByB026YLPzTytDTz1DRCYM+JI92Dw2dbpRHYmdqn6VBnQ9Bor6J8ZlNwdZdxjlSg==", + "dev": true, + "optional": true, + "peer": true + }, + "@esbuild/freebsd-x64": { + "version": "0.19.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.19.3.tgz", + "integrity": "sha512-nXesBZ2Ad1qL+Rm3crN7NmEVJ5uvfLFPLJev3x1j3feCQXfAhoYrojC681RhpdOph8NsvKBBwpYZHR7W0ifTTA==", + "dev": true, + "optional": true, + "peer": true + }, + "@esbuild/linux-arm": { + "version": "0.19.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.19.3.tgz", + "integrity": "sha512-zr48Cg/8zkzZCzDHNxXO/89bf9e+r4HtzNUPoz4GmgAkF1gFAFmfgOdCbR8zMbzFDGb1FqBBhdXUpcTQRYS1cQ==", + "dev": true, + "optional": true, + "peer": true + }, + "@esbuild/linux-arm64": { + "version": "0.19.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.19.3.tgz", + "integrity": "sha512-qXvYKmXj8GcJgWq3aGvxL/JG1ZM3UR272SdPU4QSTzD0eymrM7leiZH77pvY3UetCy0k1xuXZ+VPvoJNdtrsWQ==", + "dev": true, + "optional": true, + "peer": true + }, + "@esbuild/linux-ia32": { + "version": "0.19.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.19.3.tgz", + "integrity": "sha512-7XlCKCA0nWcbvYpusARWkFjRQNWNGlt45S+Q18UeS///K6Aw8bB2FKYe9mhVWy/XLShvCweOLZPrnMswIaDXQA==", + "dev": true, + "optional": true, + "peer": true + }, + "@esbuild/linux-loong64": { + "version": "0.19.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.19.3.tgz", + "integrity": "sha512-qGTgjweER5xqweiWtUIDl9OKz338EQqCwbS9c2Bh5jgEH19xQ1yhgGPNesugmDFq+UUSDtWgZ264st26b3de8A==", + "dev": true, + "optional": true, + "peer": true + }, + "@esbuild/linux-mips64el": { + "version": "0.19.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.19.3.tgz", + "integrity": "sha512-gy1bFskwEyxVMFRNYSvBauDIWNggD6pyxUksc0MV9UOBD138dKTzr8XnM2R4mBsHwVzeuIH8X5JhmNs2Pzrx+A==", + "dev": true, + "optional": true, + "peer": true + }, + "@esbuild/linux-ppc64": { + "version": "0.19.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.19.3.tgz", + "integrity": "sha512-UrYLFu62x1MmmIe85rpR3qou92wB9lEXluwMB/STDzPF9k8mi/9UvNsG07Tt9AqwPQXluMQ6bZbTzYt01+Ue5g==", + "dev": true, + "optional": true, + "peer": true + }, + "@esbuild/linux-riscv64": { + "version": "0.19.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.19.3.tgz", + "integrity": "sha512-9E73TfyMCbE+1AwFOg3glnzZ5fBAFK4aawssvuMgCRqCYzE0ylVxxzjEfut8xjmKkR320BEoMui4o/t9KA96gA==", + "dev": true, + "optional": true, + "peer": true + }, + "@esbuild/linux-s390x": { + "version": "0.19.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.19.3.tgz", + "integrity": "sha512-LlmsbuBdm1/D66TJ3HW6URY8wO6IlYHf+ChOUz8SUAjVTuaisfuwCOAgcxo3Zsu3BZGxmI7yt//yGOxV+lHcEA==", + "dev": true, + "optional": true, + "peer": true + }, + "@esbuild/linux-x64": { + "version": "0.19.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.19.3.tgz", + "integrity": "sha512-ogV0+GwEmvwg/8ZbsyfkYGaLACBQWDvO0Kkh8LKBGKj9Ru8VM39zssrnu9Sxn1wbapA2qNS6BiLdwJZGouyCwQ==", + "dev": true, + "optional": true, + "peer": true + }, + "@esbuild/netbsd-x64": { + "version": "0.19.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.19.3.tgz", + "integrity": "sha512-o1jLNe4uzQv2DKXMlmEzf66Wd8MoIhLNO2nlQBHLtWyh2MitDG7sMpfCO3NTcoTMuqHjfufgUQDFRI5C+xsXQw==", + "dev": true, + "optional": true, + "peer": true + }, + "@esbuild/openbsd-x64": { + "version": "0.19.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.19.3.tgz", + "integrity": "sha512-AZJCnr5CZgZOdhouLcfRdnk9Zv6HbaBxjcyhq0StNcvAdVZJSKIdOiPB9az2zc06ywl0ePYJz60CjdKsQacp5Q==", + "dev": true, + "optional": true, + "peer": true + }, + "@esbuild/sunos-x64": { + "version": "0.19.3", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.19.3.tgz", + "integrity": "sha512-Acsujgeqg9InR4glTRvLKGZ+1HMtDm94ehTIHKhJjFpgVzZG9/pIcWW/HA/DoMfEyXmANLDuDZ2sNrWcjq1lxw==", + "dev": true, + "optional": true, + "peer": true + }, + "@esbuild/win32-arm64": { + "version": "0.19.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.19.3.tgz", + "integrity": "sha512-FSrAfjVVy7TifFgYgliiJOyYynhQmqgPj15pzLyJk8BUsnlWNwP/IAy6GAiB1LqtoivowRgidZsfpoYLZH586A==", + "dev": true, + "optional": true, + "peer": true + }, + "@esbuild/win32-ia32": { + "version": "0.19.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.19.3.tgz", + "integrity": "sha512-xTScXYi12xLOWZ/sc5RBmMN99BcXp/eEf7scUC0oeiRoiT5Vvo9AycuqCp+xdpDyAU+LkrCqEpUS9fCSZF8J3Q==", + "dev": true, + "optional": true, + "peer": true + }, + "@esbuild/win32-x64": { + "version": "0.19.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.19.3.tgz", + "integrity": "sha512-FbUN+0ZRXsypPyWE2IwIkVjDkDnJoMJARWOcFZn4KPPli+QnKqF0z1anvfaYe3ev5HFCpRDLLBDHyOALLppWHw==", + "dev": true, + "optional": true, + "peer": true + }, "@eslint-community/eslint-utils": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", @@ -19618,6 +20219,46 @@ "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==", "dev": true }, + "esbuild": { + "version": "0.19.3", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.19.3.tgz", + "integrity": "sha512-UlJ1qUUA2jL2nNib1JTSkifQTcYTroFqRjwCFW4QYEKEsixXD5Tik9xML7zh2gTxkYTBKGHNH9y7txMwVyPbjw==", + "dev": true, + "peer": true, + "requires": { + "@esbuild/android-arm": "0.19.3", + "@esbuild/android-arm64": "0.19.3", + "@esbuild/android-x64": "0.19.3", + "@esbuild/darwin-arm64": "0.19.3", + "@esbuild/darwin-x64": "0.19.3", + "@esbuild/freebsd-arm64": "0.19.3", + "@esbuild/freebsd-x64": "0.19.3", + "@esbuild/linux-arm": "0.19.3", + "@esbuild/linux-arm64": "0.19.3", + "@esbuild/linux-ia32": "0.19.3", + "@esbuild/linux-loong64": "0.19.3", + "@esbuild/linux-mips64el": "0.19.3", + "@esbuild/linux-ppc64": "0.19.3", + "@esbuild/linux-riscv64": "0.19.3", + "@esbuild/linux-s390x": "0.19.3", + "@esbuild/linux-x64": "0.19.3", + "@esbuild/netbsd-x64": "0.19.3", + "@esbuild/openbsd-x64": "0.19.3", + "@esbuild/sunos-x64": "0.19.3", + "@esbuild/win32-arm64": "0.19.3", + "@esbuild/win32-ia32": "0.19.3", + "@esbuild/win32-x64": "0.19.3" + } + }, + "esbuild-register": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/esbuild-register/-/esbuild-register-3.5.0.tgz", + "integrity": "sha512-+4G/XmakeBAsvJuDugJvtyF1x+XJT4FMocynNpxrvEBViirpfUn2PgNpCHedfWhF4WokNsO/OvMKrmJOIJsI5A==", + "dev": true, + "requires": { + "debug": "^4.3.4" + } + }, "escalade": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", diff --git a/package.json b/package.json index faf02b5d4..10d895b5c 100644 --- a/package.json +++ b/package.json @@ -56,7 +56,7 @@ "build:browser": "rimraf dist/ && mkdirp dist/ && browserify build/mqtt.js --standalone mqtt > dist/mqtt.js && terser dist/mqtt.js --compress --mangle --output dist/mqtt.min.js", "build": "npm run build:ts && npm run build:browser", "prepare": "npm run build", - "unit-test:node": "node_modules/.bin/nyc --reporter=lcov --reporter=text node -r ts-node/register test/runTests.ts", + "unit-test:node": "node_modules/.bin/nyc --reporter=lcov --reporter=text node -r esbuild-register test/runTests.ts", "unit-test:browser": "airtap --server test/browser/server.js test/browser/test.js", "test:node": "npm run unit-test:node && codecov", "test:browser": "npm run build && npm run unit-test:browser", @@ -135,6 +135,7 @@ "codecov": "^3.8.2", "conventional-changelog-cli": "^3.0.0", "end-of-stream": "^1.4.4", + "esbuild-register": "^3.5.0", "eslint": "^8.46.0", "eslint-config-airbnb-base": "^15.0.0", "eslint-config-airbnb-typescript": "^17.1.0", diff --git a/test/runTests.ts b/test/runTests.ts index 0add7f6e8..375b8d18d 100644 --- a/test/runTests.ts +++ b/test/runTests.ts @@ -7,8 +7,6 @@ const files = readdirSync(__dirname) .filter((f) => f.endsWith('.ts')) .map((f) => `${__dirname}/${f}`) -console.log('Running tests:') - -run({ files, timeout: 60 * 1000 }) +run({ files, timeout: 60 * 1000, concurrency: 2 }) .compose(tap) .pipe(process.stdout) From 26dc2e8aa99755bf5225ed069a370986ac11f184 Mon Sep 17 00:00:00 2001 From: Daniel Lando Date: Tue, 19 Sep 2023 14:51:49 +0200 Subject: [PATCH 12/26] fix: increese concurrency --- test/helpers/port_list.ts | 2 +- test/runTests.ts | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/test/helpers/port_list.ts b/test/helpers/port_list.ts index b4aed27d1..81a2921b0 100644 --- a/test/helpers/port_list.ts +++ b/test/helpers/port_list.ts @@ -1,4 +1,4 @@ -const PORT = 9876 +const PORT = Math.round(Math.random() * 1000) + 1000 const PORTAND40 = PORT + 40 const PORTAND41 = PORT + 41 const PORTAND42 = PORT + 42 diff --git a/test/runTests.ts b/test/runTests.ts index 375b8d18d..055c68e7c 100644 --- a/test/runTests.ts +++ b/test/runTests.ts @@ -2,11 +2,12 @@ import { readdirSync } from 'node:fs' import { run } from 'node:test' import process from 'node:process' import { tap } from 'node:test/reporters' +import { basename } from 'node:path' const files = readdirSync(__dirname) - .filter((f) => f.endsWith('.ts')) + .filter((f) => f.endsWith('.ts') && f !== basename(__filename)) .map((f) => `${__dirname}/${f}`) -run({ files, timeout: 60 * 1000, concurrency: 2 }) +run({ files, timeout: 60 * 1000, concurrency: true }) .compose(tap) .pipe(process.stdout) From 118b4a96d15615cd6ea743cd59fcc74381b05821 Mon Sep 17 00:00:00 2001 From: Daniel Lando Date: Tue, 19 Sep 2023 15:06:21 +0200 Subject: [PATCH 13/26] fix: try to use max concurrency --- test/abstract_client.ts | 3 +- test/client.ts | 6 +- test/client_mqtt5.ts | 6 +- test/helpers/port_list.ts | 83 ++++++++++------------- test/unique_message_id_provider_client.ts | 6 +- test/websocket_client.ts | 6 +- 6 files changed, 51 insertions(+), 59 deletions(-) diff --git a/test/abstract_client.ts b/test/abstract_client.ts index b4697cbd3..7d876b79b 100644 --- a/test/abstract_client.ts +++ b/test/abstract_client.ts @@ -7,7 +7,6 @@ import fs from 'fs' import levelStore from 'mqtt-level-store' import * as mqtt from '../src/mqtt' import Store from '../src/lib/store' -import ports from './helpers/port_list' import serverBuilder from './server_helpers_for_client_tests' import handlePubrel from '../src/lib/handlers/pubrel' import handle from '../src/lib/handlers/index' @@ -45,7 +44,7 @@ import { describe, it, beforeEach, afterEach } from 'node:test' * */ -export default function abstractTest(server, config) { +export default function abstractTest(server, config, ports) { const version = config.protocolVersion || 4 function connect(opts?: IClientOptions | string) { diff --git a/test/client.ts b/test/client.ts index 566b71829..06696bc16 100644 --- a/test/client.ts +++ b/test/client.ts @@ -8,7 +8,7 @@ import mqttPacket from 'mqtt-packet' import { Duplex } from 'readable-stream' import Connection from 'mqtt-connection' import util from 'util' -import ports from './helpers/port_list' +import getPorts from './helpers/port_list' import serverBuilder from './server_helpers_for_client_tests' import _debug from 'debug' import { MqttServer } from './server' @@ -18,6 +18,8 @@ import { describe, it, after } from 'node:test' const debug = _debug('mqttjs:client-test') +const ports = getPorts(2) + describe('MqttClient', () => { let client: mqtt.MqttClient const server = serverBuilder('mqtt') @@ -36,7 +38,7 @@ describe('MqttClient', () => { process.exit(0) }) - abstractClientTests(server, config) + abstractClientTests(server, config, ports) describe('creating', () => { it('should allow instantiation of MqttClient', function _test(t, done) { diff --git a/test/client_mqtt5.ts b/test/client_mqtt5.ts index 1875dcf45..6e1d709ca 100644 --- a/test/client_mqtt5.ts +++ b/test/client_mqtt5.ts @@ -3,10 +3,12 @@ import * as mqtt from '../src/mqtt' import abstractClientTests from './abstract_client' import { MqttServer } from './server' import serverBuilder from './server_helpers_for_client_tests' -import ports from './helpers/port_list' +import getPorts from './helpers/port_list' import { ErrorWithReasonCode } from '../src/lib/shared' import { after, describe, it } from 'node:test' +const ports = getPorts(1) + describe('MQTT 5.0', () => { const server = serverBuilder('mqtt').listen(ports.PORTAND115) const config = { @@ -25,7 +27,7 @@ describe('MQTT 5.0', () => { process.exit(0) }) - abstractClientTests(server, config) + abstractClientTests(server, config, ports) it( 'topic should be complemented on receive', diff --git a/test/helpers/port_list.ts b/test/helpers/port_list.ts index 81a2921b0..af2f7dbfe 100644 --- a/test/helpers/port_list.ts +++ b/test/helpers/port_list.ts @@ -1,51 +1,36 @@ -const PORT = Math.round(Math.random() * 1000) + 1000 -const PORTAND40 = PORT + 40 -const PORTAND41 = PORT + 41 -const PORTAND42 = PORT + 42 -const PORTAND43 = PORT + 43 -const PORTAND44 = PORT + 44 -const PORTAND45 = PORT + 45 -const PORTAND46 = PORT + 46 -const PORTAND47 = PORT + 47 -const PORTAND48 = PORT + 48 -const PORTAND49 = PORT + 49 -const PORTAND50 = PORT + 50 -const PORTAND72 = PORT + 72 -const PORTAND103 = PORT + 103 -const PORTAND114 = PORT + 114 -const PORTAND115 = PORT + 115 -const PORTAND116 = PORT + 116 -const PORTAND117 = PORT + 117 -const PORTAND118 = PORT + 118 -const PORTAND119 = PORT + 119 -const PORTAND316 = PORT + 316 -const PORTAND326 = PORT + 326 -const PORTAND327 = PORT + 327 -const PORTAND400 = PORT + 400 +/** + * Method used to get ports for testing + * @param i Index to shift the ports by + * @returns + */ +export default function getPorts(i = 0) { + const PORT = 10000 + i * 400 + const ports = { + PORT, + PORTAND40: PORT + 40, + PORTAND41: PORT + 41, + PORTAND42: PORT + 42, + PORTAND43: PORT + 43, + PORTAND44: PORT + 44, + PORTAND45: PORT + 45, + PORTAND46: PORT + 46, + PORTAND47: PORT + 47, + PORTAND48: PORT + 48, + PORTAND49: PORT + 49, + PORTAND50: PORT + 50, + PORTAND72: PORT + 72, + PORTAND103: PORT + 103, + PORTAND114: PORT + 114, + PORTAND115: PORT + 115, + PORTAND116: PORT + 116, + PORTAND117: PORT + 117, + PORTAND118: PORT + 118, + PORTAND119: PORT + 119, + PORTAND316: PORT + 316, + PORTAND326: PORT + 326, + PORTAND327: PORT + 327, + PORTAND400: PORT + 400, + } -export default { - PORT, - PORTAND40, - PORTAND41, - PORTAND42, - PORTAND43, - PORTAND44, - PORTAND45, - PORTAND46, - PORTAND47, - PORTAND48, - PORTAND49, - PORTAND50, - PORTAND72, - PORTAND103, - PORTAND114, - PORTAND115, - PORTAND116, - PORTAND117, - PORTAND118, - PORTAND119, - PORTAND316, - PORTAND326, - PORTAND327, - PORTAND400, + return ports } diff --git a/test/unique_message_id_provider_client.ts b/test/unique_message_id_provider_client.ts index 659d5e0f4..eaedfb351 100644 --- a/test/unique_message_id_provider_client.ts +++ b/test/unique_message_id_provider_client.ts @@ -1,10 +1,12 @@ import abstractClientTests from './abstract_client' import serverBuilder from './server_helpers_for_client_tests' import UniqueMessageIdProvider from '../src/lib/unique-message-id-provider' -import ports from './helpers/port_list' +import getPorts from './helpers/port_list' import { IClientOptions } from 'src/mqtt' import { describe, after } from 'node:test' +const ports = getPorts(3) + describe('UniqueMessageIdProviderMqttClient', () => { const server = serverBuilder('mqtt') const config: IClientOptions = { @@ -23,5 +25,5 @@ describe('UniqueMessageIdProviderMqttClient', () => { process.exit(0) }) - abstractClientTests(server, config) + abstractClientTests(server, config, ports) }) diff --git a/test/websocket_client.ts b/test/websocket_client.ts index aecd88c56..02e437b98 100644 --- a/test/websocket_client.ts +++ b/test/websocket_client.ts @@ -3,12 +3,14 @@ import WebSocket from 'ws' import MQTTConnection from 'mqtt-connection' import assert from 'assert' import abstractClientTests from './abstract_client' -import ports from './helpers/port_list' +import getPorts from './helpers/port_list' import { MqttServerNoWait } from './server' import * as mqtt from '../src/mqtt' import { IClientOptions } from '../src/lib/client' import { after, describe, it } from 'node:test' +const ports = getPorts(4) + const port = 9999 const httpServer = http.createServer() let lastProcotols = new Set() @@ -259,5 +261,5 @@ describe('Websocket Client', () => { ) }) - abstractClientTests(httpServer, makeOptions()) + abstractClientTests(httpServer, makeOptions(), ports) }) From 15a2a4041dc340f35751af064951ba92ba74a1bf Mon Sep 17 00:00:00 2001 From: Daniel Lando Date: Tue, 19 Sep 2023 15:25:54 +0200 Subject: [PATCH 14/26] fix: store tests are failing --- test/abstract_store.ts | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/test/abstract_store.ts b/test/abstract_store.ts index 07c154059..5c095dbf5 100644 --- a/test/abstract_store.ts +++ b/test/abstract_store.ts @@ -8,15 +8,20 @@ export default function abstractStoreTest( ) { let store: IStore - // eslint-disable-next-line - beforeEach((done) => { + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-expect-error + beforeEach((_ctx, done) => { + console.log('beforeEach', done) + console.log('build', typeof done) build((err, _store) => { store = _store done(err) }) }) - afterEach((done) => { + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-expect-error + afterEach((_ctx, done) => { store.close(done) }) From 0a1633686a9ad0fc05f305f72b36e749190ca846 Mon Sep 17 00:00:00 2001 From: Daniel Lando Date: Tue, 19 Sep 2023 15:27:24 +0200 Subject: [PATCH 15/26] fix: wrong ci From 5f79076b520191f55bf5f57a811a4dc99c2d5e82 Mon Sep 17 00:00:00 2001 From: Daniel Lando Date: Tue, 19 Sep 2023 15:32:09 +0200 Subject: [PATCH 16/26] fix: remove useless console.log --- test/abstract_store.ts | 2 -- test/secure_client.ts | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/test/abstract_store.ts b/test/abstract_store.ts index 5c095dbf5..3a1ea4a45 100644 --- a/test/abstract_store.ts +++ b/test/abstract_store.ts @@ -11,8 +11,6 @@ export default function abstractStoreTest( // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-expect-error beforeEach((_ctx, done) => { - console.log('beforeEach', done) - console.log('build', typeof done) build((err, _store) => { store = _store done(err) diff --git a/test/secure_client.ts b/test/secure_client.ts index 9781b284c..87df5fb21 100644 --- a/test/secure_client.ts +++ b/test/secure_client.ts @@ -5,7 +5,7 @@ import abstractClientTests from './abstract_client' import { MqttSecureServer, MqttServerListener } from './server' import { assert } from 'chai' import 'should' -import { describe, it, beforeEach, afterEach, after } from 'node:test' +import { describe, it, after } from 'node:test' const port = 9899 const KEY = path.join(__dirname, 'helpers', 'tls-key.pem') From f8a728a304b9b42a24cda9033ff28da3952a8bc3 Mon Sep 17 00:00:00 2001 From: Daniel Lando Date: Tue, 19 Sep 2023 15:39:33 +0200 Subject: [PATCH 17/26] fix: message id provider tests and websocket --- test/message-id-provider.ts | 20 ++++++++++---------- test/websocket_client.ts | 4 ++-- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/test/message-id-provider.ts b/test/message-id-provider.ts index 4192bb311..c45265b06 100644 --- a/test/message-id-provider.ts +++ b/test/message-id-provider.ts @@ -5,7 +5,7 @@ import { describe, it } from 'node:test' describe('message id provider', () => { describe('default', () => { - it('should return 1 once the internal counter reached limit', (t, done) => { + it('should return 1 once the internal counter reached limit', (t) => { const provider = new DefaultMessageIdProvider() provider['nextId'] = 65535 @@ -13,7 +13,7 @@ describe('message id provider', () => { assert.equal(provider.allocate(), 1) }) - it('should return 65535 for last message id once the internal counter reached limit', (t, done) => { + it('should return 65535 for last message id once the internal counter reached limit', (t) => { const provider = new DefaultMessageIdProvider() provider['nextId'] = 65535 @@ -22,32 +22,32 @@ describe('message id provider', () => { assert.equal(provider.allocate(), 1) assert.equal(provider.getLastAllocated(), 1) }) - it('should return true when register with non allocated messageId', (t, done) => { + it('should return true when register with non allocated messageId', (t) => { const provider = new DefaultMessageIdProvider() assert.equal(provider.register(10), true) }) }) describe('unique', () => { - it('should return 1, 2, 3.., when allocate', (t, done) => { + it('should return 1, 2, 3.., when allocate', (t) => { const provider = new UniqueMessageIdProvider() assert.equal(provider.allocate(), 1) assert.equal(provider.allocate(), 2) assert.equal(provider.allocate(), 3) }) - it('should skip registerd messageId', (t, done) => { + it('should skip registerd messageId', (t) => { const provider = new UniqueMessageIdProvider() assert.equal(provider.register(2), true) assert.equal(provider.allocate(), 1) assert.equal(provider.allocate(), 3) }) - it('should return false register allocated messageId', (t, done) => { + it('should return false register allocated messageId', (t) => { const provider = new UniqueMessageIdProvider() assert.equal(provider.allocate(), 1) assert.equal(provider.register(1), false) assert.equal(provider.register(5), true) assert.equal(provider.register(5), false) }) - it('should retrun correct last messageId', (t, done) => { + it('should retrun correct last messageId', (t) => { const provider = new UniqueMessageIdProvider() assert.equal(provider.allocate(), 1) assert.equal(provider.getLastAllocated(), 1) @@ -56,7 +56,7 @@ describe('message id provider', () => { assert.equal(provider.allocate(), 3) assert.equal(provider.getLastAllocated(), 3) }) - it('should be reusable deallocated messageId', (t, done) => { + it('should be reusable deallocated messageId', (t) => { const provider = new UniqueMessageIdProvider() assert.equal(provider.allocate(), 1) assert.equal(provider.allocate(), 2) @@ -64,7 +64,7 @@ describe('message id provider', () => { provider.deallocate(2) assert.equal(provider.allocate(), 2) }) - it('should allocate all messageId and then return null', (t, done) => { + it('should allocate all messageId and then return null', (t) => { const provider = new UniqueMessageIdProvider() for (let i = 1; i <= 65535; i++) { assert.equal(provider.allocate(), i) @@ -74,7 +74,7 @@ describe('message id provider', () => { assert.equal(provider.allocate(), 10000) assert.equal(provider.allocate(), null) }) - it('should all messageId reallocatable after clear', (t, done) => { + it('should all messageId reallocatable after clear', (t) => { const provider = new UniqueMessageIdProvider() for (let i = 1; i <= 65535; i++) { assert.equal(provider.allocate(), i) diff --git a/test/websocket_client.ts b/test/websocket_client.ts index 02e437b98..af37c5839 100644 --- a/test/websocket_client.ts +++ b/test/websocket_client.ts @@ -206,8 +206,8 @@ describe('Websocket Client', () => { serverClient.connack({ returnCode: 0 }) }) } - const actualURL41 = 'wss://localhost:9917/' - const actualURL42 = 'ws://localhost:9918/' + const actualURL41 = `wss://localhost:${ports.PORTAND41}/` + const actualURL42 = `ws://localhost:${ports.PORTAND42}/` const serverPort41 = new MqttServerNoWait(handler).listen( ports.PORTAND41, ) From e01ada0c964658630e79d63220a0b86b54e5e87c Mon Sep 17 00:00:00 2001 From: Daniel Lando Date: Tue, 19 Sep 2023 15:43:06 +0200 Subject: [PATCH 18/26] fix: pass all tests --- test/secure_client.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/test/secure_client.ts b/test/secure_client.ts index 87df5fb21..eec731561 100644 --- a/test/secure_client.ts +++ b/test/secure_client.ts @@ -6,8 +6,11 @@ import { MqttSecureServer, MqttServerListener } from './server' import { assert } from 'chai' import 'should' import { describe, it, after } from 'node:test' +import getPorts from './helpers/port_list' -const port = 9899 +const ports = getPorts(5) + +const port = ports.PORT const KEY = path.join(__dirname, 'helpers', 'tls-key.pem') const CERT = path.join(__dirname, 'helpers', 'tls-cert.pem') const WRONG_CERT = path.join(__dirname, 'helpers', 'wrong-cert.pem') @@ -89,7 +92,7 @@ describe('MqttSecureClient', () => { process.exit(0) }) - abstractClientTests(server, config) + abstractClientTests(server, config, ports) describe('with secure parameters', () => { it('should validate successfully the CA', function _test(t, done) { From 0a5d1262a13776855893765cfeb035b1110a3d24 Mon Sep 17 00:00:00 2001 From: Daniel Lando Date: Tue, 19 Sep 2023 15:53:54 +0200 Subject: [PATCH 19/26] fix: try running tests using `--test` --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 10d895b5c..c49179d1d 100644 --- a/package.json +++ b/package.json @@ -56,7 +56,7 @@ "build:browser": "rimraf dist/ && mkdirp dist/ && browserify build/mqtt.js --standalone mqtt > dist/mqtt.js && terser dist/mqtt.js --compress --mangle --output dist/mqtt.min.js", "build": "npm run build:ts && npm run build:browser", "prepare": "npm run build", - "unit-test:node": "node_modules/.bin/nyc --reporter=lcov --reporter=text node -r esbuild-register test/runTests.ts", + "unit-test:node": "node_modules/.bin/nyc --reporter=lcov --reporter=text node -r esbuild-register --test test/*.ts", "unit-test:browser": "airtap --server test/browser/server.js test/browser/test.js", "test:node": "npm run unit-test:node && codecov", "test:browser": "npm run build && npm run unit-test:browser", From 588c914893bfd22f56ec67a30e246facbd741349 Mon Sep 17 00:00:00 2001 From: Daniel Lando Date: Tue, 19 Sep 2023 17:15:31 +0200 Subject: [PATCH 20/26] fix: switch to spec --- package.json | 2 +- test/runTests.ts | 9 ++++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index c49179d1d..10d895b5c 100644 --- a/package.json +++ b/package.json @@ -56,7 +56,7 @@ "build:browser": "rimraf dist/ && mkdirp dist/ && browserify build/mqtt.js --standalone mqtt > dist/mqtt.js && terser dist/mqtt.js --compress --mangle --output dist/mqtt.min.js", "build": "npm run build:ts && npm run build:browser", "prepare": "npm run build", - "unit-test:node": "node_modules/.bin/nyc --reporter=lcov --reporter=text node -r esbuild-register --test test/*.ts", + "unit-test:node": "node_modules/.bin/nyc --reporter=lcov --reporter=text node -r esbuild-register test/runTests.ts", "unit-test:browser": "airtap --server test/browser/server.js test/browser/test.js", "test:node": "npm run unit-test:node && codecov", "test:browser": "npm run build && npm run unit-test:browser", diff --git a/test/runTests.ts b/test/runTests.ts index 055c68e7c..34a5be446 100644 --- a/test/runTests.ts +++ b/test/runTests.ts @@ -1,13 +1,16 @@ import { readdirSync } from 'node:fs' import { run } from 'node:test' import process from 'node:process' -import { tap } from 'node:test/reporters' +import { spec as Spec } from 'node:test/reporters' import { basename } from 'node:path' +import { cpus } from 'node:os' + +const spec = new Spec() const files = readdirSync(__dirname) .filter((f) => f.endsWith('.ts') && f !== basename(__filename)) .map((f) => `${__dirname}/${f}`) -run({ files, timeout: 60 * 1000, concurrency: true }) - .compose(tap) +run({ files, timeout: 60 * 1000, concurrency: cpus().length }) + .compose(spec) .pipe(process.stdout) From bd471779213636a4383dd58fa9e86843360bf606 Mon Sep 17 00:00:00 2001 From: Daniel Lando Date: Tue, 19 Sep 2023 17:57:41 +0200 Subject: [PATCH 21/26] fix: exit code on error --- test/runTests.ts | 33 ++++++++++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/test/runTests.ts b/test/runTests.ts index 34a5be446..6571aedef 100644 --- a/test/runTests.ts +++ b/test/runTests.ts @@ -7,10 +7,37 @@ import { cpus } from 'node:os' const spec = new Spec() +let exitCode = 0 + const files = readdirSync(__dirname) .filter((f) => f.endsWith('.ts') && f !== basename(__filename)) .map((f) => `${__dirname}/${f}`) -run({ files, timeout: 60 * 1000, concurrency: cpus().length }) - .compose(spec) - .pipe(process.stdout) +const testStream = run({ + files, + timeout: 60 * 1000, + concurrency: cpus().length, +}) + +testStream.compose(spec).pipe(process.stdout) + +const summary: string[] = [] + +testStream.once('test:fail', (data) => { + exitCode = 1 + summary.push(`${data.file} - Test ${data.name} failed:\n${data.details} `) +}) + +testStream.once('test:stderr', (data) => { + exitCode = 1 + summary.push(`${data.file} - Error:\n${data.message} `) +}) + +testStream.once('end', () => { + if (summary.length > 0) { + console.error('--- ERRORS SUMMARY ---\n') + console.error(summary.join('\n')) + console.error('\n--- END OF SUMMARY ---') + } + process.exit(exitCode) +}) From e2086b5e7f50c93d8512793d4ae3497bb6158a01 Mon Sep 17 00:00:00 2001 From: Daniel Lando Date: Tue, 19 Sep 2023 18:05:45 +0200 Subject: [PATCH 22/26] fix: better summary --- test/runTests.ts | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/test/runTests.ts b/test/runTests.ts index 6571aedef..69bc7840c 100644 --- a/test/runTests.ts +++ b/test/runTests.ts @@ -25,7 +25,11 @@ const summary: string[] = [] testStream.once('test:fail', (data) => { exitCode = 1 - summary.push(`${data.file} - Test ${data.name} failed:\n${data.details} `) + summary.push( + `✖ ${data.file} - Test ${data.name} failed in ${Math.round( + data.details.duration_ms, + )}ms:\n${data.details.error} `, + ) }) testStream.once('test:stderr', (data) => { @@ -36,8 +40,8 @@ testStream.once('test:stderr', (data) => { testStream.once('end', () => { if (summary.length > 0) { console.error('--- ERRORS SUMMARY ---\n') - console.error(summary.join('\n')) - console.error('\n--- END OF SUMMARY ---') + console.error('\x1b[31m%s\x1b[0m', summary.join('\n'), '\x1b[0m\n') + console.error('--- END OF SUMMARY ---') } process.exit(exitCode) }) From d2341170a6741c0053054176563f8d305f63f5c3 Mon Sep 17 00:00:00 2001 From: Daniel Lando Date: Tue, 19 Sep 2023 18:09:12 +0200 Subject: [PATCH 23/26] fix: only consider fail test for exit code 1 --- package-lock.json | 28 +++++++++++++++++++++------- test/runTests.ts | 1 - 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index 85d6c0c62..7078d0fbd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3753,10 +3753,24 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001312", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001312.tgz", - "integrity": "sha512-Wiz1Psk2MEK0pX3rUzWaunLTZzqS2JYZFzNKqAiJGiuxIjRPLgV6+VDPOg6lQOUxmDwhTlh198JsTTi8Hzw6aQ==", - "dev": true + "version": "1.0.30001538", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001538.tgz", + "integrity": "sha512-HWJnhnID+0YMtGlzcp3T9drmBJUVDchPJ08tpUGFLs9CYlwWPH2uLgpHn8fND5pCgXVtnGS3H4QR9XLMHVNkHw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ] }, "node_modules/catering": { "version": "2.1.1", @@ -18724,9 +18738,9 @@ } }, "caniuse-lite": { - "version": "1.0.30001312", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001312.tgz", - "integrity": "sha512-Wiz1Psk2MEK0pX3rUzWaunLTZzqS2JYZFzNKqAiJGiuxIjRPLgV6+VDPOg6lQOUxmDwhTlh198JsTTi8Hzw6aQ==", + "version": "1.0.30001538", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001538.tgz", + "integrity": "sha512-HWJnhnID+0YMtGlzcp3T9drmBJUVDchPJ08tpUGFLs9CYlwWPH2uLgpHn8fND5pCgXVtnGS3H4QR9XLMHVNkHw==", "dev": true }, "catering": { diff --git a/test/runTests.ts b/test/runTests.ts index 69bc7840c..8119d3c79 100644 --- a/test/runTests.ts +++ b/test/runTests.ts @@ -33,7 +33,6 @@ testStream.once('test:fail', (data) => { }) testStream.once('test:stderr', (data) => { - exitCode = 1 summary.push(`${data.file} - Error:\n${data.message} `) }) From ac86684ad6465bfc85e04958d23b53af912c9589 Mon Sep 17 00:00:00 2001 From: Daniel Lando Date: Tue, 19 Sep 2023 18:12:26 +0200 Subject: [PATCH 24/26] fix: use `on` instead of `once` --- test/runTests.ts | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/test/runTests.ts b/test/runTests.ts index 8119d3c79..4eabed2f9 100644 --- a/test/runTests.ts +++ b/test/runTests.ts @@ -23,16 +23,17 @@ testStream.compose(spec).pipe(process.stdout) const summary: string[] = [] -testStream.once('test:fail', (data) => { +testStream.on('test:fail', (data) => { exitCode = 1 + const error = data.details.error summary.push( - `✖ ${data.file} - Test ${data.name} failed in ${Math.round( + `✖ ${data.file} - Test "${data.name}" failed in ${Math.round( data.details.duration_ms, - )}ms:\n${data.details.error} `, + )}ms: ${error.message}\n${error.stack} `, ) }) -testStream.once('test:stderr', (data) => { +testStream.on('test:stderr', (data) => { summary.push(`${data.file} - Error:\n${data.message} `) }) From a83d616886841875b54c964e56d9f8204cd3e437 Mon Sep 17 00:00:00 2001 From: Daniel Lando Date: Wed, 20 Sep 2023 08:58:29 +0200 Subject: [PATCH 25/26] fix: pretty print errors and duration --- test/runTests.ts | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/test/runTests.ts b/test/runTests.ts index 4eabed2f9..237376ab6 100644 --- a/test/runTests.ts +++ b/test/runTests.ts @@ -13,6 +13,8 @@ const files = readdirSync(__dirname) .filter((f) => f.endsWith('.ts') && f !== basename(__filename)) .map((f) => `${__dirname}/${f}`) +const start = Date.now() + const testStream = run({ files, timeout: 60 * 1000, @@ -26,10 +28,11 @@ const summary: string[] = [] testStream.on('test:fail', (data) => { exitCode = 1 const error = data.details.error + summary.push( - `✖ ${data.file} - Test "${data.name}" failed in ${Math.round( + `${data.file} - "${data.name}" (${Math.round( data.details.duration_ms, - )}ms: ${error.message}\n${error.stack} `, + )}ms)\n${error.toString()} `, ) }) @@ -38,10 +41,17 @@ testStream.on('test:stderr', (data) => { }) testStream.once('end', () => { + const duration = Date.now() - start + // print duration in blue + console.log( + '\x1b[34m%s\x1b[0m', + `ℹ Duration: ${duration / 1000}s`, + '\x1b[0m', + ) if (summary.length > 0) { - console.error('--- ERRORS SUMMARY ---\n') - console.error('\x1b[31m%s\x1b[0m', summary.join('\n'), '\x1b[0m\n') - console.error('--- END OF SUMMARY ---') + console.error('\x1b[31m%s\x1b', '\n✖ failing tests:\n') + console.error(summary.join('\n')) + console.error('\n------', '\x1b[0m\n') } process.exit(exitCode) }) From cf882c386ea9543882b5f42152208cac3c8a8e8e Mon Sep 17 00:00:00 2001 From: Daniel Lando Date: Wed, 20 Sep 2023 09:03:26 +0200 Subject: [PATCH 26/26] fix: spacing --- test/runTests.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/runTests.ts b/test/runTests.ts index 237376ab6..57c5663b6 100644 --- a/test/runTests.ts +++ b/test/runTests.ts @@ -45,7 +45,7 @@ testStream.once('end', () => { // print duration in blue console.log( '\x1b[34m%s\x1b[0m', - `ℹ Duration: ${duration / 1000}s`, + `\nℹ Duration: ${duration / 1000}s\n`, '\x1b[0m', ) if (summary.length > 0) {