Compare commits

..

1 Commits

Author SHA1 Message Date
dependabot[bot]
31f050d693 Bump path-to-regexp and express in /frontend
Bumps [path-to-regexp](https://github.com/pillarjs/path-to-regexp) and [express](https://github.com/expressjs/express). These dependencies needed to be updated together.

Updates `path-to-regexp` from 0.1.7 to 0.1.12
- [Release notes](https://github.com/pillarjs/path-to-regexp/releases)
- [Changelog](https://github.com/pillarjs/path-to-regexp/blob/master/History.md)
- [Commits](https://github.com/pillarjs/path-to-regexp/compare/v0.1.7...v0.1.12)

Updates `express` from 4.17.1 to 4.21.2
- [Release notes](https://github.com/expressjs/express/releases)
- [Changelog](https://github.com/expressjs/express/blob/4.21.2/History.md)
- [Commits](https://github.com/expressjs/express/compare/4.17.1...4.21.2)

---
updated-dependencies:
- dependency-name: path-to-regexp
  dependency-type: indirect
- dependency-name: express
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-08 20:21:05 +00:00
16 changed files with 579 additions and 1416 deletions

3
.gitignore vendored
View File

@@ -5,5 +5,4 @@
.project
.factorypath
.settings/
.vscode
htmlReport/
.vscode

View File

@@ -3577,6 +3577,11 @@
}
}
},
"base16": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/base16/-/base16-1.0.0.tgz",
"integrity": "sha512-pNdYkNPiJUnEhnfXV56+sQy8+AaPcG3POZAUnwr4EeqCUZFz4u2PePbo3e5Gj4ziYPCWGUZT9RHisvJKnwFuBQ=="
},
"base64-js": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
@@ -4474,6 +4479,14 @@
"sha.js": "2.4.11"
}
},
"cross-fetch": {
"version": "3.1.8",
"resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.8.tgz",
"integrity": "sha512-cvA+JwZoU0Xq+h6WkMvAUqPEYy92Obet6UdKLfW60qn99ftItKjB5T+BkyWOFWe2pUyfQ+IJHmpOTznqk1M6Kg==",
"requires": {
"node-fetch": "^2.6.12"
}
},
"cross-spawn": {
"version": "6.0.5",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz",
@@ -6242,42 +6255,42 @@
"resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz",
"integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==",
"requires": {
"accepts": "1.3.7",
"accepts": "~1.3.7",
"array-flatten": "1.1.1",
"body-parser": "1.19.0",
"content-disposition": "0.5.3",
"content-type": "1.0.4",
"content-type": "~1.0.4",
"cookie": "0.4.0",
"cookie-signature": "1.0.6",
"debug": "2.6.9",
"depd": "1.1.2",
"encodeurl": "1.0.2",
"escape-html": "1.0.3",
"etag": "1.8.1",
"finalhandler": "1.1.2",
"depd": "~1.1.2",
"encodeurl": "~1.0.2",
"escape-html": "~1.0.3",
"etag": "~1.8.1",
"finalhandler": "~1.1.2",
"fresh": "0.5.2",
"merge-descriptors": "1.0.1",
"methods": "1.1.2",
"on-finished": "2.3.0",
"parseurl": "1.3.3",
"methods": "~1.1.2",
"on-finished": "~2.3.0",
"parseurl": "~1.3.3",
"path-to-regexp": "0.1.7",
"proxy-addr": "2.0.7",
"proxy-addr": "~2.0.5",
"qs": "6.7.0",
"range-parser": "1.2.1",
"range-parser": "~1.2.1",
"safe-buffer": "5.1.2",
"send": "0.17.1",
"serve-static": "1.14.1",
"setprototypeof": "1.1.1",
"statuses": "1.5.0",
"type-is": "1.6.18",
"statuses": "~1.5.0",
"type-is": "~1.6.18",
"utils-merge": "1.0.1",
"vary": "1.1.2"
"vary": "~1.1.2"
},
"dependencies": {
"array-flatten": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
"integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI="
"integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg=="
},
"debug": {
"version": "2.6.9",
@@ -6290,7 +6303,7 @@
"ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
}
}
},
@@ -6438,6 +6451,43 @@
"bser": "2.1.1"
}
},
"fbemitter": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/fbemitter/-/fbemitter-3.0.0.tgz",
"integrity": "sha512-KWKaceCwKQU0+HPoop6gn4eOHk50bBv/VxjJtGMfwmJt3D29JpN4H4eisCtIPA+a8GVBam+ldMMpMjJUvpDyHw==",
"requires": {
"fbjs": "^3.0.0"
}
},
"fbjs": {
"version": "3.0.5",
"resolved": "https://registry.npmjs.org/fbjs/-/fbjs-3.0.5.tgz",
"integrity": "sha512-ztsSx77JBtkuMrEypfhgc3cI0+0h+svqeie7xHbh1k/IKdcydnvadp/mUaGgjAOXQmQSxsqgaRhS3q9fy+1kxg==",
"requires": {
"cross-fetch": "^3.1.5",
"fbjs-css-vars": "^1.0.0",
"loose-envify": "^1.0.0",
"object-assign": "^4.1.0",
"promise": "^7.1.1",
"setimmediate": "^1.0.5",
"ua-parser-js": "^1.0.35"
},
"dependencies": {
"promise": {
"version": "7.3.1",
"resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz",
"integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==",
"requires": {
"asap": "~2.0.3"
}
}
}
},
"fbjs-css-vars": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/fbjs-css-vars/-/fbjs-css-vars-1.0.2.tgz",
"integrity": "sha512-b2XGFAFdWZWg0phtAWLHCk836A1Xann+I+Dgd3Gk64MHKZO44FfoD1KxyvbSh0qZsIoXQGGlVztIY+oitJPpRQ=="
},
"figgy-pudding": {
"version": "3.5.2",
"resolved": "https://registry.npmjs.org/figgy-pudding/-/figgy-pudding-3.5.2.tgz",
@@ -6567,6 +6617,15 @@
"readable-stream": "2.3.7"
}
},
"flux": {
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/flux/-/flux-4.0.4.tgz",
"integrity": "sha512-NCj3XlayA2UsapRpM7va6wU1+9rE5FIL7qoMcmxWHRzbp0yujihMBm9BBHZ1MDIk5h5o2Bl6eGiCe8rYELAmYw==",
"requires": {
"fbemitter": "^3.0.0",
"fbjs": "^3.0.1"
}
},
"follow-redirects": {
"version": "1.14.2",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.2.tgz",
@@ -9787,11 +9846,21 @@
"resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz",
"integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8="
},
"lodash.curry": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/lodash.curry/-/lodash.curry-4.1.1.tgz",
"integrity": "sha512-/u14pXGviLaweY5JI0IUzgzF2J6Ne8INyzAZjImcryjgkZ+ebruBxy2/JaOOkTqScddcYtakjhSaeemV8lR0tA=="
},
"lodash.debounce": {
"version": "4.0.8",
"resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz",
"integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168="
},
"lodash.flow": {
"version": "3.5.0",
"resolved": "https://registry.npmjs.org/lodash.flow/-/lodash.flow-3.5.0.tgz",
"integrity": "sha512-ff3BX/tSioo+XojX4MOsOMhJw0nZoUEF011LX8g8d3gvjVbxd89cCio4BCXronjxcTUIJUoqKEUA+n4CqvvRPw=="
},
"lodash.memoize": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz",
@@ -10291,6 +10360,35 @@
}
}
},
"node-fetch": {
"version": "2.7.0",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz",
"integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==",
"requires": {
"whatwg-url": "^5.0.0"
},
"dependencies": {
"tr46": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
},
"webidl-conversions": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
"integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="
},
"whatwg-url": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
"integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
"requires": {
"tr46": "~0.0.3",
"webidl-conversions": "^3.0.0"
}
}
}
},
"node-forge": {
"version": "0.10.0",
"resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.10.0.tgz",
@@ -12209,6 +12307,11 @@
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
"integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A=="
},
"pure-color": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/pure-color/-/pure-color-1.3.0.tgz",
"integrity": "sha512-QFADYnsVoBMw1srW7OVKEYjG+MbIa49s54w1MA1EDY6r2r/sTcKKYqRX1f4GYvnXP7eN/Pe9HFcX+hwzmrXRHA=="
},
"q": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz",
@@ -12318,6 +12421,17 @@
"whatwg-fetch": "3.6.2"
}
},
"react-base16-styling": {
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/react-base16-styling/-/react-base16-styling-0.6.0.tgz",
"integrity": "sha512-yvh/7CArceR/jNATXOKDlvTnPKPmGZz7zsenQ3jUwLzHkNUR0CvY3yGYJbWJ/nnxsL8Sgmt5cO3/SILVuPO6TQ==",
"requires": {
"base16": "^1.0.0",
"lodash.curry": "^4.0.1",
"lodash.flow": "^3.3.0",
"pure-color": "^1.2.0"
}
},
"react-dev-utils": {
"version": "11.0.4",
"resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-11.0.4.tgz",
@@ -12535,6 +12649,22 @@
"resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
"integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w=="
},
"react-json-view": {
"version": "1.21.3",
"resolved": "https://registry.npmjs.org/react-json-view/-/react-json-view-1.21.3.tgz",
"integrity": "sha512-13p8IREj9/x/Ye4WI/JpjhoIwuzEgUAtgJZNBJckfzJt1qyh24BdTm6UQNGnyTq9dapQdrqvquZTo3dz1X6Cjw==",
"requires": {
"flux": "^4.0.1",
"react-base16-styling": "^0.6.0",
"react-lifecycles-compat": "^3.0.4",
"react-textarea-autosize": "^8.3.2"
}
},
"react-lifecycles-compat": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz",
"integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA=="
},
"react-refresh": {
"version": "0.8.3",
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.8.3.tgz",
@@ -12606,6 +12736,31 @@
"workbox-webpack-plugin": "5.1.4"
}
},
"react-textarea-autosize": {
"version": "8.5.5",
"resolved": "https://registry.npmjs.org/react-textarea-autosize/-/react-textarea-autosize-8.5.5.tgz",
"integrity": "sha512-CVA94zmfp8m4bSHtWwmANaBR8EPsKy2aZ7KwqhoS4Ftib87F9Kvi7XQhOixypPLMc6kVYgOXvKFuuzZDpHGRPg==",
"requires": {
"@babel/runtime": "^7.20.13",
"use-composed-ref": "^1.3.0",
"use-latest": "^1.2.1"
},
"dependencies": {
"@babel/runtime": {
"version": "7.26.0",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.26.0.tgz",
"integrity": "sha512-FDSOghenHTiToteC/QRlv2q3DhPZ/oOXTBoirfWNx1Cx3TMVcGWQtMMmQcSvb/JjpNeGzx8Pq/b4fKEJuWm1sw==",
"requires": {
"regenerator-runtime": "^0.14.0"
}
},
"regenerator-runtime": {
"version": "0.14.1",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz",
"integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw=="
}
}
},
"read-pkg": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz",
@@ -14709,6 +14864,11 @@
"is-typedarray": "1.0.0"
}
},
"ua-parser-js": {
"version": "1.0.39",
"resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.39.tgz",
"integrity": "sha512-k24RCVWlEcjkdOxYmVJgeD/0a1TiSpqLg+ZalVGV9lsnr4yqu0w7tX/x2xX6G4zpkgQnRf89lxuZ1wsbjXM8lw=="
},
"unbox-primitive": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz",
@@ -14915,6 +15075,24 @@
"resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz",
"integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ=="
},
"use-composed-ref": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/use-composed-ref/-/use-composed-ref-1.3.0.tgz",
"integrity": "sha512-GLMG0Jc/jiKov/3Ulid1wbv3r54K9HlMW29IWcDFPEqFkSO2nS0MuefWgMJpeHQ9YJeXDL3ZUF+P3jdXlZX/cQ=="
},
"use-isomorphic-layout-effect": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.2.0.tgz",
"integrity": "sha512-q6ayo8DWoPZT0VdG4u3D3uxcgONP3Mevx2i2b0434cwWBoL+aelL1DzkXI6w3PhTZzUeR2kaVlZn70iCiseP6w=="
},
"use-latest": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/use-latest/-/use-latest-1.2.1.tgz",
"integrity": "sha512-xA+AVm/Wlg3e2P/JiItTziwS7FK92LWrDB0p+hgXloIMuVCeJJ8v6f0eeHyPZaJrM+usM1FkFfbNCrJGs8A/zw==",
"requires": {
"use-isomorphic-layout-effect": "^1.1.1"
}
},
"util": {
"version": "0.11.1",
"resolved": "https://registry.npmjs.org/util/-/util-0.11.1.tgz",
@@ -15083,6 +15261,7 @@
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz",
"integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==",
"optional": true,
"requires": {
"arr-flatten": "1.1.0",
"array-unique": "0.3.2",
@@ -15100,6 +15279,7 @@
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
"integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
"optional": true,
"requires": {
"is-extendable": "0.1.1"
}
@@ -15130,6 +15310,7 @@
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz",
"integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=",
"optional": true,
"requires": {
"extend-shallow": "2.0.1",
"is-number": "3.0.0",
@@ -15141,6 +15322,7 @@
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
"integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
"optional": true,
"requires": {
"is-extendable": "0.1.1"
}
@@ -15191,6 +15373,7 @@
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
"integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=",
"optional": true,
"requires": {
"kind-of": "3.2.2"
},
@@ -15199,6 +15382,7 @@
"version": "3.2.2",
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
"integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
"optional": true,
"requires": {
"is-buffer": "1.1.6"
}
@@ -15209,6 +15393,7 @@
"version": "3.1.10",
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz",
"integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==",
"optional": true,
"requires": {
"arr-diff": "4.0.0",
"array-unique": "0.3.2",
@@ -15240,6 +15425,7 @@
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz",
"integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=",
"optional": true,
"requires": {
"is-number": "3.0.0",
"repeat-string": "1.6.1"

View File

@@ -2136,7 +2136,7 @@ abab@^2.0.3:
resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.5.tgz#c0b678fb32d60fc1219c784d6a826fe385aeb79a"
integrity sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q==
accepts@~1.3.4, accepts@~1.3.5, accepts@~1.3.7:
accepts@~1.3.4, accepts@~1.3.5:
version "1.3.7"
resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd"
integrity sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==
@@ -2144,6 +2144,14 @@ accepts@~1.3.4, accepts@~1.3.5, accepts@~1.3.7:
mime-types "~2.1.24"
negotiator "0.6.2"
accepts@~1.3.8:
version "1.3.8"
resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e"
integrity sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==
dependencies:
mime-types "~2.1.34"
negotiator "0.6.3"
acorn-globals@^6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-6.0.0.tgz#46cdd39f0f8ff08a876619b55f5ac8a6dc770b45"
@@ -2773,21 +2781,23 @@ bn.js@^5.0.0, bn.js@^5.1.1:
resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.1.3.tgz#beca005408f642ebebea80b042b4d18d2ac0ee6b"
integrity sha512-GkTiFpjFtUzU9CbMeJ5iazkCzGL3jrhzerzZIuqLABjbwRaFt33I9tUdSNryIptM+RxDet6OKm2WnLXzW51KsQ==
body-parser@1.19.0:
version "1.19.0"
resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.0.tgz#96b2709e57c9c4e09a6fd66a8fd979844f69f08a"
integrity sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==
body-parser@1.20.3:
version "1.20.3"
resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.3.tgz#1953431221c6fb5cd63c4b36d53fab0928e548c6"
integrity sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==
dependencies:
bytes "3.1.0"
content-type "~1.0.4"
bytes "3.1.2"
content-type "~1.0.5"
debug "2.6.9"
depd "~1.1.2"
http-errors "1.7.2"
depd "2.0.0"
destroy "1.2.0"
http-errors "2.0.0"
iconv-lite "0.4.24"
on-finished "~2.3.0"
qs "6.7.0"
raw-body "2.4.0"
type-is "~1.6.17"
on-finished "2.4.1"
qs "6.13.0"
raw-body "2.5.2"
type-is "~1.6.18"
unpipe "1.0.0"
bonjour@^3.5.0:
version "3.5.0"
@@ -2975,10 +2985,10 @@ bytes@3.0.0:
resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048"
integrity sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=
bytes@3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6"
integrity sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==
bytes@3.1.2:
version "3.1.2"
resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5"
integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==
cacache@^12.0.2:
version "12.0.4"
@@ -3039,6 +3049,14 @@ cache-base@^1.0.1:
union-value "^1.0.0"
unset-value "^1.0.0"
call-bind-apply-helpers@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.0.tgz#33127b42608972f76812a501d69db5d8ce404979"
integrity sha512-CCKAP2tkPau7D3GE8+V8R6sQubA9R5foIzGp+85EXCVSCivuxBNAWqcpn72PKYiIcqoViv/kcUDpaEIMBVi1lQ==
dependencies:
es-errors "^1.3.0"
function-bind "^1.1.2"
call-bind@^1.0.0, call-bind@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c"
@@ -3047,6 +3065,16 @@ call-bind@^1.0.0, call-bind@^1.0.2:
function-bind "^1.1.1"
get-intrinsic "^1.0.2"
call-bind@^1.0.7:
version "1.0.8"
resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.8.tgz#0736a9660f537e3388826f440d5ec45f744eaa4c"
integrity sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==
dependencies:
call-bind-apply-helpers "^1.0.0"
es-define-property "^1.0.0"
get-intrinsic "^1.2.4"
set-function-length "^1.2.2"
caller-callsite@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/caller-callsite/-/caller-callsite-2.0.0.tgz#847e0fce0a223750a9a027c54b33731ad3154134"
@@ -3444,18 +3472,23 @@ contains-path@^0.1.0:
resolved "https://registry.yarnpkg.com/contains-path/-/contains-path-0.1.0.tgz#fe8cf184ff6670b6baef01a9d4861a5cbec4120a"
integrity sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo=
content-disposition@0.5.3:
version "0.5.3"
resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.3.tgz#e130caf7e7279087c5616c2007d0485698984fbd"
integrity sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==
content-disposition@0.5.4:
version "0.5.4"
resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.4.tgz#8b82b4efac82512a02bb0b1dcec9d2c5e8eb5bfe"
integrity sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==
dependencies:
safe-buffer "5.1.2"
safe-buffer "5.2.1"
content-type@~1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b"
integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==
content-type@~1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.5.tgz#8b773162656d1d1086784c8f23a54ce6d73d7918"
integrity sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==
convert-source-map@1.7.0, convert-source-map@^1.4.0, convert-source-map@^1.6.0, convert-source-map@^1.7.0:
version "1.7.0"
resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.7.0.tgz#17a2cb882d7f77d3490585e2ce6c524424a3a442"
@@ -3473,10 +3506,10 @@ cookie-signature@1.0.6:
resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c"
integrity sha1-4wOogrNCzD7oylE6eZmXNNqzriw=
cookie@0.4.0:
version "0.4.0"
resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.0.tgz#beb437e7022b3b6d49019d088665303ebe9c14ba"
integrity sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==
cookie@0.7.1:
version "0.7.1"
resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.7.1.tgz#2f73c42142d5d5cf71310a74fc4ae61670e5dbc9"
integrity sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==
copy-concurrently@^1.0.0:
version "1.0.5"
@@ -3960,6 +3993,15 @@ default-gateway@^4.2.0:
execa "^1.0.0"
ip-regex "^2.1.0"
define-data-property@^1.1.4:
version "1.1.4"
resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.4.tgz#894dc141bb7d3060ae4366f6a0107e68fbe48c5e"
integrity sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==
dependencies:
es-define-property "^1.0.0"
es-errors "^1.3.0"
gopd "^1.0.1"
define-properties@^1.1.2, define-properties@^1.1.3:
version "1.1.3"
resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1"
@@ -4007,6 +4049,11 @@ delayed-stream@~1.0.0:
resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk=
depd@2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df"
integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==
depd@~1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9"
@@ -4020,10 +4067,10 @@ des.js@^1.0.0:
inherits "^2.0.1"
minimalistic-assert "^1.0.0"
destroy@~1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80"
integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=
destroy@1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.2.0.tgz#4803735509ad8be552934c67df614f94e66fa015"
integrity sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==
detect-newline@^3.0.0:
version "3.1.0"
@@ -4193,6 +4240,15 @@ dotenv@8.2.0:
resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-8.2.0.tgz#97e619259ada750eea3e4ea3e26bceea5424b16a"
integrity sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw==
dunder-proto@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/dunder-proto/-/dunder-proto-1.0.0.tgz#c2fce098b3c8f8899554905f4377b6d85dabaa80"
integrity sha512-9+Sj30DIu+4KvHqMfLUGLFYL2PkURSYMVXJyXe92nFRvlYq5hBjLEhblKB+vkd/WVlUYMWigiY07T91Fkk0+4A==
dependencies:
call-bind-apply-helpers "^1.0.0"
es-errors "^1.3.0"
gopd "^1.2.0"
duplexer@^0.1.1:
version "0.1.2"
resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.2.tgz#3abe43aef3835f8ae077d136ddce0f276b0400e6"
@@ -4279,6 +4335,11 @@ encodeurl@~1.0.2:
resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59"
integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=
encodeurl@~2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-2.0.0.tgz#7b8ea898077d7e409d3ac45474ea38eaf0857a58"
integrity sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==
end-of-stream@^1.0.0, end-of-stream@^1.1.0:
version "1.4.4"
resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0"
@@ -4370,6 +4431,16 @@ es-abstract@^1.18.0-next.1, es-abstract@^1.18.0-next.2:
string.prototype.trimend "^1.0.3"
string.prototype.trimstart "^1.0.3"
es-define-property@^1.0.0, es-define-property@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.1.tgz#983eb2f9a6724e9303f61addf011c72e09e0b0fa"
integrity sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==
es-errors@^1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f"
integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==
es-to-primitive@^1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a"
@@ -4774,37 +4845,38 @@ expect@^26.6.0, expect@^26.6.2:
jest-regex-util "^26.0.0"
express@^4.17.1:
version "4.17.1"
resolved "https://registry.yarnpkg.com/express/-/express-4.17.1.tgz#4491fc38605cf51f8629d39c2b5d026f98a4c134"
integrity sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==
version "4.21.2"
resolved "https://registry.yarnpkg.com/express/-/express-4.21.2.tgz#cf250e48362174ead6cea4a566abef0162c1ec32"
integrity sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==
dependencies:
accepts "~1.3.7"
accepts "~1.3.8"
array-flatten "1.1.1"
body-parser "1.19.0"
content-disposition "0.5.3"
body-parser "1.20.3"
content-disposition "0.5.4"
content-type "~1.0.4"
cookie "0.4.0"
cookie "0.7.1"
cookie-signature "1.0.6"
debug "2.6.9"
depd "~1.1.2"
encodeurl "~1.0.2"
depd "2.0.0"
encodeurl "~2.0.0"
escape-html "~1.0.3"
etag "~1.8.1"
finalhandler "~1.1.2"
finalhandler "1.3.1"
fresh "0.5.2"
merge-descriptors "1.0.1"
http-errors "2.0.0"
merge-descriptors "1.0.3"
methods "~1.1.2"
on-finished "~2.3.0"
on-finished "2.4.1"
parseurl "~1.3.3"
path-to-regexp "0.1.7"
proxy-addr "~2.0.5"
qs "6.7.0"
path-to-regexp "0.1.12"
proxy-addr "~2.0.7"
qs "6.13.0"
range-parser "~1.2.1"
safe-buffer "5.1.2"
send "0.17.1"
serve-static "1.14.1"
setprototypeof "1.1.1"
statuses "~1.5.0"
safe-buffer "5.2.1"
send "0.19.0"
serve-static "1.16.2"
setprototypeof "1.2.0"
statuses "2.0.1"
type-is "~1.6.18"
utils-merge "1.0.1"
vary "~1.1.2"
@@ -4980,17 +5052,17 @@ fill-range@^7.0.1:
dependencies:
to-regex-range "^5.0.1"
finalhandler@~1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.2.tgz#b7e7d000ffd11938d0fdb053506f6ebabe9f587d"
integrity sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==
finalhandler@1.3.1:
version "1.3.1"
resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.3.1.tgz#0c575f1d1d324ddd1da35ad7ece3df7d19088019"
integrity sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==
dependencies:
debug "2.6.9"
encodeurl "~1.0.2"
encodeurl "~2.0.0"
escape-html "~1.0.3"
on-finished "~2.3.0"
on-finished "2.4.1"
parseurl "~1.3.3"
statuses "~1.5.0"
statuses "2.0.1"
unpipe "~1.0.0"
find-cache-dir@^2.1.0:
@@ -5104,10 +5176,10 @@ form-data@~2.3.2:
combined-stream "^1.0.6"
mime-types "^2.1.12"
forwarded@~0.1.2:
version "0.1.2"
resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84"
integrity sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=
forwarded@0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811"
integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==
fragment-cache@^0.2.1:
version "0.2.1"
@@ -5197,6 +5269,11 @@ function-bind@^1.1.1:
resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==
function-bind@^1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c"
integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==
functional-red-black-tree@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327"
@@ -5221,6 +5298,20 @@ get-intrinsic@^1.0.2, get-intrinsic@^1.1.0, get-intrinsic@^1.1.1:
has "^1.0.3"
has-symbols "^1.0.1"
get-intrinsic@^1.2.4:
version "1.2.5"
resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.5.tgz#dfe7dd1b30761b464fe51bf4bb00ac7c37b681e7"
integrity sha512-Y4+pKa7XeRUPWFNvOOYHkRYrfzW07oraURSvjDmRVOJ748OrVmeXtpE4+GCEHncjCjkTxPNRt8kEbxDhsn6VTg==
dependencies:
call-bind-apply-helpers "^1.0.0"
dunder-proto "^1.0.0"
es-define-property "^1.0.1"
es-errors "^1.3.0"
function-bind "^1.1.2"
gopd "^1.2.0"
has-symbols "^1.1.0"
hasown "^2.0.2"
get-own-enumerable-property-symbols@^3.0.0:
version "3.0.2"
resolved "https://registry.yarnpkg.com/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz#b5fde77f22cbe35f390b4e089922c50bce6ef664"
@@ -5347,6 +5438,11 @@ globby@^6.1.0:
pify "^2.0.0"
pinkie-promise "^2.0.0"
gopd@^1.0.1, gopd@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.2.0.tgz#89f56b8217bdbc8802bd299df6d7f1081d7e51a1"
integrity sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==
graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.4:
version "4.2.6"
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.6.tgz#ff040b2b0853b23c3d31027523706f1885d76bee"
@@ -5398,11 +5494,23 @@ has-flag@^4.0.0:
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b"
integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==
has-property-descriptors@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz#963ed7d071dc7bf5f084c5bfbe0d1b6222586854"
integrity sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==
dependencies:
es-define-property "^1.0.0"
has-symbols@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.1.tgz#9f5214758a44196c406d9bd76cebf81ec2dd31e8"
integrity sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==
has-symbols@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.1.0.tgz#fc9c6a783a084951d0b971fe1018de813707a338"
integrity sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==
has-value@^0.3.1:
version "0.3.1"
resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f"
@@ -5458,6 +5566,13 @@ hash.js@^1.0.0, hash.js@^1.0.3:
inherits "^2.0.3"
minimalistic-assert "^1.0.1"
hasown@^2.0.2:
version "2.0.2"
resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003"
integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==
dependencies:
function-bind "^1.1.2"
he@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f"
@@ -5574,16 +5689,16 @@ http-deceiver@^1.2.7:
resolved "https://registry.yarnpkg.com/http-deceiver/-/http-deceiver-1.2.7.tgz#fa7168944ab9a519d337cb0bec7284dc3e723d87"
integrity sha1-+nFolEq5pRnTN8sL7HKE3D5yPYc=
http-errors@1.7.2:
version "1.7.2"
resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.2.tgz#4f5029cf13239f31036e5b2e55292bcfbcc85c8f"
integrity sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==
http-errors@2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-2.0.0.tgz#b7774a1486ef73cf7667ac9ae0858c012c57b9d3"
integrity sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==
dependencies:
depd "~1.1.2"
inherits "2.0.3"
setprototypeof "1.1.1"
statuses ">= 1.5.0 < 2"
toidentifier "1.0.0"
depd "2.0.0"
inherits "2.0.4"
setprototypeof "1.2.0"
statuses "2.0.1"
toidentifier "1.0.1"
http-errors@~1.6.2:
version "1.6.3"
@@ -5595,17 +5710,6 @@ http-errors@~1.6.2:
setprototypeof "1.1.0"
statuses ">= 1.4.0 < 2"
http-errors@~1.7.2:
version "1.7.3"
resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.3.tgz#6c619e4f9c60308c38519498c14fbb10aacebb06"
integrity sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw==
dependencies:
depd "~1.1.2"
inherits "2.0.4"
setprototypeof "1.1.1"
statuses ">= 1.5.0 < 2"
toidentifier "1.0.0"
http-parser-js@>=0.5.1:
version "0.5.3"
resolved "https://registry.yarnpkg.com/http-parser-js/-/http-parser-js-0.5.3.tgz#01d2709c79d41698bb01d4decc5e9da4e4a033d9"
@@ -7132,10 +7236,10 @@ memory-fs@^0.5.0:
errno "^0.1.3"
readable-stream "^2.0.1"
merge-descriptors@1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61"
integrity sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=
merge-descriptors@1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.3.tgz#d80319a65f3c7935351e5cfdac8f9318504dbed5"
integrity sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==
merge-stream@^2.0.0:
version "2.0.0"
@@ -7197,6 +7301,11 @@ mime-db@1.46.0, "mime-db@>= 1.43.0 < 2":
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.46.0.tgz#6267748a7f799594de3cbc8cde91def349661cee"
integrity sha512-svXaP8UQRZ5K7or+ZmfNhg2xX3yKDMUzqadsSqi4NCH/KomcH75MAMYAGVlvXn4+b/xOPhS3I2uHKRUzvjY7BQ==
mime-db@1.52.0:
version "1.52.0"
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70"
integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==
mime-types@^2.1.12, mime-types@^2.1.27, mime-types@~2.1.17, mime-types@~2.1.19, mime-types@~2.1.24:
version "2.1.29"
resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.29.tgz#1d4ab77da64b91f5f72489df29236563754bb1b2"
@@ -7204,6 +7313,13 @@ mime-types@^2.1.12, mime-types@^2.1.27, mime-types@~2.1.17, mime-types@~2.1.19,
dependencies:
mime-db "1.46.0"
mime-types@~2.1.34:
version "2.1.35"
resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a"
integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==
dependencies:
mime-db "1.52.0"
mime@1.6.0:
version "1.6.0"
resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1"
@@ -7345,17 +7461,12 @@ ms@2.0.0:
resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=
ms@2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a"
integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==
ms@2.1.2:
version "2.1.2"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
ms@^2.1.1:
ms@2.1.3, ms@^2.1.1:
version "2.1.3"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2"
integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==
@@ -7417,6 +7528,11 @@ negotiator@0.6.2:
resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb"
integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==
negotiator@0.6.3:
version "0.6.3"
resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd"
integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==
neo-async@^2.5.0, neo-async@^2.6.1, neo-async@^2.6.2:
version "2.6.2"
resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f"
@@ -7598,6 +7714,11 @@ object-copy@^0.1.0:
define-property "^0.2.5"
kind-of "^3.0.3"
object-inspect@^1.13.1:
version "1.13.3"
resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.3.tgz#f14c183de51130243d6d18ae149375ff50ea488a"
integrity sha512-kDCGIbxkDSXE3euJZZXzc6to7fCrKHNI/hSRQnRuQ+BWjFNzZwiFF8fj/6o2t2G9/jTj8PSIYTfCLelLZEeRpA==
object-inspect@^1.8.0, object-inspect@^1.9.0:
version "1.9.0"
resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.9.0.tgz#c90521d74e1127b67266ded3394ad6116986533a"
@@ -7684,10 +7805,10 @@ obuf@^1.0.0, obuf@^1.1.2:
resolved "https://registry.yarnpkg.com/obuf/-/obuf-1.1.2.tgz#09bea3343d41859ebd446292d11c9d4db619084e"
integrity sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==
on-finished@~2.3.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947"
integrity sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=
on-finished@2.4.1:
version "2.4.1"
resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.4.1.tgz#58c8c44116e54845ad57f14ab10b03533184ac3f"
integrity sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==
dependencies:
ee-first "1.1.1"
@@ -7983,10 +8104,10 @@ path-parse@^1.0.6:
resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c"
integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==
path-to-regexp@0.1.7:
version "0.1.7"
resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c"
integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=
path-to-regexp@0.1.12:
version "0.1.12"
resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.12.tgz#d5e1a12e478a976d432ef3c58d534b9923164bb7"
integrity sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==
path-type@^2.0.0:
version "2.0.0"
@@ -8869,12 +8990,12 @@ prop-types@^15.7.2:
object-assign "^4.1.1"
react-is "^16.8.1"
proxy-addr@~2.0.5:
version "2.0.6"
resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.6.tgz#fdc2336505447d3f2f2c638ed272caf614bbb2bf"
integrity sha512-dh/frvCBVmSsDYzw6n926jv974gddhkFPfiN8hPOi30Wax25QZyZEGveluCgliBnqmuM+UJmBErbAUFIoDbjOw==
proxy-addr@~2.0.7:
version "2.0.7"
resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025"
integrity sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==
dependencies:
forwarded "~0.1.2"
forwarded "0.2.0"
ipaddr.js "1.9.1"
prr@~1.0.1:
@@ -8949,10 +9070,12 @@ q@^1.1.2:
resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7"
integrity sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=
qs@6.7.0:
version "6.7.0"
resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc"
integrity sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==
qs@6.13.0:
version "6.13.0"
resolved "https://registry.yarnpkg.com/qs/-/qs-6.13.0.tgz#6ca3bd58439f7e245655798997787b0d88a51906"
integrity sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==
dependencies:
side-channel "^1.0.6"
qs@~6.5.2:
version "6.5.2"
@@ -9019,13 +9142,13 @@ range-parser@^1.2.1, range-parser@~1.2.1:
resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031"
integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==
raw-body@2.4.0:
version "2.4.0"
resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.4.0.tgz#a1ce6fb9c9bc356ca52e89256ab59059e13d0332"
integrity sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==
raw-body@2.5.2:
version "2.5.2"
resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.2.tgz#99febd83b90e08975087e8f1f9419a149366b68a"
integrity sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==
dependencies:
bytes "3.1.0"
http-errors "1.7.2"
bytes "3.1.2"
http-errors "2.0.0"
iconv-lite "0.4.24"
unpipe "1.0.0"
@@ -9654,7 +9777,7 @@ safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1:
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
safe-buffer@>=5.1.0, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@~5.2.0:
safe-buffer@5.2.1, safe-buffer@>=5.1.0, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@~5.2.0:
version "5.2.1"
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
@@ -9788,24 +9911,24 @@ semver@^7.2.1, semver@^7.3.2:
dependencies:
lru-cache "^6.0.0"
send@0.17.1:
version "0.17.1"
resolved "https://registry.yarnpkg.com/send/-/send-0.17.1.tgz#c1d8b059f7900f7466dd4938bdc44e11ddb376c8"
integrity sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==
send@0.19.0:
version "0.19.0"
resolved "https://registry.yarnpkg.com/send/-/send-0.19.0.tgz#bbc5a388c8ea6c048967049dbeac0e4a3f09d7f8"
integrity sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==
dependencies:
debug "2.6.9"
depd "~1.1.2"
destroy "~1.0.4"
depd "2.0.0"
destroy "1.2.0"
encodeurl "~1.0.2"
escape-html "~1.0.3"
etag "~1.8.1"
fresh "0.5.2"
http-errors "~1.7.2"
http-errors "2.0.0"
mime "1.6.0"
ms "2.1.1"
on-finished "~2.3.0"
ms "2.1.3"
on-finished "2.4.1"
range-parser "~1.2.1"
statuses "~1.5.0"
statuses "2.0.1"
serialize-javascript@^4.0.0:
version "4.0.0"
@@ -9834,21 +9957,33 @@ serve-index@^1.9.1:
mime-types "~2.1.17"
parseurl "~1.3.2"
serve-static@1.14.1:
version "1.14.1"
resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.14.1.tgz#666e636dc4f010f7ef29970a88a674320898b2f9"
integrity sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==
serve-static@1.16.2:
version "1.16.2"
resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.16.2.tgz#b6a5343da47f6bdd2673848bf45754941e803296"
integrity sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==
dependencies:
encodeurl "~1.0.2"
encodeurl "~2.0.0"
escape-html "~1.0.3"
parseurl "~1.3.3"
send "0.17.1"
send "0.19.0"
set-blocking@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7"
integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc=
set-function-length@^1.2.2:
version "1.2.2"
resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.2.2.tgz#aac72314198eaed975cf77b2c3b6b880695e5449"
integrity sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==
dependencies:
define-data-property "^1.1.4"
es-errors "^1.3.0"
function-bind "^1.1.2"
get-intrinsic "^1.2.4"
gopd "^1.0.1"
has-property-descriptors "^1.0.2"
set-value@^2.0.0, set-value@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.1.tgz#a18d40530e6f07de4228c7defe4227af8cad005b"
@@ -9869,10 +10004,10 @@ setprototypeof@1.1.0:
resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656"
integrity sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==
setprototypeof@1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.1.tgz#7e95acb24aa92f5885e0abef5ba131330d4ae683"
integrity sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==
setprototypeof@1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424"
integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==
sha.js@^2.4.0, sha.js@^2.4.8:
version "2.4.11"
@@ -9925,6 +10060,16 @@ side-channel@^1.0.4:
get-intrinsic "^1.0.2"
object-inspect "^1.9.0"
side-channel@^1.0.6:
version "1.0.6"
resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.6.tgz#abd25fb7cd24baf45466406b1096b7831c9215f2"
integrity sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==
dependencies:
call-bind "^1.0.7"
es-errors "^1.3.0"
get-intrinsic "^1.2.4"
object-inspect "^1.13.1"
signal-exit@^3.0.0, signal-exit@^3.0.2:
version "3.0.3"
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c"
@@ -10186,7 +10331,12 @@ static-extend@^0.1.1:
define-property "^0.2.5"
object-copy "^0.1.0"
"statuses@>= 1.4.0 < 2", "statuses@>= 1.5.0 < 2", statuses@~1.5.0:
statuses@2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63"
integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==
"statuses@>= 1.4.0 < 2":
version "1.5.0"
resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c"
integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=
@@ -10640,10 +10790,10 @@ to-regex@^3.0.1, to-regex@^3.0.2:
regex-not "^1.0.2"
safe-regex "^1.1.0"
toidentifier@1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553"
integrity sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==
toidentifier@1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35"
integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==
tough-cookie@^2.3.3, tough-cookie@~2.5.0:
version "2.5.0"
@@ -10767,7 +10917,7 @@ type-fest@^0.8.1:
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d"
integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==
type-is@~1.6.17, type-is@~1.6.18:
type-is@~1.6.18:
version "1.6.18"
resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131"
integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==

View File

@@ -37,7 +37,6 @@ import org.apache.rocketmq.common.Pair;
import org.apache.rocketmq.common.message.MessageClientIDSetter;
import org.apache.rocketmq.common.message.MessageExt;
import org.apache.rocketmq.common.message.MessageQueue;
import org.apache.rocketmq.dashboard.support.AutoCloseConsumerWrapper;
import org.apache.rocketmq.remoting.protocol.body.Connection;
import org.apache.rocketmq.remoting.protocol.body.ConsumeMessageDirectlyResult;
import org.apache.rocketmq.remoting.protocol.body.ConsumerConnection;
@@ -128,11 +127,11 @@ public class MessageServiceImpl implements MessageService {
if (isEnableAcl) {
rpcHook = new AclClientRPCHook(new SessionCredentials(configure.getAccessKey(), configure.getSecretKey()));
}
AutoCloseConsumerWrapper consumerWrapper = new AutoCloseConsumerWrapper();
DefaultMQPullConsumer consumer = consumerWrapper.getConsumer(rpcHook, configure.isUseTLS());
DefaultMQPullConsumer consumer = buildDefaultMQPullConsumer(rpcHook, configure.isUseTLS());
List<MessageView> messageViewList = Lists.newArrayList();
try {
String subExpression = "*";
consumer.start();
Set<MessageQueue> mqs = consumer.fetchSubscribeMessageQueues(topic);
for (MessageQueue mq : mqs) {
long minOffset = consumer.searchOffset(mq, begin);
@@ -189,6 +188,8 @@ public class MessageServiceImpl implements MessageService {
} catch (Exception e) {
Throwables.throwIfUnchecked(e);
throw new RuntimeException(e);
} finally {
consumer.shutdown();
}
}
@@ -262,8 +263,7 @@ public class MessageServiceImpl implements MessageService {
if (isEnableAcl) {
rpcHook = new AclClientRPCHook(new SessionCredentials(configure.getAccessKey(), configure.getSecretKey()));
}
AutoCloseConsumerWrapper consumerWrapper = new AutoCloseConsumerWrapper();
DefaultMQPullConsumer consumer = consumerWrapper.getConsumer(rpcHook, configure.isUseTLS());
DefaultMQPullConsumer consumer = buildDefaultMQPullConsumer(rpcHook, configure.isUseTLS());
long total = 0;
List<QueueOffsetInfo> queueOffsetInfos = new ArrayList<>();
@@ -271,6 +271,7 @@ public class MessageServiceImpl implements MessageService {
List<MessageView> messageViews = new ArrayList<>();
try {
consumer.start();
Collection<MessageQueue> messageQueues = consumer.fetchSubscribeMessageQueues(query.getTopic());
int idx = 0;
for (MessageQueue messageQueue : messageQueues) {
@@ -393,6 +394,8 @@ public class MessageServiceImpl implements MessageService {
} catch (Exception e) {
Throwables.throwIfUnchecked(e);
throw new RuntimeException(e);
} finally {
consumer.shutdown();
}
}
@@ -402,14 +405,14 @@ public class MessageServiceImpl implements MessageService {
if (isEnableAcl) {
rpcHook = new AclClientRPCHook(new SessionCredentials(configure.getAccessKey(), configure.getSecretKey()));
}
AutoCloseConsumerWrapper consumerWrapper = new AutoCloseConsumerWrapper();
DefaultMQPullConsumer consumer = consumerWrapper.getConsumer(rpcHook, configure.isUseTLS());
DefaultMQPullConsumer consumer = buildDefaultMQPullConsumer(rpcHook, configure.isUseTLS());
List<MessageView> messageViews = new ArrayList<>();
long offset = query.getPageNum() * query.getPageSize();
long total = 0;
try {
consumer.start();
for (QueueOffsetInfo queueOffsetInfo : queueOffsetInfos) {
long start = queueOffsetInfo.getStart();
long end = queueOffsetInfo.getEnd();
@@ -459,6 +462,8 @@ public class MessageServiceImpl implements MessageService {
} catch (Exception e) {
Throwables.throwIfUnchecked(e);
throw new RuntimeException(e);
} finally {
consumer.shutdown();
}
}

View File

@@ -73,10 +73,6 @@ import static org.apache.rocketmq.common.TopicAttributes.TOPIC_MESSAGE_TYPE_ATTR
@Service
public class TopicServiceImpl extends AbstractCommonService implements TopicService {
private transient DefaultMQProducer systemTopicProducer;
private final Object producerLock = new Object();
@Autowired
private RMQConfigure configure;
@@ -301,40 +297,18 @@ public class TopicServiceImpl extends AbstractCommonService implements TopicServ
if (isEnableAcl) {
rpcHook = new AclClientRPCHook(new SessionCredentials(configure.getAccessKey(), configure.getSecretKey()));
}
// ensures thread safety
if (systemTopicProducer == null) {
synchronized (producerLock) {
if (systemTopicProducer == null) {
systemTopicProducer = buildDefaultMQProducer(MixAll.SELF_TEST_PRODUCER_GROUP, rpcHook);
systemTopicProducer.setInstanceName("SystemTopicProducer-" + System.currentTimeMillis());
systemTopicProducer.setNamesrvAddr(configure.getNamesrvAddr());
try {
systemTopicProducer.start();
} catch (Exception e) {
systemTopicProducer = null;
Throwables.throwIfUnchecked(e);
throw new RuntimeException(e);
}
}
}
}
DefaultMQProducer producer = buildDefaultMQProducer(MixAll.SELF_TEST_PRODUCER_GROUP, rpcHook);
producer.setInstanceName(String.valueOf(System.currentTimeMillis()));
producer.setNamesrvAddr(configure.getNamesrvAddr());
try {
return systemTopicProducer.getDefaultMQProducerImpl()
.getmQClientFactory()
.getMQClientAPIImpl()
.getSystemTopicList(20000L);
producer.start();
return producer.getDefaultMQProducerImpl().getmQClientFactory().getMQClientAPIImpl().getSystemTopicList(20000L);
} catch (Exception e) {
// If the call fails, close and clean up the producer, and it will be re-created next time.
synchronized (producerLock) {
if (systemTopicProducer != null) {
systemTopicProducer.shutdown();
systemTopicProducer = null;
}
}
Throwables.throwIfUnchecked(e);
throw new RuntimeException(e);
} finally {
producer.shutdown();
}
}

View File

@@ -1,132 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.rocketmq.dashboard.support;
import org.apache.rocketmq.client.consumer.DefaultMQPullConsumer;
import org.apache.rocketmq.client.exception.MQClientException;
import org.apache.rocketmq.common.MixAll;
import org.apache.rocketmq.remoting.RPCHook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.time.Duration;
import java.time.Instant;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
public class AutoCloseConsumerWrapper {
private final Logger logger = LoggerFactory.getLogger(GlobalRestfulResponseBodyAdvice.class);
private static final AtomicReference<DefaultMQPullConsumer> CONSUMER_REF = new AtomicReference<>();
private final AtomicBoolean isTaskScheduled = new AtomicBoolean(false);
private final AtomicBoolean isClosing = new AtomicBoolean(false);
private static volatile Instant lastUsedTime = Instant.now();
private static final ScheduledExecutorService SCHEDULER =
Executors.newSingleThreadScheduledExecutor();
public AutoCloseConsumerWrapper() {
startIdleCheckTask();
}
public DefaultMQPullConsumer getConsumer(RPCHook rpcHook,Boolean useTLS) {
lastUsedTime = Instant.now();
DefaultMQPullConsumer consumer = CONSUMER_REF.get();
if (consumer == null) {
synchronized (this) {
consumer = CONSUMER_REF.get();
if (consumer == null) {
consumer = createNewConsumer(rpcHook,useTLS);
CONSUMER_REF.set(consumer);
}
try {
consumer.start();
} catch (MQClientException e) {
consumer.shutdown();
CONSUMER_REF.set(null);
throw new RuntimeException("Failed to start consumer", e);
}
}
}
return consumer;
}
protected DefaultMQPullConsumer createNewConsumer(RPCHook rpcHook, Boolean useTLS) {
return new DefaultMQPullConsumer(MixAll.TOOLS_CONSUMER_GROUP, rpcHook) {{
setUseTLS(useTLS);
}};
}
private void startIdleCheckTask() {
if (!isTaskScheduled.get()) {
synchronized (this) {
if (!isTaskScheduled.get()) {
SCHEDULER.scheduleWithFixedDelay(() -> {
try {
checkAndCloseIdleConsumer();
} catch (Exception e) {
logger.error("Idle check failed", e);
}
}, 1, 1, TimeUnit.MINUTES);
isTaskScheduled.set(true);
}
}
}
}
public void checkAndCloseIdleConsumer() {
if (shouldClose()) {
synchronized (this) {
if (shouldClose()) {
close();
}
}
}
}
private boolean shouldClose() {
long idleTimeoutMs = 60_000;
return CONSUMER_REF.get() != null &&
Duration.between(lastUsedTime, Instant.now()).toMillis() > idleTimeoutMs;
}
public void close() {
if (isClosing.compareAndSet(false, true)) {
try {
DefaultMQPullConsumer consumer = CONSUMER_REF.getAndSet(null);
if (consumer != null) {
consumer.shutdown();
}
isTaskScheduled.set(false);
} finally {
isClosing.set(false);
}
}
}
}

View File

@@ -79,7 +79,7 @@ module.controller('consumerController', ['$scope', 'ngDialog', '$http', 'Notific
url: "consumer/groupList.query",
params: {
skipSysGroup: false,
address: $scope.isRmqVersionV5() ? localStorage.getItem('proxyAddr') : null
address: localStorage.getItem('isV5') ? localStorage.getItem('proxyAddr') : null
}
}).success(function (resp) {
if (resp.status == 0) {

View File

@@ -27,15 +27,6 @@ app.controller('AppCtrl', ['$scope','$window','$translate','$http','Notification
localStorage.setItem("isV5", v);
}
$scope.isRmqVersionV5 = function(){
var v=localStorage.getItem('isV5');
//for js !! 'false' is true!
if( /false/i.test(v) ){
return false;
}
return !! v;
}
$scope.logout = function(){
$http({
method: "POST",

View File

@@ -141,7 +141,7 @@ module.controller('topicController', ['$scope', 'ngDialog', '$http', 'Notificati
return true
}
}
if ($scope.isRmqVersionV5() && $scope.filterUnspecified) {
if (localStorage.getItem('isV5') && $scope.filterUnspecified) {
if (type.includes("UNSPECIFIED")) {
return true
}
@@ -150,21 +150,21 @@ module.controller('topicController', ['$scope', 'ngDialog', '$http', 'Notificati
if (type.includes("NORMAL")) {
return true
}
if (!$scope.isRmqVersionV5() && type.includes("UNSPECIFIED")) {
if (!localStorage.getItem('isV5') && type.includes("UNSPECIFIED")) {
return true
}
}
if ($scope.isRmqVersionV5() && $scope.filterDelay) {
if (localStorage.getItem('isV5') && $scope.filterDelay) {
if (type.includes("DELAY")) {
return true
}
}
if ($scope.isRmqVersionV5() && $scope.filterFifo) {
if (localStorage.getItem('isV5') && $scope.filterFifo) {
if (type.includes("FIFO")) {
return true
}
}
if ($scope.isRmqVersionV5() && $scope.filterTransaction) {
if (localStorage.getItem('isV5') && $scope.filterTransaction) {
if (type.includes("TRANSACTION")) {
return true
}

View File

@@ -87,9 +87,6 @@ import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import static org.mockito.ArgumentMatchers.eq;
@RunWith(MockitoJUnitRunner.Silent.class)
public class MQAdminExtImplTest {
@@ -198,55 +195,62 @@ public class MQAdminExtImplTest {
@Test
public void testExamineSubscriptionGroupConfig() throws Exception {
assertNotNull(mqAdminExtImpl);
// Create valid SubscriptionGroupWrapper with group_test entry
SubscriptionGroupWrapper wrapper = new SubscriptionGroupWrapper();
ConcurrentMap<String, SubscriptionGroupConfig> subscriptionGroupTable = new ConcurrentHashMap<>();
SubscriptionGroupConfig config = new SubscriptionGroupConfig();
config.setGroupName("group_test");
subscriptionGroupTable.put("group_test", config);
wrapper.setSubscriptionGroupTable(subscriptionGroupTable);
// Create successful response
RemotingCommand successResponse = RemotingCommand.createResponseCommand(null);
successResponse.setCode(ResponseCode.SUCCESS);
successResponse.setBody(RemotingSerializable.encode(wrapper));
// Mock the remote invocation
when(remotingClient.invokeSync(eq(brokerAddr), any(RemotingCommand.class), anyLong()))
.thenReturn(successResponse);
// Test successful case
{
RemotingCommand response1 = RemotingCommand.createResponseCommand(null);
RemotingCommand response2 = RemotingCommand.createResponseCommand(null);
response2.setCode(ResponseCode.SUCCESS);
response2.setBody(RemotingSerializable.encode(MockObjectUtil.createSubscriptionGroupWrapper()));
when(remotingClient.invokeSync(anyString(), any(), anyLong()))
.thenThrow(new RuntimeException("invokeSync exception"))
.thenReturn(response1).thenReturn(response2);
}
// invokeSync exception
try {
mqAdminExtImpl.examineSubscriptionGroupConfig(brokerAddr, "topic_test");
} catch (Exception e) {
Assert.assertEquals(e.getMessage(), "invokeSync exception");
}
// responseCode is not success
try {
mqAdminExtImpl.examineSubscriptionGroupConfig(brokerAddr, "group_test");
} catch (Exception e) {
assertThat(e.getCause()).isInstanceOf(MQBrokerException.class);
assertThat(((MQBrokerException) e.getCause()).getResponseCode()).isEqualTo(1);
}
// GET_ALL_SUBSCRIPTIONGROUP_CONFIG success
SubscriptionGroupConfig subscriptionGroupConfig = mqAdminExtImpl.examineSubscriptionGroupConfig(brokerAddr, "group_test");
Assert.assertNotNull(subscriptionGroupConfig);
Assert.assertEquals("group_test", subscriptionGroupConfig.getGroupName());
Assert.assertEquals(subscriptionGroupConfig.getGroupName(), "group_test");
}
@Test
public void testExamineTopicConfig() throws Exception {
assertNotNull(mqAdminExtImpl);
// Create valid TopicConfigSerializeWrapper with topic_test entry
TopicConfigSerializeWrapper wrapper = new TopicConfigSerializeWrapper();
ConcurrentMap<String, TopicConfig> topicConfigTable = new ConcurrentHashMap<>();
TopicConfig config = new TopicConfig();
config.setTopicName("topic_test");
topicConfigTable.put("topic_test", config);
wrapper.setTopicConfigTable(topicConfigTable);
// Create successful response
RemotingCommand successResponse = RemotingCommand.createResponseCommand(null);
successResponse.setCode(ResponseCode.SUCCESS);
successResponse.setBody(RemotingSerializable.encode(wrapper));
// Mock the remote invocation
when(remotingClient.invokeSync(eq(brokerAddr), any(RemotingCommand.class), anyLong()))
.thenReturn(successResponse);
// Test successful case
{
RemotingCommand response1 = RemotingCommand.createResponseCommand(null);
RemotingCommand response2 = RemotingCommand.createResponseCommand(null);
response2.setCode(ResponseCode.SUCCESS);
response2.setBody(RemotingSerializable.encode(MockObjectUtil.createTopicConfigWrapper()));
when(remotingClient.invokeSync(anyString(), any(), anyLong()))
.thenThrow(new RuntimeException("invokeSync exception"))
.thenReturn(response1).thenReturn(response2);
}
// invokeSync exception
try {
mqAdminExtImpl.examineTopicConfig(brokerAddr, "topic_test");
} catch (Exception e) {
Assert.assertEquals(e.getMessage(), "invokeSync exception");
}
// responseCode is not success
try {
mqAdminExtImpl.examineTopicConfig(brokerAddr, "topic_test");
} catch (Exception e) {
assertThat(e.getCause()).isInstanceOf(MQBrokerException.class);
assertThat(((MQBrokerException) e.getCause()).getResponseCode()).isEqualTo(1);
}
// GET_ALL_TOPIC_CONFIG success
TopicConfig topicConfig = mqAdminExtImpl.examineTopicConfig(brokerAddr, "topic_test");
Assert.assertNotNull(topicConfig);
Assert.assertEquals("topic_test", topicConfig.getTopicName());
Assert.assertEquals(topicConfig.getTopicName(), "topic_test");
}
@Test

View File

@@ -19,9 +19,7 @@ package org.apache.rocketmq.dashboard.controller;
import com.alibaba.fastjson.JSON;
import com.google.common.collect.Lists;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import org.apache.rocketmq.client.exception.MQClientException;
@@ -41,9 +39,6 @@ import org.apache.rocketmq.dashboard.model.request.DeleteSubGroupRequest;
import org.apache.rocketmq.dashboard.model.request.ResetOffsetRequest;
import org.apache.rocketmq.dashboard.service.impl.ConsumerServiceImpl;
import org.apache.rocketmq.dashboard.util.MockObjectUtil;
import org.apache.rocketmq.dashboard.model.TopicConsumerInfo;
import org.apache.rocketmq.dashboard.model.QueueStatInfo;
import org.apache.rocketmq.remoting.protocol.body.Connection;
import org.junit.Before;
import org.junit.Test;
import org.mockito.InjectMocks;
@@ -58,7 +53,6 @@ import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.isNull;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.when;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@@ -235,70 +229,24 @@ public class ConsumerControllerTest extends BaseControllerTest {
@Test
public void testQueryConsumerByTopic() throws Exception {
// Prepare test data
List<TopicConsumerInfo> topicConsumerInfoList = new ArrayList<>();
TopicConsumerInfo info = new TopicConsumerInfo("test-topic");
// Add queue stats
List<QueueStatInfo> queueStatInfoList = new ArrayList<>();
QueueStatInfo queueStat1 = new QueueStatInfo();
queueStat1.setBrokerName("broker-0");
queueStat1.setQueueId(0);
info.appendQueueStatInfo(queueStat1);
QueueStatInfo queueStat2 = new QueueStatInfo();
queueStat2.setBrokerName("broker-1");
queueStat2.setQueueId(1);
info.appendQueueStatInfo(queueStat2);
topicConsumerInfoList.add(info);
// Mock the service method directly
doReturn(topicConsumerInfoList).when(consumerService).queryConsumeStatsListByGroupName(anyString(), any());
// Perform request and verify response
final String url = "/consumer/queryTopicByConsumer.query";
requestBuilder = MockMvcRequestBuilders.get(url);
requestBuilder.param("consumerGroup", "group_test");
perform = mockMvc.perform(requestBuilder);
perform.andExpect(status().isOk())
.andExpect(jsonPath("$.status").value(0))
.andExpect(jsonPath("$.data[0].topic").value("test-topic"))
.andExpect(jsonPath("$.data[0].queueStatInfoList", hasSize(2)))
.andExpect(jsonPath("$.data[0].queueStatInfoList[0].brokerName").value("broker-0"))
.andExpect(jsonPath("$.data[0].queueStatInfoList[1].brokerName").value("broker-1"));
.andExpect(jsonPath("$.data", hasSize(1)))
.andExpect(jsonPath("$.data[0].queueStatInfoList", hasSize(2)));
}
@Test
public void testConsumerConnection() throws Exception {
// Prepare test data
ConsumerConnection connection = new ConsumerConnection();
connection.setConsumeType(ConsumeType.CONSUME_ACTIVELY);
connection.setMessageModel(MessageModel.CLUSTERING);
// Setup connection set
HashSet<Connection> connections = new HashSet<>();
Connection conn = new Connection();
conn.setClientAddr("127.0.0.1");
conn.setClientId("clientId");
connections.add(conn);
connection.setConnectionSet(connections);
// Mock the service method
doReturn(connection).when(consumerService).getConsumerConnection(anyString(), any());
// Perform request and verify response
final String url = "/consumer/consumerConnection.query";
requestBuilder = MockMvcRequestBuilders.get(url);
requestBuilder.param("consumerGroup", "group_test");
perform = mockMvc.perform(requestBuilder);
perform.andExpect(status().isOk())
.andExpect(jsonPath("$.status").value(0))
.andExpect(jsonPath("$.data.consumeType").value("CONSUME_ACTIVELY"))
.andExpect(jsonPath("$.data.messageModel").value("CLUSTERING"))
.andExpect(jsonPath("$.data.connectionSet[0].clientAddr").value("127.0.0.1"));
.andExpect(jsonPath("$.data.consumeType").value(ConsumeType.CONSUME_ACTIVELY.name()))
.andExpect(jsonPath("$.data.messageModel").value(MessageModel.CLUSTERING.name()));
}
@Test

View File

@@ -90,31 +90,6 @@ public class MessageControllerTest extends BaseControllerTest {
when(pullResult.getPullStatus()).thenReturn(PullStatus.FOUND);
when(pullResult.getMsgFoundList()).thenReturn(wrappers);
when(messageService.buildDefaultMQPullConsumer(any(), anyBoolean())).thenReturn(defaultMQPullConsumer);
// Ensure searchOffset returns values that make sense for the test times
when(defaultMQPullConsumer.searchOffset(any(MessageQueue.class), anyLong())).thenAnswer(invocation -> {
long timestamp = invocation.getArgument(1);
if (timestamp <= System.currentTimeMillis()) {
return 0L; // Beginning offset for timestamps in the past
} else {
return Long.MAX_VALUE - 10L; // Near max offset for future timestamps
}
});
// Make sure that messageService.queryMessageByTopicAndKey returns some messages for the test
MessageExt messageExt = MockObjectUtil.createMessageExt();
List<MessageExt> foundMessages = new ArrayList<>();
foundMessages.add(messageExt);
// Ensure the PullResult always returns a message
PullResult pullResultWithMessages = mock(PullResult.class);
when(pullResultWithMessages.getPullStatus()).thenReturn(PullStatus.FOUND);
when(pullResultWithMessages.getMsgFoundList()).thenReturn(foundMessages);
when(pullResultWithMessages.getNextBeginOffset()).thenReturn(1L);
// Override the previous mock to ensure the test finds messages
when(defaultMQPullConsumer.pull(any(MessageQueue.class), anyString(), anyLong(), anyInt()))
.thenReturn(pullResultWithMessages);
}
}
@@ -174,7 +149,8 @@ public class MessageControllerTest extends BaseControllerTest {
requestBuilder.content(JSON.toJSONString(query));
perform = mockMvc.perform(requestBuilder);
perform.andExpect(status().isOk())
.andExpect(jsonPath("$.data.page.content", hasSize(0)));
.andExpect(jsonPath("$.data.page.content", hasSize(1)))
.andExpect(jsonPath("$.data.page.content[0].msgId").value("0A9A003F00002A9F0000000000000319"));
String taskId = MessageClientIDSetter.createUniqID();
{
@@ -194,7 +170,6 @@ public class MessageControllerTest extends BaseControllerTest {
// hit cache
query.setTaskId(taskId);
query.setPageNum(1);
requestBuilder.content(JSON.toJSONString(query));
perform = mockMvc.perform(requestBuilder);
perform.andExpect(status().isOk())

View File

@@ -19,7 +19,6 @@ package org.apache.rocketmq.dashboard.controller;
import com.alibaba.fastjson.JSON;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@@ -42,7 +41,6 @@ import org.apache.rocketmq.remoting.protocol.body.TopicList;
import org.apache.rocketmq.remoting.protocol.route.TopicRouteData;
import org.apache.rocketmq.dashboard.model.request.SendTopicMessageRequest;
import org.apache.rocketmq.dashboard.model.request.TopicConfigInfo;
import org.apache.rocketmq.dashboard.model.request.TopicTypeList;
import org.apache.rocketmq.dashboard.service.impl.ConsumerServiceImpl;
import org.apache.rocketmq.dashboard.service.impl.TopicServiceImpl;
import org.apache.rocketmq.dashboard.util.MockObjectUtil;
@@ -55,9 +53,8 @@ import org.mockito.Spy;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.hasSize;
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyLong;
@@ -275,8 +272,9 @@ public class TopicControllerTest extends BaseControllerTest {
requestBuilder.content(JSON.toJSONString(request));
perform = mockMvc.perform(requestBuilder);
perform.andExpect(status().isOk())
.andExpect(jsonPath("$.status").value(-1))
.andExpect(jsonPath("$.errMsg").value(containsString("NullPointerException")));
.andExpect(jsonPath("$.data.sendStatus").value(SendStatus.SEND_OK.name()))
.andExpect(jsonPath("$.data.msgId").value("7F000001E41A2E5D6D978B82C20F003D"));
}
@Test
@@ -319,45 +317,6 @@ public class TopicControllerTest extends BaseControllerTest {
.andExpect(jsonPath("$.data").value(true));
}
@Test
public void testListTopicType() throws Exception {
// Build test environment
// Set up scope at beginning with '{' and '}' to match the class pattern
{
// Create mock TopicTypeList to be returned by service
ArrayList<String> topicNames = new ArrayList<>();
topicNames.add("topic1");
topicNames.add("topic2");
topicNames.add("%SYS%topic3");
ArrayList<String> messageTypes = new ArrayList<>();
messageTypes.add("NORMAL");
messageTypes.add("FIFO");
messageTypes.add("SYSTEM");
TopicTypeList topicTypeList = new TopicTypeList(topicNames, messageTypes);
// Mock service method
doReturn(topicTypeList).when(topicService).examineAllTopicType();
}
// Execute request
final String url = "/topic/list.queryTopicType";
requestBuilder = MockMvcRequestBuilders.get(url);
perform = mockMvc.perform(requestBuilder);
// Verify response
performOkExpect(perform)
.andExpect(jsonPath("$.data.topicNameList", hasSize(3)))
.andExpect(jsonPath("$.data.topicNameList[0]").value("topic1"))
.andExpect(jsonPath("$.data.topicNameList[1]").value("topic2"))
.andExpect(jsonPath("$.data.topicNameList[2]").value("%SYS%topic3"))
.andExpect(jsonPath("$.data.messageTypeList", hasSize(3)))
.andExpect(jsonPath("$.data.messageTypeList[0]").value("NORMAL"))
.andExpect(jsonPath("$.data.messageTypeList[1]").value("FIFO"))
.andExpect(jsonPath("$.data.messageTypeList[2]").value("SYSTEM"));
}
@Override protected Object getTestController() {
return topicController;
}

View File

@@ -1,480 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.rocketmq.dashboard.service.impl;
import com.google.common.cache.Cache;
import org.apache.rocketmq.acl.common.AclClientRPCHook;
import org.apache.rocketmq.client.consumer.DefaultMQPullConsumer;
import org.apache.rocketmq.client.consumer.PullResult;
import org.apache.rocketmq.client.consumer.PullStatus;
import org.apache.rocketmq.client.exception.MQClientException;
import org.apache.rocketmq.common.Pair;
import org.apache.rocketmq.common.message.MessageClientIDSetter;
import org.apache.rocketmq.common.message.MessageExt;
import org.apache.rocketmq.common.message.MessageQueue;
import org.apache.rocketmq.dashboard.config.RMQConfigure;
import org.apache.rocketmq.dashboard.exception.ServiceException;
import org.apache.rocketmq.dashboard.model.MessagePage;
import org.apache.rocketmq.dashboard.model.MessageView;
import org.apache.rocketmq.dashboard.model.QueueOffsetInfo;
import org.apache.rocketmq.dashboard.model.request.MessageQuery;
import org.apache.rocketmq.dashboard.model.MessageQueryByPage;
import org.apache.rocketmq.remoting.protocol.body.Connection;
import org.apache.rocketmq.remoting.protocol.body.ConsumeMessageDirectlyResult;
import org.apache.rocketmq.remoting.protocol.body.ConsumerConnection;
import org.apache.rocketmq.tools.admin.MQAdminExt;
import org.apache.rocketmq.tools.admin.api.MessageTrack;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Spy;
import org.mockito.junit.MockitoJUnitRunner;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.lenient;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@RunWith(MockitoJUnitRunner.Silent.class)
public class MessageServiceImplTest {
@InjectMocks
@Spy
private MessageServiceImpl messageService;
@Mock
private MQAdminExt mqAdminExt;
@Mock
private RMQConfigure configure;
@Mock
private DefaultMQPullConsumer consumer;
@Mock
private Cache<String, MessagePage> messagePageCache;
private static final String TOPIC = "testTopic";
private static final String MSG_ID = "testMsgId";
private static final String CONSUMER_GROUP = "testConsumerGroup";
private static final String CLIENT_ID = "testClientId";
private static final String KEY = "testKey";
private static final String TASK_ID = "CID_RMQ_SYS_TASK12345";
@Before
public void setUp() throws Exception {
// Set up default mock responses
when(configure.getNamesrvAddr()).thenReturn("localhost:9876");
when(configure.isUseTLS()).thenReturn(false);
// Mock the consumer creation to avoid actual RocketMQ calls
lenient().doReturn(consumer).when(messageService).buildDefaultMQPullConsumer(any(), anyBoolean());
}
@Test
public void testViewMessage() throws Exception {
// Setup
MessageExt messageExt = createMessageExt(MSG_ID, TOPIC, "test body", System.currentTimeMillis());
List<MessageTrack> tracks = Collections.singletonList(mock(MessageTrack.class));
when(mqAdminExt.viewMessage(anyString(), anyString())).thenReturn(messageExt);
doReturn(tracks).when(messageService).messageTrackDetail(any(MessageExt.class));
// Execute
Pair<MessageView, List<MessageTrack>> result = messageService.viewMessage(TOPIC, MSG_ID);
// Verify
assertNotNull(result);
assertEquals(messageExt.getMsgId(), result.getObject1().getMsgId());
assertEquals(tracks, result.getObject2());
verify(mqAdminExt).viewMessage(TOPIC, MSG_ID);
}
@Test(expected = ServiceException.class)
public void testViewMessageException() throws Exception {
// Setup
when(mqAdminExt.viewMessage(anyString(), anyString())).thenThrow(new RuntimeException("Test exception"));
// Execute & Verify exception is thrown
messageService.viewMessage(TOPIC, MSG_ID);
}
@Test
public void testQueryMessageByTopicAndKey() throws Exception {
// Setup mock MessageExt objects
MessageExt msg1 = createMessageExt("id1", TOPIC, "body1", System.currentTimeMillis());
MessageExt msg2 = createMessageExt("id2", TOPIC, "body2", System.currentTimeMillis());
// Create MessageView objects from the MessageExt objects
MessageView view1 = MessageView.fromMessageExt(msg1);
MessageView view2 = MessageView.fromMessageExt(msg2);
// We'll use fresh objects for this test to avoid recursive mock issues
List<MessageView> expectedViews = Arrays.asList(view1, view2);
// Skip the real implementation and provide test data directly
doReturn(expectedViews).when(messageService).queryMessageByTopicAndKey(TOPIC, KEY);
// Execute
List<MessageView> result = messageService.queryMessageByTopicAndKey(TOPIC, KEY);
// Verify we get the expected number of messages
assertEquals(2, result.size());
}
@Test(expected = ServiceException.class)
public void testQueryMessageByTopicAndKeyMQException() throws Exception {
// Setup a fresh spy that's not part of our test setup to avoid recursive mocking issues
MessageServiceImpl testService = mock(MessageServiceImpl.class);
when(testService.queryMessageByTopicAndKey(TOPIC, KEY))
.thenThrow(new ServiceException(-1, "Test error"));
// Execute & Verify exception is thrown
testService.queryMessageByTopicAndKey(TOPIC, KEY);
}
@Test(expected = RuntimeException.class)
public void testQueryMessageByTopicAndKeyRuntimeException() throws Exception {
// Setup a fresh spy that's not part of our test setup to avoid recursive mocking issues
MessageServiceImpl testService = mock(MessageServiceImpl.class);
when(testService.queryMessageByTopicAndKey(TOPIC, KEY))
.thenThrow(new RuntimeException("Test exception"));
// Execute & Verify exception is thrown
testService.queryMessageByTopicAndKey(TOPIC, KEY);
}
@Test
public void testQueryMessageByTopic() throws Exception {
// Setup message queues
Set<MessageQueue> messageQueues = new HashSet<>();
messageQueues.add(new MessageQueue(TOPIC, "broker-1", 0));
messageQueues.add(new MessageQueue(TOPIC, "broker-2", 1));
when(consumer.fetchSubscribeMessageQueues(TOPIC)).thenReturn(messageQueues);
// Setup pull results for both queues
PullResult pullResult1 = createPullResult(PullStatus.FOUND, Arrays.asList(
createMessageExt("id1", TOPIC, "body1", 1500),
createMessageExt("id2", TOPIC, "body2", 2000)
), 0, 10);
PullResult pullResult2 = createPullResult(PullStatus.FOUND, Arrays.asList(
createMessageExt("id3", TOPIC, "body3", 1800),
createMessageExt("id4", TOPIC, "body4", 2200)
), 0, 10);
PullResult emptyResult = createPullResult(PullStatus.NO_NEW_MSG, Collections.emptyList(), 10, 10);
// First pull gets messages, second pull gets empty to terminate loop
when(consumer.pull(any(MessageQueue.class), anyString(), anyLong(), anyInt()))
.thenReturn(pullResult1)
.thenReturn(emptyResult)
.thenReturn(pullResult2)
.thenReturn(emptyResult);
// Execute
long beginTime = 1000;
long endTime = 3000;
List<MessageView> result = messageService.queryMessageByTopic(TOPIC, beginTime, endTime);
// Verify
assertEquals(4, result.size());
// Should be sorted by timestamp in descending order
assertEquals("id4", result.get(0).getMsgId()); // 2200
assertEquals("id2", result.get(1).getMsgId()); // 2000
assertEquals("id3", result.get(2).getMsgId()); // 1800
assertEquals("id1", result.get(3).getMsgId()); // 1500
verify(consumer, times(4)).pull(any(MessageQueue.class), eq("*"), anyLong(), anyInt());
verify(consumer).start();
verify(consumer).shutdown();
}
@Test
public void testQueryMessageByTopicWithOutOfRangeTimestamps() throws Exception {
// Setup message queues
Set<MessageQueue> messageQueues = new HashSet<>();
messageQueues.add(new MessageQueue(TOPIC, "broker-1", 0));
when(consumer.fetchSubscribeMessageQueues(TOPIC)).thenReturn(messageQueues);
// Setup pull results - some messages are outside time range
PullResult pullResult = createPullResult(PullStatus.FOUND, Arrays.asList(
createMessageExt("id1", TOPIC, "body1", 500), // Outside range (too early)
createMessageExt("id2", TOPIC, "body2", 1500), // Inside range
createMessageExt("id3", TOPIC, "body3", 3500) // Outside range (too late)
), 0, 10);
PullResult emptyResult = createPullResult(PullStatus.NO_NEW_MSG, Collections.emptyList(), 10, 10);
when(consumer.pull(any(MessageQueue.class), anyString(), anyLong(), anyInt()))
.thenReturn(pullResult)
.thenReturn(emptyResult);
// Execute
long beginTime = 1000;
long endTime = 3000;
List<MessageView> result = messageService.queryMessageByTopic(TOPIC, beginTime, endTime);
// Verify - only messages within time range should be included
assertEquals(1, result.size());
assertEquals("id2", result.get(0).getMsgId());
}
@Test
public void testQueryMessageByTopicWithDifferentPullStatuses() throws Exception {
// Setup message queues
Set<MessageQueue> messageQueues = new HashSet<>();
messageQueues.add(new MessageQueue(TOPIC, "broker-1", 0));
when(consumer.fetchSubscribeMessageQueues(TOPIC)).thenReturn(messageQueues);
// Test all different pull statuses
PullResult pullResult1 = createPullResult(PullStatus.FOUND,
Collections.singletonList(createMessageExt("id1", TOPIC, "body1", 1500)), 0, 5);
PullResult pullResult2 = createPullResult(PullStatus.NO_MATCHED_MSG,
Collections.emptyList(), 5, 6);
PullResult pullResult3 = createPullResult(PullStatus.NO_NEW_MSG,
Collections.emptyList(), 6, 7);
PullResult pullResult4 = createPullResult(PullStatus.OFFSET_ILLEGAL,
Collections.emptyList(), 7, 8);
when(consumer.pull(any(MessageQueue.class), anyString(), anyLong(), anyInt()))
.thenReturn(pullResult1)
.thenReturn(pullResult2)
.thenReturn(pullResult3)
.thenReturn(pullResult4);
// Execute
long beginTime = 1000;
long endTime = 3000;
List<MessageView> result = messageService.queryMessageByTopic(TOPIC, beginTime, endTime);
// Verify
assertEquals(1, result.size());
assertEquals("id1", result.get(0).getMsgId());
}
@Test
public void testMessageTrackDetail() throws Exception {
// Setup
MessageExt msg = createMessageExt(MSG_ID, TOPIC, "body", System.currentTimeMillis());
List<MessageTrack> tracks = Collections.singletonList(mock(MessageTrack.class));
when(mqAdminExt.messageTrackDetail(any(MessageExt.class))).thenReturn(tracks);
// Execute
List<MessageTrack> result = messageService.messageTrackDetail(msg);
// Verify
assertEquals(tracks, result);
verify(mqAdminExt).messageTrackDetail(msg);
}
@Test
public void testMessageTrackDetailException() throws Exception {
// Setup
MessageExt msg = createMessageExt(MSG_ID, TOPIC, "body", System.currentTimeMillis());
when(mqAdminExt.messageTrackDetail(any(MessageExt.class))).thenThrow(new RuntimeException("Test exception"));
// Execute
List<MessageTrack> result = messageService.messageTrackDetail(msg);
// Verify - should return empty list on exception
assertTrue(result.isEmpty());
}
@Test
public void testConsumeMessageDirectlyWithClientId() throws Exception {
// Setup
ConsumeMessageDirectlyResult expectedResult = new ConsumeMessageDirectlyResult();
when(mqAdminExt.consumeMessageDirectly(CONSUMER_GROUP, CLIENT_ID, TOPIC, MSG_ID))
.thenReturn(expectedResult);
// Execute
ConsumeMessageDirectlyResult result = messageService.consumeMessageDirectly(TOPIC, MSG_ID, CONSUMER_GROUP, CLIENT_ID);
// Verify
assertEquals(expectedResult, result);
verify(mqAdminExt).consumeMessageDirectly(CONSUMER_GROUP, CLIENT_ID, TOPIC, MSG_ID);
}
@Test
public void testConsumeMessageDirectlyWithoutClientId() throws Exception {
// Setup
ConsumeMessageDirectlyResult expectedResult = new ConsumeMessageDirectlyResult();
ConsumerConnection consumerConnection = new ConsumerConnection();
HashSet<Connection> connectionSet = new HashSet<>();
// Add a connection without clientId - should be skipped
Connection emptyConn = new Connection();
connectionSet.add(emptyConn);
// Add a connection with clientId - should be used
Connection conn = new Connection();
conn.setClientId(CLIENT_ID);
connectionSet.add(conn);
consumerConnection.setConnectionSet(connectionSet);
when(mqAdminExt.examineConsumerConnectionInfo(CONSUMER_GROUP)).thenReturn(consumerConnection);
when(mqAdminExt.consumeMessageDirectly(CONSUMER_GROUP, CLIENT_ID, TOPIC, MSG_ID))
.thenReturn(expectedResult);
// Execute
ConsumeMessageDirectlyResult result = messageService.consumeMessageDirectly(TOPIC, MSG_ID, CONSUMER_GROUP, null);
// Verify
assertEquals(expectedResult, result);
verify(mqAdminExt).examineConsumerConnectionInfo(CONSUMER_GROUP);
verify(mqAdminExt).consumeMessageDirectly(CONSUMER_GROUP, CLIENT_ID, TOPIC, MSG_ID);
}
@Test(expected = IllegalStateException.class)
public void testConsumeMessageDirectlyWithNoConsumer() throws Exception {
// Setup
ConsumerConnection consumerConnection = new ConsumerConnection();
consumerConnection.setConnectionSet(new HashSet<>());
when(mqAdminExt.examineConsumerConnectionInfo(CONSUMER_GROUP)).thenReturn(consumerConnection);
// Execute & Verify exception
messageService.consumeMessageDirectly(TOPIC, MSG_ID, CONSUMER_GROUP, null);
}
@Test
public void testMoveStartOffset() throws Exception {
// Create test queue offsets
List<QueueOffsetInfo> queueOffsets = new ArrayList<>();
MessageQueue mq1 = new MessageQueue(TOPIC, "broker", 0);
MessageQueue mq2 = new MessageQueue(TOPIC, "broker", 1);
MessageQueue mq3 = new MessageQueue(TOPIC, "broker", 2);
QueueOffsetInfo qo1 = new QueueOffsetInfo(0, 0L, 10L, 0L, 0L, mq1);
QueueOffsetInfo qo2 = new QueueOffsetInfo(1, 0L, 20L, 0L, 0L, mq2);
QueueOffsetInfo qo3 = new QueueOffsetInfo(2, 0L, 30L, 0L, 0L, mq3);
queueOffsets.add(qo1);
queueOffsets.add(qo2);
queueOffsets.add(qo3);
// Create query with offset 15 (page 2 with size 15)
MessageQueryByPage query = new MessageQueryByPage(2, 15, TOPIC, 1000, 3000);
// Access the private method
Method method = MessageServiceImpl.class.getDeclaredMethod("moveStartOffset",
List.class, MessageQueryByPage.class);
method.setAccessible(true);
int nextIndex = (Integer) method.invoke(messageService, queueOffsets, query);
// Verify - the actual implementation distributes 15 units of offset across 3 queues
assertEquals(15, qo1.getStartOffset() + qo2.getStartOffset() + qo3.getStartOffset());
assertTrue(nextIndex >= 0 && nextIndex < queueOffsets.size());
}
@Test
public void testMoveEndOffset() throws Exception {
// Create test queue offsets
List<QueueOffsetInfo> queueOffsets = new ArrayList<>();
MessageQueue mq1 = new MessageQueue(TOPIC, "broker", 0);
MessageQueue mq2 = new MessageQueue(TOPIC, "broker", 1);
QueueOffsetInfo qo1 = new QueueOffsetInfo(0, 0L, 10L, 5L, 5L, mq1);
QueueOffsetInfo qo2 = new QueueOffsetInfo(1, 0L, 20L, 10L, 10L, mq2);
queueOffsets.add(qo1);
queueOffsets.add(qo2);
// Create query with page size 10
MessageQueryByPage query = new MessageQueryByPage(2, 10, TOPIC, 1000, 3000);
int nextIndex = 0; // Start with the first queue
// Access the private method
Method method = MessageServiceImpl.class.getDeclaredMethod("moveEndOffset",
List.class, MessageQueryByPage.class, int.class);
method.setAccessible(true);
method.invoke(messageService, queueOffsets, query, nextIndex);
// Verify total endOffset increment is page size
assertEquals(10, (qo1.getEndOffset() - 5L) + (qo2.getEndOffset() - 10L));
}
@Test
public void testBuildDefaultMQPullConsumer() {
// Test with TLS enabled
DefaultMQPullConsumer tlsConsumer = messageService.buildDefaultMQPullConsumer(null, true);
assertNotNull(tlsConsumer);
// Test with TLS disabled
DefaultMQPullConsumer nonTlsConsumer = messageService.buildDefaultMQPullConsumer(null, false);
assertNotNull(nonTlsConsumer);
// Test with RPC hook
AclClientRPCHook rpcHook = mock(AclClientRPCHook.class);
DefaultMQPullConsumer hookConsumer = messageService.buildDefaultMQPullConsumer(rpcHook, false);
assertNotNull(hookConsumer);
}
// Helper methods
private MessageExt createMessageExt(String msgId, String topic, String body, long storeTimestamp) {
MessageExt msg = new MessageExt();
msg.setMsgId(msgId);
msg.setTopic(topic);
msg.setBody(body.getBytes());
msg.setStoreTimestamp(storeTimestamp);
return msg;
}
private PullResult createPullResult(PullStatus status, List<MessageExt> msgFoundList, long nextBeginOffset, long minOffset) {
return new PullResult(status, nextBeginOffset, minOffset, minOffset + msgFoundList.size(), msgFoundList);
}
}

View File

@@ -1,332 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.rocketmq.dashboard.service.impl;
import org.apache.rocketmq.dashboard.model.request.TopicConfigInfo;
import org.apache.rocketmq.dashboard.model.request.TopicTypeList;
import org.apache.rocketmq.dashboard.util.MockObjectUtil;
import org.apache.rocketmq.remoting.protocol.body.TopicList;
import org.apache.rocketmq.tools.admin.MQAdminExt;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Spy;
import org.mockito.junit.MockitoJUnitRunner;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.when;
import org.apache.rocketmq.acl.common.AclClientRPCHook;
import org.apache.rocketmq.client.producer.DefaultMQProducer;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.client.producer.SendStatus;
import org.apache.rocketmq.client.producer.TransactionMQProducer;
import org.apache.rocketmq.common.attribute.TopicMessageType;
import org.apache.rocketmq.common.message.Message;
import org.apache.rocketmq.dashboard.config.RMQConfigure;
import org.apache.rocketmq.dashboard.model.request.SendTopicMessageRequest;
import org.mockito.ArgumentCaptor;
import org.mockito.ArgumentMatchers;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.isNull;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.lenient;
@RunWith(MockitoJUnitRunner.class)
public class TopicServiceImplTest {
@InjectMocks
@Spy
private TopicServiceImpl topicService;
@Mock
private MQAdminExt mqAdminExt;
@Mock
private RMQConfigure configure;
@Before
public void setUp() {
// Setup common mocks
when(configure.getNamesrvAddr()).thenReturn("localhost:9876");
// Use lenient() to prevent the unnecessary stubbing error
lenient().when(configure.isUseTLS()).thenReturn(false);
}
@Test
public void testExamineAllTopicType() throws Exception {
// Create mock TopicList with different types of topics
TopicList topicList = new TopicList();
Set<String> topicSet = new HashSet<>();
topicSet.add("normalTopic");
topicSet.add("%RETRY%someGroup");
topicSet.add("%DLQ%someGroup");
topicSet.add("%SYS%sysTopic");
topicList.setTopicList(topicSet);
// Mock fetchAllTopicList to return our test topics
doReturn(topicList).when(topicService).fetchAllTopicList(anyBoolean(), anyBoolean());
// Mock examineTopicConfig for the normal topic
TopicConfigInfo configInfo = new TopicConfigInfo();
configInfo.setMessageType("NORMAL");
List<TopicConfigInfo> topicConfigInfos = new ArrayList<>();
topicConfigInfos.add(configInfo);
doReturn(topicConfigInfos).when(topicService).examineTopicConfig(anyString());
// Call the method being tested
TopicTypeList result = topicService.examineAllTopicType();
// Verify the results
Assert.assertNotNull(result);
Assert.assertEquals(4, result.getTopicNameList().size());
Assert.assertEquals(4, result.getMessageTypeList().size());
// Verify that the topics contain the expected names and types
// Note: the actual order might be different due to sorting in the method
// So we're checking that all expected items are included
Assert.assertTrue(result.getTopicNameList().contains("normalTopic"));
Assert.assertTrue(result.getTopicNameList().contains("%RETRY%someGroup"));
Assert.assertTrue(result.getTopicNameList().contains("%DLQ%someGroup"));
Assert.assertTrue(result.getTopicNameList().contains("%SYS%sysTopic"));
// Verify message types
Assert.assertTrue(result.getMessageTypeList().contains("NORMAL"));
Assert.assertTrue(result.getMessageTypeList().contains("RETRY"));
Assert.assertTrue(result.getMessageTypeList().contains("DELAY"));
Assert.assertTrue(result.getMessageTypeList().contains("SYSTEM"));
}
@Test
public void testSendTopicMessageRequestNormal() throws Exception {
// Prepare test data
SendTopicMessageRequest request = new SendTopicMessageRequest();
request.setTopic("testTopic");
request.setTag("testTag");
request.setKey("testKey");
request.setMessageBody("Hello RocketMQ");
request.setTraceEnabled(false);
// Mock the topic config
TopicConfigInfo configInfo = new TopicConfigInfo();
configInfo.setMessageType(TopicMessageType.NORMAL.name());
List<TopicConfigInfo> topicConfigInfos = new ArrayList<>();
topicConfigInfos.add(configInfo);
doReturn(topicConfigInfos).when(topicService).examineTopicConfig("testTopic");
// Mock ACL disabled
when(configure.isACLEnabled()).thenReturn(false);
// Mock producer
DefaultMQProducer mockProducer = mock(DefaultMQProducer.class);
doReturn(mockProducer).when(topicService).buildDefaultMQProducer(any(), any(), anyBoolean());
// Mock send result
SendResult expectedResult = new SendResult();
expectedResult.setSendStatus(SendStatus.SEND_OK);
when(mockProducer.send(any(Message.class))).thenReturn(expectedResult);
// Call the method
SendResult result = topicService.sendTopicMessageRequest(request);
// Verify
Assert.assertEquals(expectedResult, result);
// Verify producer configuration and message sending
verify(mockProducer).setInstanceName(anyString());
verify(mockProducer).setNamesrvAddr("localhost:9876");
verify(mockProducer).start();
// Verify message content
ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class);
verify(mockProducer).send(messageCaptor.capture());
Message sentMessage = messageCaptor.getValue();
Assert.assertEquals("testTopic", sentMessage.getTopic());
Assert.assertEquals("testTag", sentMessage.getTags());
Assert.assertEquals("testKey", sentMessage.getKeys());
Assert.assertEquals("Hello RocketMQ", new String(sentMessage.getBody()));
// Verify producer shutdown
verify(mockProducer).shutdown();
}
@Test
public void testSendTopicMessageRequestTransaction() throws Exception {
// Prepare test data
SendTopicMessageRequest request = new SendTopicMessageRequest();
request.setTopic("testTopic");
request.setTag("testTag");
request.setKey("testKey");
request.setMessageBody("Hello RocketMQ");
request.setTraceEnabled(false);
// Mock the topic config
TopicConfigInfo configInfo = new TopicConfigInfo();
configInfo.setMessageType(TopicMessageType.TRANSACTION.name());
List<TopicConfigInfo> topicConfigInfos = new ArrayList<>();
topicConfigInfos.add(configInfo);
doReturn(topicConfigInfos).when(topicService).examineTopicConfig("testTopic");
// Mock ACL disabled
when(configure.isACLEnabled()).thenReturn(false);
// Mock producer
TransactionMQProducer mockProducer = mock(TransactionMQProducer.class);
doReturn(mockProducer).when(topicService).buildTransactionMQProducer(any(), any(), anyBoolean());
// Mock send result - use org.apache.rocketmq.client.producer.TransactionSendResult instead of SendResult
org.apache.rocketmq.client.producer.TransactionSendResult expectedResult = new org.apache.rocketmq.client.producer.TransactionSendResult();
expectedResult.setSendStatus(SendStatus.SEND_OK);
when(mockProducer.sendMessageInTransaction(any(Message.class), isNull())).thenReturn(expectedResult);
// Call the method
SendResult result = topicService.sendTopicMessageRequest(request);
// Verify
Assert.assertEquals(expectedResult, result);
// Verify producer configuration and message sending
verify(mockProducer).setInstanceName(anyString());
verify(mockProducer).setNamesrvAddr("localhost:9876");
verify(mockProducer).setTransactionListener(any());
verify(mockProducer).start();
// Verify message content
ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class);
verify(mockProducer).sendMessageInTransaction(messageCaptor.capture(), isNull());
Message sentMessage = messageCaptor.getValue();
Assert.assertEquals("testTopic", sentMessage.getTopic());
Assert.assertEquals("testTag", sentMessage.getTags());
Assert.assertEquals("testKey", sentMessage.getKeys());
Assert.assertEquals("Hello RocketMQ", new String(sentMessage.getBody()));
// Verify producer shutdown
verify(mockProducer).shutdown();
}
@Test
public void testSendTopicMessageRequestWithACLEnabled() throws Exception {
// Prepare test data
SendTopicMessageRequest request = new SendTopicMessageRequest();
request.setTopic("testTopic");
request.setTag("testTag");
request.setKey("testKey");
request.setMessageBody("Hello RocketMQ");
request.setTraceEnabled(false);
// Mock the topic config
TopicConfigInfo configInfo = new TopicConfigInfo();
configInfo.setMessageType(TopicMessageType.NORMAL.name());
List<TopicConfigInfo> topicConfigInfos = new ArrayList<>();
topicConfigInfos.add(configInfo);
doReturn(topicConfigInfos).when(topicService).examineTopicConfig("testTopic");
// Mock ACL enabled
when(configure.isACLEnabled()).thenReturn(true);
when(configure.getAccessKey()).thenReturn("testAccessKey");
when(configure.getSecretKey()).thenReturn("testSecretKey");
// Mock producer
DefaultMQProducer mockProducer = mock(DefaultMQProducer.class);
doReturn(mockProducer).when(topicService).buildDefaultMQProducer(any(), any(AclClientRPCHook.class), anyBoolean());
// Mock send result
SendResult expectedResult = new SendResult();
expectedResult.setSendStatus(SendStatus.SEND_OK);
when(mockProducer.send(any(Message.class))).thenReturn(expectedResult);
// Call the method
SendResult result = topicService.sendTopicMessageRequest(request);
// Verify
Assert.assertEquals(expectedResult, result);
// Since we can't directly verify the AclClientRPCHook content, we verify that build was called with non-null hook
verify(topicService).buildDefaultMQProducer(any(), any(AclClientRPCHook.class), eq(false));
// Verify producer methods
verify(mockProducer).start();
verify(mockProducer).send(any(Message.class));
verify(mockProducer).shutdown();
}
@Test
public void testSendTopicMessageRequestWithTraceEnabled() throws Exception {
// Prepare test data
SendTopicMessageRequest request = new SendTopicMessageRequest();
request.setTopic("testTopic");
request.setTag("testTag");
request.setKey("testKey");
request.setMessageBody("Hello RocketMQ");
request.setTraceEnabled(true); // Enable tracing
// Mock the topic config
TopicConfigInfo configInfo = new TopicConfigInfo();
configInfo.setMessageType(TopicMessageType.NORMAL.name());
List<TopicConfigInfo> topicConfigInfos = new ArrayList<>();
topicConfigInfos.add(configInfo);
doReturn(topicConfigInfos).when(topicService).examineTopicConfig("testTopic");
// Mock ACL disabled
when(configure.isACLEnabled()).thenReturn(false);
// Mock producer
DefaultMQProducer mockProducer = mock(DefaultMQProducer.class);
doReturn(mockProducer).when(topicService).buildDefaultMQProducer(any(), any(), eq(true));
// Cannot mock waitSendTraceFinish as it's private
// doNothing().when(topicService).waitSendTraceFinish(any(DefaultMQProducer.class), eq(true));
// Mock send result
SendResult expectedResult = new SendResult();
expectedResult.setSendStatus(SendStatus.SEND_OK);
when(mockProducer.send(any(Message.class))).thenReturn(expectedResult);
// Call the method
SendResult result = topicService.sendTopicMessageRequest(request);
// Verify
Assert.assertEquals(expectedResult, result);
// Verify that buildDefaultMQProducer was called with traceEnabled=true
verify(topicService).buildDefaultMQProducer(any(), any(), eq(true));
// Cannot verify waitSendTraceFinish as it's private
// verify(topicService).waitSendTraceFinish(mockProducer, true);
}
}

View File

@@ -1,84 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.rocketmq.dashboard.util;
import org.apache.rocketmq.client.consumer.DefaultMQPullConsumer;
import org.apache.rocketmq.dashboard.support.AutoCloseConsumerWrapper;
import org.apache.rocketmq.remoting.RPCHook;
import java.lang.reflect.Field;
import static org.mockito.Mockito.mock;
import org.apache.rocketmq.client.exception.MQClientException;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.junit.jupiter.MockitoExtension;
import java.time.Instant;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;
@ExtendWith(MockitoExtension.class)
class AutoCloseConsumerWrapperTests {
private static class TestableWrapper extends AutoCloseConsumerWrapper {
private DefaultMQPullConsumer mockConsumer = mock(DefaultMQPullConsumer.class);
@Override
protected DefaultMQPullConsumer createNewConsumer(RPCHook rpcHook, Boolean useTLS) {
return mockConsumer;
}
}
@Test
void shouldReuseConsumerInstance() throws Exception {
TestableWrapper wrapper = new TestableWrapper();
DefaultMQPullConsumer first = wrapper.getConsumer(mock(RPCHook.class), true);
assertNotNull(first);
DefaultMQPullConsumer second = wrapper.getConsumer(mock(RPCHook.class), true);
assertSame(first, second);
}
@Test
void shouldHandleStartFailure() throws Exception {
TestableWrapper wrapper = new TestableWrapper();
doThrow(new MQClientException("Simulated error", null))
.when(wrapper.mockConsumer).start();
assertThrows(RuntimeException.class, () ->
wrapper.getConsumer(mock(RPCHook.class), true));
verify(wrapper.mockConsumer).shutdown();
}
@Test
void shouldCloseIdleConsumer() throws Exception {
TestableWrapper wrapper = new TestableWrapper();
wrapper.getConsumer(mock(RPCHook.class), true);
Field lastUsedTime = AutoCloseConsumerWrapper.class.getDeclaredField("lastUsedTime");
lastUsedTime.setAccessible(true);
lastUsedTime.set(wrapper, Instant.now().minusSeconds(70));
wrapper.checkAndCloseIdleConsumer();
verify(wrapper.mockConsumer).shutdown();
}
}