diff --git a/common/config/rush/pnpm-lock.yaml b/common/config/rush/pnpm-lock.yaml index ff9a665868bb..143a48beac07 100644 --- a/common/config/rush/pnpm-lock.yaml +++ b/common/config/rush/pnpm-lock.yaml @@ -14,6 +14,7 @@ dependencies: '@rush-temp/core-paging': 'file:projects/core-paging.tgz' '@rush-temp/core-tracing': 'file:projects/core-tracing.tgz' '@rush-temp/cosmos': 'file:projects/cosmos.tgz' + '@rush-temp/dev-tool': 'file:projects/dev-tool.tgz' '@rush-temp/eslint-plugin-azure-sdk': 'file:projects/eslint-plugin-azure-sdk.tgz' '@rush-temp/event-hubs': 'file:projects/event-hubs.tgz' '@rush-temp/event-processor-host': 'file:projects/event-processor-host.tgz' @@ -580,6 +581,13 @@ packages: dev: false resolution: integrity: sha512-t7uW6eFafjO+qJ3BIV2gGUyZs27egcNRkUdalkud+Qa3+kg//f129iuOFivHDXQ+vnU3fDXuwgv0cqMCbcE8sw== + /@types/chalk/2.2.0: + dependencies: + chalk: 3.0.0 + deprecated: 'This is a stub types definition for chalk (https://github.com/chalk/chalk). chalk provides its own type definitions, so you don''t need @types/chalk installed!' + dev: false + resolution: + integrity: sha512-1zzPV9FDe1I/WHhRkf9SNgqtRJWZqrBWgu7JGveuHmmyR9CnAPCie2N/x+iHrgnpYBIcCJWHBoMRv2TRWktsvw== /@types/color-name/1.1.1: dev: false resolution: @@ -720,6 +728,10 @@ packages: dev: false resolution: integrity: sha512-l+zSbvT8TPRaCxL1l9cwHCb0tSqGAGcjPJFItGGYat5oCTiq1uQQKYg5m7AF1mgnEBzFXGLJ2LRmNjtreRX76Q== + /@types/prettier/2.0.2: + dev: false + resolution: + integrity: sha512-IkVfat549ggtkZUthUzEX49562eGikhSYeVGX97SkMFn+sTZrgRewXjQ4tPKFPCykZHkX1Zfd9OoELGqKU2jJA== /@types/priorityqueuejs/1.0.1: dev: false resolution: @@ -779,10 +791,10 @@ packages: dev: false resolution: integrity: sha512-AOqu6bQu5MSWwYvehMXLukFHnupHrpZ8nvgae5Ggie9UwzDR1CCwoXgSSWNZJuyOlCdfdsWMA5F2LlmvyoTv8A== - /@types/underscore/1.10.5: + /@types/underscore/1.10.6: dev: false resolution: - integrity: sha512-4pI77A5w5QjFFMlEDkcMYN/B3cWACYV++J2wYT15+WcB/om3YJVejzi6i++e/13J7G4rDGNX4HR6QVq9h8fOVQ== + integrity: sha512-kEEmuAxiebFZrkL/si1BaP5/86sHCz491oDeSzRqB7kNokcbxDHKPTuiopj8F8xLl4p09lpiXYkxWZrBZDt41Q== /@types/uuid/8.0.0: dev: false resolution: @@ -1552,6 +1564,15 @@ packages: node: '>=4' resolution: integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== + /chalk/3.0.0: + dependencies: + ansi-styles: 4.2.1 + supports-color: 7.1.0 + dev: false + engines: + node: '>=8' + resolution: + integrity: sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg== /chalk/4.1.0: dependencies: ansi-styles: 4.2.1 @@ -2400,7 +2421,7 @@ packages: ignore: 4.0.6 import-fresh: 3.2.1 imurmurhash: 0.1.4 - inquirer: 7.3.0 + inquirer: 7.3.1 is-glob: 4.0.1 js-yaml: 3.14.0 json-stable-stringify-without-jsonify: 1.0.1 @@ -3151,7 +3172,7 @@ packages: /handlebars/4.7.6: dependencies: minimist: 1.2.5 - neo-async: 2.6.1 + neo-async: 2.6.2 source-map: 0.6.1 wordwrap: 1.0.0 dev: false @@ -3451,7 +3472,7 @@ packages: dev: false resolution: integrity: sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw== - /inquirer/7.3.0: + /inquirer/7.3.1: dependencies: ansi-escapes: 4.3.1 chalk: 4.1.0 @@ -3470,7 +3491,7 @@ packages: engines: node: '>=8.0.0' resolution: - integrity: sha512-K+LZp6L/6eE5swqIcVXrxl21aGDU4S50gKH0/d96OMQnSBCyGyZl/oZhbkVmdp5sBoINHd4xZvFSARh2dk6DWA== + integrity: sha512-/+vOpHQHhoh90Znev8BXiuw1TDQ7IDxWsQnFafUEoK5+4uN5Eoz1p+3GqOj/NtzEi9VzWKQcV9Bm+i8moxedsA== /interpret/1.4.0: dev: false engines: @@ -4706,10 +4727,10 @@ packages: node: '>= 0.6' resolution: integrity: sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw== - /neo-async/2.6.1: + /neo-async/2.6.2: dev: false resolution: - integrity: sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw== + integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== /nested-error-stacks/2.1.0: dev: false resolution: @@ -7551,7 +7572,7 @@ packages: dev: false name: '@rush-temp/ai-text-analytics' resolution: - integrity: sha512-0qtWNE3in6ZnLbonLVPQViYfV5ab8pF9+dZiqta/xszQziRU6maqTTXfHX3H92zfBFLJhkyXuUFp5RRxCRX+yg== + integrity: sha512-vNKSrruEe5u1+admulWPyGLK6E0912jamCYCdZCI/U5Ob+rsT/UAsCBYIB640s55xceAUX1LABQgNMznuqMllQ== tarball: 'file:projects/ai-text-analytics.tgz' version: 0.0.0 'file:projects/app-configuration.tgz': @@ -7608,7 +7629,7 @@ packages: dev: false name: '@rush-temp/app-configuration' resolution: - integrity: sha512-AF3tZ0LP0kLHCPSFZKZiFK8I3YmzBe/dqo8UMcu31ZU6gLIZEt0aUinJ56cNpj5MEZgjBM6DRvCV0sDoXV+RJg== + integrity: sha512-DLfwUvTzl4IBiX0zYSvGYU2EHs23ZyjWli+cYFIYmELY3GFQGZIwjbPnbnafjRZCCVx0QMiI/HAP3HkqS+ehwA== tarball: 'file:projects/app-configuration.tgz' version: 0.0.0 'file:projects/core-amqp.tgz': @@ -8076,7 +8097,7 @@ packages: '@types/semaphore': 1.1.0 '@types/sinon': 9.0.4 '@types/tunnel': 0.0.1 - '@types/underscore': 1.10.5 + '@types/underscore': 1.10.6 '@types/uuid': 8.0.0 '@typescript-eslint/eslint-plugin': 2.34.0_3787943315ebc5ea524d5c102dc9e452 '@typescript-eslint/eslint-plugin-tslint': 2.34.0_f8f62cb1f34b48259c049dd0f60912e9 @@ -8122,6 +8143,35 @@ packages: integrity: sha512-OFXCs9hekvAyYVa+9rX7LfU4X4u3Gil18Ip3gJYvFGfC24rvkxJ3ODKtokBBSPUArJWTFahCXfQCC+2W/59rtg== tarball: 'file:projects/cosmos.tgz' version: 0.0.0 + 'file:projects/dev-tool.tgz': + dependencies: + '@types/chai': 4.2.11 + '@types/chai-as-promised': 7.1.3 + '@types/chalk': 2.2.0 + '@types/fs-extra': 8.1.1 + '@types/minimist': 1.2.0 + '@types/mocha': 7.0.2 + '@types/node': 8.10.61 + '@types/prettier': 2.0.2 + '@typescript-eslint/eslint-plugin': 2.34.0_3787943315ebc5ea524d5c102dc9e452 + '@typescript-eslint/parser': 2.34.0_eslint@6.8.0+typescript@3.9.6 + chai: 4.2.0 + chai-as-promised: 7.1.1_chai@4.2.0 + chalk: 3.0.0 + eslint: 6.8.0 + fs-extra: 8.1.0 + minimist: 1.2.5 + mocha: 7.2.0 + prettier: 1.19.1 + rimraf: 3.0.2 + ts-node: 8.10.2_typescript@3.9.6 + typescript: 3.9.6 + dev: false + name: '@rush-temp/dev-tool' + resolution: + integrity: sha512-5TXnGsXxkseKtD1Uu/f8Ua++Np5VFavRs7Hl4IfMbFGBrbWPxXGJJLs/CJLljI71Q9Dqc5YmxoFbtY3agUTrNQ== + tarball: 'file:projects/dev-tool.tgz' + version: 0.0.0 'file:projects/eslint-plugin-azure-sdk.tgz': dependencies: '@types/bluebird': 3.5.32 @@ -8226,7 +8276,7 @@ packages: dev: false name: '@rush-temp/event-hubs' resolution: - integrity: sha512-mFcVc6WBPBac/+1cHV7l6S98uQlnMNotM1tqKe1kvefV7IMCIpBK+LgUvXGiU88Xqo2a0mjuaIJ5rhYqwavWjw== + integrity: sha512-/pbKrwC/DdUROGXFEIXD+94vdWDwaLpqaAHlgfud7lXmJ24K+v1mMt27evWjVJXyMAwPN7/d6x+eBAV9AYv3bw== tarball: 'file:projects/event-hubs.tgz' version: 0.0.0 'file:projects/event-processor-host.tgz': @@ -8503,7 +8553,7 @@ packages: dev: false name: '@rush-temp/keyvault-certificates' resolution: - integrity: sha512-otmneyGWp0xCx4UwtBqDtU3ufO4PAaG5d6bEXAA4T76s3+cUlqLZtC5Zwqnd/DwnQiWVILhUxAI7OE1HM5EM/A== + integrity: sha512-E6lIroLbv6l4+X7ZM3JFgeEiCPRF+30zH6oxgHy+Gi7e/1tokvvt02N1lBoOn3m6Hybnb9gwSHM3MGDZbX+NAQ== tarball: 'file:projects/keyvault-certificates.tgz' version: 0.0.0 'file:projects/keyvault-common.tgz': @@ -8578,7 +8628,7 @@ packages: dev: false name: '@rush-temp/keyvault-keys' resolution: - integrity: sha512-jzriUWCWYbtt/6Gqu1CLcaBoJ/v0kzeoW/JNV3riquZc7vgIhJsJzOW3FwIjiWyUUNePgNWxdATyW3e6NR/MEA== + integrity: sha512-N3sTisoY5cFP3AN4h3lB2uDVXTjbzXsdl95nstsB+oPc+epFqFMSfC+qw/aub3sWdmvNOhoAbvcZhit2TpJW2w== tarball: 'file:projects/keyvault-keys.tgz' version: 0.0.0 'file:projects/keyvault-secrets.tgz': @@ -8643,7 +8693,7 @@ packages: dev: false name: '@rush-temp/keyvault-secrets' resolution: - integrity: sha512-4QvZ/dB/AaMMJbqK7pKQcYfjcBWdhYgxZrRkta9Bd7Y3DZyTIUGCjxnWDZa4CyyV1BQSDY/rpAlnCneQQZZGjg== + integrity: sha512-iE+V14zIXSxoADbKEAjZYJDZHKg9jehqqcyHq2iL4Tgj7JB8t2+llOToEgHYVXhQAYHOxuIaU3WeNYbGVHBdJQ== tarball: 'file:projects/keyvault-secrets.tgz' version: 0.0.0 'file:projects/logger.tgz': @@ -8755,7 +8805,7 @@ packages: dev: false name: '@rush-temp/search-documents' resolution: - integrity: sha512-d2Mn4FQL/FzuxABfvT9scg1+vRrfZ4c66sFtyYjrIybU4B37YLx3bryrj+Ufc8+m+kcZcb+kHzon2Pr41h47fQ== + integrity: sha512-Z7F/kLEKb6jEh6v8SxNrLM3JjWdeYQqkwIlCqBl3QdR26TIE4i2lmd6WzSyiayINgGf8S+kfrkJHKFpyIGEWsg== tarball: 'file:projects/search-documents.tgz' version: 0.0.0 'file:projects/service-bus.tgz': @@ -8831,7 +8881,7 @@ packages: dev: false name: '@rush-temp/service-bus' resolution: - integrity: sha512-wSAmks1T5tOckF82dT10wTLXXNblVKFh9YPilOMKyWGKQ32c1A23vPmY2NgUDLA9AkIjRuH+diL1Hqam3/Wh2g== + integrity: sha512-Uxr+OzhSFHuuJEcrE67tBrdQWk7t1wQa/+dzl3TPqPB7xYLMB8L67kTVjNqZ5mJDqhZFwA/ubvmnq9XYHdYE3g== tarball: 'file:projects/service-bus.tgz' version: 0.0.0 'file:projects/storage-blob-changefeed.tgz': @@ -8955,7 +9005,7 @@ packages: dev: false name: '@rush-temp/storage-blob' resolution: - integrity: sha512-LfZzexxvRVT+n4a8BRQPyqsMk2vFdcj2vjzEP6dlehaE/3/Ctn+H73c27Bex9bL4db0lqCAsTjs2y1vYorimKg== + integrity: sha512-RxvkBuFDKdLJiG37sHP13er+P+SmR4Ro1mrZ+Gh6Zxjw3REYSbhlp2tssbV4OTTw8oLJW0YWUdzuZLPSR/r4hA== tarball: 'file:projects/storage-blob.tgz' version: 0.0.0 'file:projects/storage-file-datalake.tgz': @@ -9082,7 +9132,7 @@ packages: dev: false name: '@rush-temp/storage-file-share' resolution: - integrity: sha512-QFP/fGUT9mKykve7C2bnti+/smhZKVn1k5KGiHh7690AmVTiPU6cov+bRNX0ZBBenKgQZi8tfPC3iiBgyKnVZg== + integrity: sha512-EwD/REe6mLYBeRNNA0z4xq4JiQZfaVItDorSiZ9exXByB2EuaLP7fI6sYQXLA60jG2BSm8BUaoz9tl2Y4WlVpg== tarball: 'file:projects/storage-file-share.tgz' version: 0.0.0 'file:projects/storage-internal-avro.tgz': @@ -9200,7 +9250,7 @@ packages: dev: false name: '@rush-temp/storage-queue' resolution: - integrity: sha512-CEsnZhmug0x5p73wkOC0kuGuQ/H+6/d7XoRB1Rs7iAfxytJXiDgRQDy72OeZo8RmfHDtHdpy+k+rp766YpKk/g== + integrity: sha512-yBcozJGh3VBVKs6OB4s6z5G8HXrv1jTIqNw7P0SAZZ8ihz/gKp+vJ01QZKkH53DK0gfgM1PdwWhjdm8ZFtl9pg== tarball: 'file:projects/storage-queue.tgz' version: 0.0.0 'file:projects/tables.tgz': @@ -9428,6 +9478,7 @@ specifiers: '@rush-temp/core-paging': 'file:./projects/core-paging.tgz' '@rush-temp/core-tracing': 'file:./projects/core-tracing.tgz' '@rush-temp/cosmos': 'file:./projects/cosmos.tgz' + '@rush-temp/dev-tool': 'file:./projects/dev-tool.tgz' '@rush-temp/eslint-plugin-azure-sdk': 'file:./projects/eslint-plugin-azure-sdk.tgz' '@rush-temp/event-hubs': 'file:./projects/event-hubs.tgz' '@rush-temp/event-processor-host': 'file:./projects/event-processor-host.tgz' diff --git a/common/scripts/prep-samples.js b/common/scripts/prep-samples.js deleted file mode 100644 index 6c521c039c29..000000000000 --- a/common/scripts/prep-samples.js +++ /dev/null @@ -1,209 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. - -/** - * prep-samples.js - * - * Prepares sample files for execution in CI by replacing abosolute package imports with relative - * imports. This is useful because it allows us to check in "camera-ready" copies of our samples - * so that they can be ingested directly into external documentation pipelines, while still allowing - * us to compile and run our samples in CI. - * - * Usage: node prep-samples.js [PACKAGE PATH] - * - PACKAGE PATH should be set to the directory of a `package.json` for a package that contains - * TypeScript samples. - * - If PACKAGE PATH is not specified, CWD will be used - * - * The command expects to find a directory tree `samples/typescript` under PACKAGE PATH. - * - * WARNING: This script ___WILL NOT___ revert changes it makes to the samples. Make sure any staged - * changes you have made to the samples are committed to git or otherwise preserved, as this script - * will completely overwrite them! - */ - -const baseFS = require("fs"); -const path = require("path"); -const promisify = require("util").promisify; - -const exec = promisify(require("child_process").execFile); - -// Node >= 10 provide fs.promises, but since we're still building Node 8 for now -// we need to use util.promisify if fs.promises doesn't exist -const fs = - baseFS.promises || - (() => { - return { - readdir: promisify(baseFS.readdir), - readFile: promisify(baseFS.readFile), - writeFile: promisify(baseFS.writeFile) - }; - })(); - -/** - * Breadth-first search for files matching a given predicate - * - * @param {string} dir The root of the sample tree to search - * @param {(fs.Entry) => boolean} matches Predicate that decides whether or not a file entry is included - * @returns - */ -async function* findMatchingFiles(dir, matches) { - const initialFiles = await fs.readdir(dir, { withFileTypes: true }); - - // BFS Queue and queue index - const q = initialFiles.map(f => [f, dir]); - - while (q.length) { - // [fs.Dirent, string] (file and dirName part of the full path) - const [entry, dirName] = q.shift(); - const fullPath = path.join(dirName, entry.name); - - if (entry.isDirectory()) { - // Enqueue children of this directory to the bfs - const children = await fs.readdir(fullPath, { withFileTypes: true }); - for (const child of children) { - q.push([child, fullPath]); - } - } else if (matches(entry)) { - yield fullPath; - } else if ( - entry.isBlockDevice() || - entry.isCharacterDevice() || - entry.isFIFO() || - entry.isSocket() || - entry.isSymbolicLink() - ) { - console.warn( - "[prep-samples] WARNING: Encountered a special file in the sample tree. Skipping:", - fullPath - ); - } - } - - // The full trace of files visited by the iterator is returned and can be accessed using `iter.value` - // once it is `done`, in case it is ever needed for debugging - return q; -} - -/** - * Replaces package require/import statements with relative paths for CI - * - * @param {string} fileName the name of the file to open and process - * @param {string} baseDir the base directory of the package - * @param {string} pkgName name of the package to use when looking for package-local imports - */ -async function enableLocalRun(fileName, baseDir, pkgName) { - const fileContents = await fs.readFile(fileName, { encoding: "utf-8" }); - const isTs = fileName.endsWith(".ts"); - const importRegex = isTs - ? new RegExp(`import\\s+(.*)\\s+from\\s+"${pkgName}";?\\s?`, "s") - : new RegExp(`const\\s+(.*)\\s*=\\s*require\\("${pkgName}"\\);?\\s?`, "s"); - - if (!importRegex.exec(fileContents)) { - // With the newer methods of using helper files and batch running, this - // should be a warning - console.warn( - `[prep-samples] skipping ${fileName} because it did not contain a matching import/require` - ); - return; - } - - const relativeDir = path.dirname(fileName.replace(baseDir, "")); - - // `string.length - string.split(path.sep).join("").length` is a dirty but well-supported way to - // count the depth of a path and that avoids the difficulty of creating a regexp constructor - // that can escape both linux and windows path separators - const depth = - relativeDir.length - relativeDir.split(path.sep).join("").length; - - let relativePath = new Array(depth).fill("..").join("/"); - - if (isTs) { - // TypeScript imports should use src directly - relativePath += "/src"; - } - - const importRenamedContents = fileContents.replace( - importRegex, - isTs - ? `import $1 from "${relativePath}";` - : `const $1 = require("${relativePath}");` - ); - - // Remove trailing call to main() - const updatedContents = importRenamedContents.replace( - new RegExp("main\\(\\)\\.catch.*", "s"), - isTs ? "" : "module.exports = { main };\n" - ); - - console.log("[prep-samples] Updating imports in", fileName); - return fs.writeFile(fileName, updatedContents, { encoding: "utf-8" }); -} - -async function main() { - // Accept a base directory (package directory) as an argument or use CWD - const args = process.argv.slice(2); - - let baseDir; - if (args.length) { - baseDir = path.resolve(args[0]); - } else { - baseDir = process.cwd(); - } - - const package = require(path.join(baseDir, "package.json")); - console.log( - "[prep-samples] Preparing samples for package:", - `${package.name}@${package.version}` - ); - - // Check if the package samples directory is dirty using git - // Refuse to proceed if this script may overwrite changes to samples. - try { - const gitDiff = await exec("git", [ - "status", - "-s", - path.join(baseDir, "samples") - ]); - if (gitDiff.stdout !== "") { - console.error( - "[prep-samples] Error: The samples tree is dirty. Refusing to continue." - ); - console.error( - "[prep-samples] Stash or commit your changes to the following files:" - ); - for (const line of gitDiff.stdout.trim().split("\n")) { - console.error(" -", line); - } - process.exit(1); - } - } catch (err) { - console.error( - "[prep-samples] Error: Failed to check the git status. Refusing to continue." - ); - process.exit(1); - } - - const tsDir = path.join(baseDir, "samples", "typescript", "src"); - for await (const fileName of findMatchingFiles( - tsDir, - entry => - entry.isFile() && - entry.name.endsWith(".ts") && - !entry.name.endsWith(".d.ts") - )) { - await enableLocalRun(fileName, baseDir, package.name); - } - - const jsDir = path.join(baseDir, "samples", "javascript"); - for await (const fileName of findMatchingFiles( - jsDir, - entry => entry.isFile() && entry.name.endsWith(".js") - )) { - await enableLocalRun(fileName, baseDir, package.name); - } -} - -main().catch(err => { - console.error("[prep-samples]", err); - process.exit(1); -}); diff --git a/common/scripts/run-samples.js b/common/scripts/run-samples.js deleted file mode 100644 index aeabbbc7b552..000000000000 --- a/common/scripts/run-samples.js +++ /dev/null @@ -1,115 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. - -/** - * run-samples.js - * - * Runs all JavaScript files in a directory, using the calling convention for - * our sample code. - */ - -const baseFS = require("fs"); -const path = require("path"); - -const IGNORE = ["node_modules"]; - -// Node >= 10 provide fs.promises, but since we're still building Node 8 for now -// we need to use util.promisify if fs.promises doesn't exist -const fs = - baseFS.promises || - (() => { - const promisify = require("util").promisify; - return { - readdir: promisify(baseFS.readdir) - }; - })(); - -/** - * Breadth-first search for files matching a given predicate - * - * @param {string} tsDir The root of the sample tree to search - * @param {(fs.Entry) => boolean} matches Predicate that decides whether or not a file entry is included - * @returns - */ -async function* findMatchingFiles(tsDir, matches) { - const initialFiles = await fs.readdir(tsDir, { withFileTypes: true }); - - // BFS Queue and queue index - const q = initialFiles.map(f => [f, tsDir]); - - while (q.length) { - // [fs.Dirent, string] (file and dirName part of the full path) - const [entry, dirName] = q.shift(); - const fullPath = path.join(dirName, entry.name); - - if (IGNORE.includes(entry.name)) { - console.log("[run-samples] Ignoring", fullPath); - continue; - } - - if (entry.isDirectory()) { - // Enqueue children of this directory to the bfs - const children = await fs.readdir(fullPath, { withFileTypes: true }); - for (const child of children) { - q.push([child, fullPath]); - } - } else if (matches(entry)) { - yield fullPath; - } - } - - // The full trace of files visited by the iterator is returned and can be accessed using `iter.value` - // once it is `done`, in case it is ever needed for debugging - return q; -} - -async function main() { - // Accept a base directory - const args = process.argv.slice(2); - - let sampleDir; - if (args.length) { - sampleDir = path.resolve(args[0]); - } else { - sampleDir = process.cwd(); - } - - // Patch the environment for the sample helper - process.env.BATCH_RUN_SAMPLES = "true"; - - console.log("[run-samples] Running all samples in:", sampleDir); - - let errors = []; - - for await (const fileName of findMatchingFiles( - sampleDir, - entry => entry.isFile() && entry.name.endsWith(".js") - )) { - console.log("[run-samples] Running", fileName); - const { main: sampleMain } = require(fileName); - try { - await sampleMain(); - } catch (err) { - const truncatedError = err - .toString() - .split("\n")[0] - .slice(0, 100); - errors.push([path.basename(fileName), truncatedError]); - console.warn("[run-samples] Error in", fileName, ":", err); - console.warn("[run-samples] Continuing ..."); - } - } - - if (errors.length > 0) { - console.error("[run-samples] Errors occurred in the following files:"); - for (const [fileName, error] of errors) { - console.error(" -", fileName, "(", error, ")"); - } - process.exit(1); - } -} - -main().catch(err => { - console.error("[run-samples] Error:", err); - process.exit(1); -}); diff --git a/common/tools/dev-tool/.eslintrc.json b/common/tools/dev-tool/.eslintrc.json new file mode 100644 index 000000000000..5b9e539283c0 --- /dev/null +++ b/common/tools/dev-tool/.eslintrc.json @@ -0,0 +1,12 @@ +{ + "parser": "@typescript-eslint/parser", + "plugins": ["@typescript-eslint"], + "extends": [ + "eslint:recommended", + "plugin:@typescript-eslint/eslint-recommended", + "plugin:@typescript-eslint/recommended" + ], + "rules": { + "@typescript-eslint/explicit-function-return-type": "off" + } +} diff --git a/common/tools/dev-tool/README.md b/common/tools/dev-tool/README.md new file mode 100644 index 000000000000..a64d9d8516c7 --- /dev/null +++ b/common/tools/dev-tool/README.md @@ -0,0 +1,201 @@ +# @azure/dev-tool + +`dev-tool` is an extensible command-line utility for Azure SDK for JS contributors. + +It provides a place to centralize scripts, resources, and processes for development of the Azure SDK for JavaScript. It is its own unpublished package and has the ability to use dependencies that are managed with Rush in the development process, and it is written in TypeScript. + +## Installation + +`dev-tool` runs using ts-node, so it does not need to be built. It is ready-to-go after a `rush update`. It additionally does not need to be installed to a user's machine in order to be used in `package.json` scripts, since it provides the `dev-tool` binary to any dependent packages through the `bin` entry in its `package.json`. Simply add `@azure/dev-tool` to the `devDependencies` of a package, and the `dev-tool` binary will become available. If you wish to use `dev-tool` from the CLI manually, you can install it globally on your system by running `npm install -g` from this directory. + +## Usage + +`dev-tool` uses a command hierarchy. For example, at the time of writing, the command tree looks like this: + +`dev-tool` + - `about` (display command help and information) + - `package` + - `resolve` (display information about the project that owns a directory) + - `samples` + - `dev` (link samples to local sources for access to IntelliSense during development) + - `prep` (prepare samples for local source-linked execution) + - `run` (execute a sample or all samples within a directory) + +The `dev-tool about` command will print some information about how to use the command. All commands additionally accept the `--help` argument, which will print information about the usage of that specific command. For example, to show help information for the `resolve` command above, issue the command `dev-tool package resolve --help`. + +## Extending the Tool + +The source hierarchy matches the command hierarchy. Every sub-command has its own folder and `index.ts` file in `src/commands`, where `src/commands/index.ts` defines the behavior of the root `dev-tool` command, and each subfolder's `index.ts` file describes a nested sub-command. Every leaf node in the command tree ("leaf command") has its own TypeScript file. For example, `src/commands/about.ts` defines the behavior of the `dev-tool about` command, and `src/commands/package/resolve.ts` defines the behavior of the `dev-tool package resolve` command. + +### Command Interface + +Every command file's exports must implement the `CommandModule` interface defined in `src/util/commandModule.ts`. The interface requires that every command export a constant `commandInfo` that implements the `CommandInfo` interface defined in the same file. A helper command `makeCommandInfo` is provided to assist with the creation of this interface while providing strong type-checking of command-line options. The `CommandInfo` interface specifies the name, description, and options (command-line arguments) of the command. The command module must also export an async handler function as its default export. Two helper functions, `leafCommand` and `subCommand` are provided to assist with development and to provide strong type-checking when +extending dev-tool. + +### Creating a new leaf command + +To create a new leaf command in one of the existing sub-command, create a new TypeScript file for that command. Make sure that your module exports the required `commandInfo` and default handler function. When creating the `commandInfo` object, use the `makeCommandInfo` helper function. When creating a command, use the `leafCommand` helper to get a strongly-typed `options` parameter for your handler. + +As an example, we can create a new `hello-world` command under the `dev-tool package` sub-command. The command will print out a string using the many different logging functions. It will accept an argument `--echo ` that specifies the string to be printed. + +`src/commands/package/hello-world.ts` +```typescript +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license + +import { createPrinter } from "../../util/printer"; +import { leafCommand, makeCommandInfo } from "../../framework/command"; + +const log = createPrinter("hello-world"); + +export const commandInfo = makeCommandInfo("hello-world", "print a lovely message", { + echo: { + kind: "string", + description: "override the message to be printed", + default: "Hello world!" + } +}); + +export default leafCommand(commandInfo, async (options) => { + // Demonstrate the colorized command output. + log("Normal:", options.echo); + log.success("Success:", options.echo); + log.info("Info:", options.echo); + log.warn("Warn:", options.echo); + log.error("Error:", options.echo); + log.debug("Debug:", options.echo); + + return true; +}); +``` + +(__Note__: using the `makeCommandInfo` function is required to have strong type-checking on the `options` parameter of the handler. The `options` field of `commandInfo` must have a very strong type, and `makeCommandInfo` takes care of ensuring that the type is as strongly specified as possible.) + +As a last step, add a mapping for the `"hello-world"` command to the sub-command map in `src/commands/package/index.ts`. This will allow the command to resolve: + +`src/commands/package/index.ts` +```typescript +// ... + +export default subCommand(commandInfo, { + "hello-world": () => import("./hello-world"), + // ... rest of the sub-commands still here +}); +``` + +At this point, the command is ready. When using `leafCommand` or `subCommand`, parsing and handling of arguments, including the `--help` output will be handled automatically by the command infrastructure. Debug output will only be shown if the `DEBUG` environment variable is set. Try it out: + +- Use `dev-tool package hello-world` to see the default output of the command +- Use `DEBUG=true dev-tool package hello-world` to see the full debugging output +- Use `dev-tool package hello-world --help` to view the generated help pages and make sure they are correct +- Use `dev-tool package hello-world --echo ` to change the default `"Hello world!"` text to something else. +- Use `dev-tool package --help` to see the `hello-world` command in the help message of its parent command + +### Creating a new command with sub-commands + +To create a new branching sub-command, create a new folder in the source tree and add an `index.ts` file. The folder should be named the same as the new command. The `subCommand` helper function can assist with creating a branching command. + +As an example, we can convert the `hello-world` example above into a branching command `hello` with a single sub-command `world`. Instead of adding it to the `package` sub-command, we will add it to the root `dev-tool` command. + +Instead of creating a single file `hello-world.ts`, we will instead create a folder `src/commands/hello` and two ts files: `src/commands/hello/index.ts` and `src/commands/hello/world.ts`. In `src/commands/hello/index.ts`, we can define our new sub-command: + +`src/commands/hello/index.ts` +```typescript +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license + +import { subCommand, makeCommandInfo } from "../../framework/command"; + +export const commandInfo = makeCommandInfo("hello", "commands for printing some lovely messages"); + +export default subCommand(commandInfo, { + world: () => import("./world") +}); +``` + +(__Note__: Since we don't have any arguments or options to add to the sub-command, the `options` argument to `makeCommandInfo` is omitted (since the sub-command just delegates to its child commands, we wouldn't be able to use any options in this parent command anyway).) + +This simple file establishes the mapping from the command name `"world"` to our new command module `src/commands/hello/world.ts`. The contents of `world.ts` are very similar to the previous `hello-world.ts` module, but we will change the `name` field of `commandInfo` and the argument to `createPrinter`: + +`src/commands/hello/world.ts` +```typescript +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license + +import { createPrinter } from "../../util/printer"; +import { leafCommand, makeCommandInfo } from "../../framework/command"; + +const log = createPrinter("world"); + +export const commandInfo = makeCommandInfo("world", "print a lovely message", { + echo: { + kind: "string", + description: "override the message to be printed", + default: "Hello world!" + }}); + +export default leafCommand(commandInfo, async (options) => { + // Demonstrate the colorized command output. + log("Normal:", options.echo); + log.success("Success:", options.echo); + log.info("Info:", options.echo); + log.warn("Warn:", options.echo); + log.error("Error:", options.echo); + log.debug("Debug:", options.echo); + + return true; +}); +``` + +The final step is to add a mapping to our new subcommand to the`baseCommands` map root `src/commands/index.ts` file: + +`src/commands/index.ts` +```typescript +// ... + +/** + * All of dev-tool's base commands and the modules that define them + */ +export const baseCommands = { + "hello": () => import("./hello") + // ... all other sub-commands still here +} as const; + +// ... +``` + +(__Note__: If we were adding our `hello` command to another sub-command rather than the root, we would just add it to that sub-command's `index.ts` instead of the root `src/commands/index.ts`, similar to how we added `hello-world` to `src/commands/package/index.ts` in the previous example.) + +### Understanding the Options Type + +When using `leafCommand`, the handler function takes a value `options` with a type that is generated from the `options` property of the `CommandInfo` object given as the first argument to `leafCommand`. The underlying parsing behavior is implemented by `minimist` and is validated in the `parseOptions` function in `src/util/commandBuilder.ts`. + +The structure of the `CommandInfo.options` field is a map from option names to a tagged union that supports three variants (using the "kind" property as the disciminant): + +- `"string"` for command-line flags that have a string value (for example, `--directory path/to/directory`) +- `"boolean"` for command-line flags that have a boolean value (for example, `--quiet` with no argument) +- `"multistring"` for command-line flags that have string values and may be specified more than once (for example, `--add-dir path/to/dir1 --add-dir path/to/dir2`) + +Each variant supports an optional `shortName` field that specifies a one-letter command alias (e.g. a value of `shortName: "d"` would make `-d` an alias of the `--directory` option above). Each also has an optional `default` parameter to specify the default value should the argument not be specified on the command-line. If no default value is provided, the type of the `options` value passed to the handler will be expanded to include `undefined` as a possible value. Finally, each option has a `description` field that includes the help text shown in the messages produced by `--help`. + +### Final Developer Notes + +- Using the `subCommand` and `leafCommand` helpers is not required. If a command module exports any function with the signature `(...args: string[]) => Promise` as its default export, it will run when the command is invoked and will be given the arguments passed in the parameters. __However__, only `subCommand` and `leafCommand` provide automatic argument parsing and handling of `--help`. The functions used to provide this behavior are located in the `src/util/commandBuilder.ts` module. +- Some additional helper modules can be found in `src/util` such as `resolveProject.ts` which walks up the directory hierarchy and finds the absolute path of the nearest SDK package directory (useful for commands like `samples` which always operate relative to the package directory) +- The tool runs using the `transpileOnly` option in the `ts-node` configuration, meaning it does not perform run-time type-checking. The build step of the package will run type-checking using `tsc`, so to check the tool's code for type errors, simply use `rushx build`. + +## Contributing + +This project welcomes contributions and suggestions. Most contributions require you to agree to a +Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us +the rights to use your contribution. For details, visit https://cla.microsoft.com. + +When you submit a pull request, a CLA-bot will automatically determine whether you need to provide +a CLA and decorate the PR appropriately (e.g., label, comment). Simply follow the instructions +provided by the bot. You will only need to do this once across all repos using our CLA. + +This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). +For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or +contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. + +If you'd like to contribute to this library, please read the [contributing guide](https://github.com/Azure/azure-sdk-for-js/blob/master/CONTRIBUTING.md) to learn more about how to build and test the code. diff --git a/common/tools/dev-tool/launch.js b/common/tools/dev-tool/launch.js new file mode 100755 index 000000000000..908d0971110a --- /dev/null +++ b/common/tools/dev-tool/launch.js @@ -0,0 +1,17 @@ +#!/usr/bin/env node + +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +const path = require("path"); + +if (process.env.DEBUG) { + console.info("Azure SDK for JS dev-tool: bootstrapping from", __dirname); +} + +// Shim to invoke true typescript source +require("ts-node").register({ + transpileOnly: true, + project: path.join(__dirname, "tsconfig.json") +}); +require(path.join(__dirname, "src", "index.ts")); diff --git a/common/tools/dev-tool/package.json b/common/tools/dev-tool/package.json new file mode 100644 index 000000000000..a019a27f1272 --- /dev/null +++ b/common/tools/dev-tool/package.json @@ -0,0 +1,61 @@ +{ + "name": "@azure/dev-tool", + "version": "1.0.0", + "description": "A helpful command for azure-sdk-for-js developers", + "bin": { + "dev-tool": "launch.js" + }, + "files": [ + "src" + ], + "scripts": { + "audit": "node ../../../common/scripts/rush-audit.js && rimraf node_modules package-lock.json && npm i --package-lock-only 2>&1 && npm audit", + "build": "tsc", + "build:test": "echo skipped", + "clean": "rimraf dist dist-* *.tgz *.log", + "extract-api": "echo skipped", + "format": "prettier --write src/**/*.ts test/**/*.ts *.{js,json}", + "integration-test:browser": "echo skipped", + "integration-test:node": "echo skipped", + "lint": "eslint src test --ext .ts -f html -o template-lintReport.html || exit 0", + "pack": "npm pack 2>&1", + "prebuild": "npm run clean", + "unit-test": "mocha --require ts-node/register test/**/*.spec.ts" + }, + "repository": "github:Azure/azure-sdk-for-js", + "author": "Microsoft Corporation", + "license": "MIT", + "bugs": { + "url": "https://github.com/azure/azure-sdk-for-js/issues" + }, + "homepage": "https://github.com/azure/azure-sdk-for-js/tree/master/common/tools/dev-tool", + "sideEffects": false, + "private": true, + "prettier": "@azure/eslint-plugin-azure-sdk/prettier.json", + "dependencies": { + "chalk": "~3.0.0", + "fs-extra": "^8.1.0", + "minimist": "~1.2.5", + "prettier": "^1.16.4", + "ts-node": "^8.3.0", + "typescript": "~3.9.3" + }, + "devDependencies": { + "@azure/eslint-plugin-azure-sdk": "^3.0.0", + "@types/chai": "^4.1.6", + "@types/chai-as-promised": "^7.1.0", + "@types/chalk": "~2.2.0", + "@types/fs-extra": "^8.0.0", + "@types/minimist": "~1.2.0", + "@types/mocha": "^7.0.2", + "@types/node": "^8.0.0", + "@types/prettier": "~2.0.1", + "@typescript-eslint/eslint-plugin": "^2.0.0", + "@typescript-eslint/parser": "^2.0.0", + "chai": "^4.2.0", + "chai-as-promised": "^7.1.1", + "eslint": "^6.1.0", + "mocha": "^7.1.1", + "rimraf": "^3.0.0" + } +} diff --git a/common/tools/dev-tool/src/commands/about.ts b/common/tools/dev-tool/src/commands/about.ts new file mode 100644 index 000000000000..9a6187f1c713 --- /dev/null +++ b/common/tools/dev-tool/src/commands/about.ts @@ -0,0 +1,51 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license + +import chalk from "chalk"; + +import { baseCommands, baseCommandInfo } from "."; +import { resolveProject } from "../util/resolveProject"; +import { createPrinter } from "../util/printer"; +import { leafCommand, makeCommandInfo } from "../framework/command"; +import { printCommandUsage } from "../framework/printCommandUsage"; + +const log = createPrinter("help"); + +const banner = `\ + _______ __ __ __ + / / ___/ ____/ /__ _ __ / /_____ ____ / / + __ / /\\__ \\ / __ / _ \\ | / /_____/ __/ __ \\/ __ \\/ / +/ /_/ /___/ / / /_/ / __/ |/ /_____/ /_/ /_/ / /_/ / / +\\____//____/ \\__,_/\\___/|___/ \\__/\\____/\\____/_/ + +Developer quality-of-life command for the Azure SDK for JS +`; + +export const commandInfo = makeCommandInfo("about", "display command help and information"); + +export default leafCommand(commandInfo, async (options) => { + console.log(chalk.blueBright(banner)); + + try { + const packageInfo = await resolveProject(__dirname); + console.log(chalk.blueBright(` Name/Version:\t${packageInfo.name}@${packageInfo.version}`)); + console.log(chalk.blueBright(` Location:\t${packageInfo.path}`)); + console.log(); + } catch (error) { + log.error("Could not locate dev-tool package."); + log.error("Unable to display dev-tool version information."); + } + + if (options.args.length || options["--"]?.length) { + console.log(); + log.warn("Warning, unused options:", JSON.stringify(options)); + } + + await printCommandUsage(baseCommandInfo, baseCommands); + + console.log("For more information about a given command, try `dev-tool COMMAND --help`"); + + console.log(); + + return true; +}); diff --git a/common/tools/dev-tool/src/commands/index.ts b/common/tools/dev-tool/src/commands/index.ts new file mode 100644 index 000000000000..6d157d8fe941 --- /dev/null +++ b/common/tools/dev-tool/src/commands/index.ts @@ -0,0 +1,23 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license + +import { subCommand, makeCommandInfo } from "../framework/command"; + +/** + * All of dev-tool's base commands and the modules that define them + */ +export const baseCommands = { + about: () => import("./about"), + package: () => import("./package"), + samples: () => import("./samples") +} as const; + +/** + * Metadata about the base command, only used in `dev-tool help` + */ +export const baseCommandInfo = makeCommandInfo("dev-tool", "Azure SDK for JS dev-tool"); + +/** + * Default dev-tool subcommand + */ +export const baseCommand = subCommand(baseCommandInfo, baseCommands); diff --git a/common/tools/dev-tool/src/commands/package/index.ts b/common/tools/dev-tool/src/commands/package/index.ts new file mode 100644 index 000000000000..4badd034bf05 --- /dev/null +++ b/common/tools/dev-tool/src/commands/package/index.ts @@ -0,0 +1,10 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license + +import { subCommand, makeCommandInfo } from "../../framework/command"; + +export const commandInfo = makeCommandInfo("package", "manage SDK packages in the monorepo"); + +export default subCommand(commandInfo, { + resolve: () => import("./resolve") +}); diff --git a/common/tools/dev-tool/src/commands/package/resolve.ts b/common/tools/dev-tool/src/commands/package/resolve.ts new file mode 100644 index 000000000000..e5e2d33116c4 --- /dev/null +++ b/common/tools/dev-tool/src/commands/package/resolve.ts @@ -0,0 +1,51 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license + +import path from "path"; + +import { resolveProject } from "../../util/resolveProject"; +import { createPrinter } from "../../util/printer"; +import { leafCommand } from "../../framework/command"; +import { makeCommandInfo } from "../../framework/command"; + +const log = createPrinter("resolve-package"); + +export const commandInfo = makeCommandInfo( + "resolve", + "display information about the project that owns a directory", + { + directory: { + shortName: "d", + kind: "string", + description: "base directory for resolution (uses CWD if unset)", + allowMultiple: true + }, + quiet: { + shortName: "q", + kind: "boolean", + default: false, + description: "output only the directory name with no extra formatting" + } + } +); + +export default leafCommand(commandInfo, async (options) => { + const dirs = (options.directory ?? [process.cwd()]).map((p) => path.resolve(p)); + for (const dir of dirs) { + try { + const currentPackage = await resolveProject(dir); + if (options.quiet) { + console.log(currentPackage.path); + } else { + log.success("== Detected package:", currentPackage.name); + log.info(`Version specifier: ${currentPackage.name}@${currentPackage.version}`); + log.info(`Location: ${path.resolve(dir, currentPackage.path)}`); + } + } catch (error) { + log.error("Could not find package starting from", dir); + log.error(error); + } + } + + return true; +}); diff --git a/common/tools/dev-tool/src/commands/samples/dev.ts b/common/tools/dev-tool/src/commands/samples/dev.ts new file mode 100644 index 000000000000..574ef5ab044b --- /dev/null +++ b/common/tools/dev-tool/src/commands/samples/dev.ts @@ -0,0 +1,38 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +import fs from "fs-extra"; +import path from "path"; + +import { resolveProject } from "../../util/resolveProject"; +import { createPrinter } from "../../util/printer"; +import { leafCommand, makeCommandInfo } from "../../framework/command"; + +const log = createPrinter("dev-samples"); + +export const commandInfo = makeCommandInfo( + "dev", + "link samples to local sources for access to IntelliSense during development" +); + +export default leafCommand(commandInfo, async () => { + const pkg = await resolveProject(process.cwd()); + + const relativeLinkName = path.join("samples", "typescript", "node_modules", pkg.name); + const linkName = path.join(pkg.path, relativeLinkName); + const relativeLinkTarget = path.relative(linkName, path.join(pkg.path, "samples")); + + await fs.ensureDir(path.dirname(linkName)); + + if (fs.existsSync(linkName)) { + log.error("Link already exists:", linkName); + log.error("Make sure your samples tree is pristine before running dev-samples."); + return false; + } + + log.info(`Linking ${relativeLinkName} to ${relativeLinkTarget}`); + + await fs.symlink(relativeLinkTarget, linkName); + + return true; +}); diff --git a/common/tools/dev-tool/src/commands/samples/index.ts b/common/tools/dev-tool/src/commands/samples/index.ts new file mode 100644 index 000000000000..f93af14611cf --- /dev/null +++ b/common/tools/dev-tool/src/commands/samples/index.ts @@ -0,0 +1,13 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license + +import { subCommand, makeCommandInfo } from "../../framework/command"; + +export const commandInfo = makeCommandInfo("samples", "manage samples in an SDK package"); + +export default subCommand(commandInfo, { + dev: () => import("./dev"), + prep: () => import("./prep"), + run: () => import("./run"), + "ts-to-js": () => import("./tsToJs") +}); diff --git a/common/tools/dev-tool/src/commands/samples/prep.ts b/common/tools/dev-tool/src/commands/samples/prep.ts new file mode 100644 index 000000000000..47990faffc71 --- /dev/null +++ b/common/tools/dev-tool/src/commands/samples/prep.ts @@ -0,0 +1,109 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +import fs from "fs-extra"; +import path from "path"; + +import { createPrinter } from "../../util/printer"; +import { findMatchingFiles } from "../../util/findMatchingFiles"; +import { resolveProject } from "../../util/resolveProject"; +import { leafCommand, makeCommandInfo } from "../../framework/command"; + +const log = createPrinter("prep-samples"); + +export const commandInfo = makeCommandInfo( + "prep", + "prepare samples for local source-linked execution" +); + +/** + * Replaces package require/import statements with relative paths for CI + * + * @param fileName the name of the file to open and process + * @param baseDir the base directory of the package + * @param pkgName name of the package to use when looking for package-local imports + */ +async function enableLocalRun(fileName: string, baseDir: string, pkgName: string) { + const fileContents = await fs.readFile(fileName, { encoding: "utf-8" }); + const isTs = fileName.endsWith(".ts"); + const importRegex = isTs + ? new RegExp(`import\\s+(.*)\\s+from\\s+"${pkgName}";?\\s?`, "s") + : new RegExp(`const\\s+(.*)\\s*=\\s*require\\("${pkgName}"\\);?\\s?`, "s"); + + if (!importRegex.exec(fileContents)) { + // With the newer methods of using helper files and batch running, this + // should be a warning + log.warn(`skipping ${fileName} because it did not contain a matching import/require`); + return; + } + + const relativeDir = path.dirname(fileName.replace(baseDir, "")); + + // `string.length - string.split(path.sep).join("").length` is a dirty but well-supported way to + // count the depth of a path and that avoids the difficulty of creating a regexp constructor + // that can escape both linux and windows path separators + const depth = relativeDir.length - relativeDir.split(path.sep).join("").length; + + let relativePath = new Array(depth).fill("..").join("/"); + + if (isTs) { + // TypeScript imports should use src directly + relativePath += "/src"; + } + + const importRenamedContents = fileContents.replace( + importRegex, + isTs ? `import $1 from "${relativePath}";` : `const $1 = require("${relativePath}");` + ); + + // Remove trailing call to main() + const updatedContents = importRenamedContents.replace( + new RegExp("main\\(\\)\\.catch.*", "s"), + isTs ? "" : "module.exports = { main };\n" + ); + + log("Updating imports in", fileName); + return fs.writeFile(fileName, updatedContents, { encoding: "utf-8" }); +} + +async function* cat(...generators: AsyncIterable[]): AsyncIterable { + for (const g of generators) { + yield* g; + } +} + +export default leafCommand(commandInfo, async (options) => { + let argumentDir; + if (options.args.length) { + argumentDir = path.resolve(options.args[0]); + } else { + argumentDir = process.cwd(); + } + + const pkg = await resolveProject(argumentDir); + + log.info("Preparing samples for package:", `${pkg.name}@${pkg.version}`); + + // Create dist-samples and copy to it + const outputDir = path.join(pkg.path, "dist-samples"); + if (fs.existsSync(outputDir)) { + log.warn("Cleaning up old dist-samples folder."); + await fs.remove(outputDir); + } + await fs.copy(path.join(pkg.path, "samples"), outputDir); + + const tsDir = path.join(outputDir, "typescript", "src"); + const tsFiles = findMatchingFiles( + tsDir, + (name, entry) => entry.isFile() && name.endsWith(".ts") && !name.endsWith(".d.ts") + ); + + const jsDir = path.join(outputDir, "javascript"); + const jsFiles = findMatchingFiles(jsDir, (name, entry) => entry.isFile() && name.endsWith(".js")); + + for await (const fileName of cat(tsFiles, jsFiles)) { + await enableLocalRun(fileName, pkg.path, pkg.name); + } + + return true; +}); diff --git a/common/tools/dev-tool/src/commands/samples/run.ts b/common/tools/dev-tool/src/commands/samples/run.ts new file mode 100644 index 000000000000..2d6a92c20208 --- /dev/null +++ b/common/tools/dev-tool/src/commands/samples/run.ts @@ -0,0 +1,93 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +import fs from "fs-extra"; +import path from "path"; + +import { findMatchingFiles } from "../../util/findMatchingFiles"; +import { createPrinter } from "../../util/printer"; +import { leafCommand, makeCommandInfo } from "../../framework/command"; + +const log = createPrinter("run-samples"); + +const IGNORE = ["node_modules"]; + +export const commandInfo = makeCommandInfo( + "run", + "execute a sample or all samples within a directory" +); + +/** + * Run a single sample file, accumulating any thrown errors into `accumulatedErrors` + * + * @param name the file to run + * @param accumulatedErrors an array to push truncated errors onto as tuples of [fileName, error] + */ +async function runSingle(name: string, accumulatedErrors: Array<[string, string]>) { + log("Running", name); + try { + if (/.*\/samples\/.*/.exec(name)) { + // This is an un-prepared sample, so just require it and it will run. + await import(name); + } else if (!/.*\/dist-samples\/.*/.exec(name)) { + // This is not an unprepared or a prepared sample + log.warn("Executing a file that is neither in samples nor dist-samples."); + } else { + const { main: sampleMain } = await import(name); + await sampleMain(); + } + } catch (err) { + const truncatedError: string = err + .toString() + .split("\n")[0] + .slice(0, 100); + accumulatedErrors.push([path.basename(name), truncatedError]); + log.warn(`Error in ${name}:`); + log.warn(err); + } +} + +export default leafCommand(commandInfo, async (options) => { + if (options.args.length === 0) { + throw new Error("At least one argument is required for run-samples"); + } + + const samples = options.args.map((dir) => path.resolve(dir)); + + // Patch the environment for the sample helper + process.env.BATCH_RUN_SAMPLES = "true"; + + const errors: Array<[string, string]> = []; + + for (const sample of samples) { + const stats = await fs.stat(sample); + if (stats.isFile()) { + runSingle(sample, errors); + } else if (stats.isDirectory()) { + for await (const fileName of findMatchingFiles( + sample, + (name, entry) => entry.isFile() && name.endsWith(".js"), + { + ignore: IGNORE + } + )) { + await runSingle(fileName, errors); + } + } else { + log.warn(`Sample ${sample} is neither a file nor a directory.`); + log.warn("Continuing ..."); + errors.push([path.basename(sample), "Neither a file nor a directory"]); + } + } + + if (errors.length > 0) { + log.error("Errors occurred in the following files:"); + for (const [fileName, error] of errors) { + log.error(" -", fileName, "(", error, ")"); + } + + return false; + } + + return true; +}); diff --git a/common/tools/dev-tool/src/commands/samples/tsToJs.ts b/common/tools/dev-tool/src/commands/samples/tsToJs.ts new file mode 100644 index 000000000000..c9f0c9311ea3 --- /dev/null +++ b/common/tools/dev-tool/src/commands/samples/tsToJs.ts @@ -0,0 +1,90 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +import fs from "fs-extra"; +import path from "path"; + +import * as prettier from "prettier"; +import ts from "typescript"; + +import { leafCommand, makeCommandInfo } from "../../framework/command"; + +export const commandInfo = makeCommandInfo( + "ts-to-js", + "convert a TypeScript sample to a JavaScript equivalent using our conventions for samples" +); + +import untypedPrettierOptions from "@azure/eslint-plugin-azure-sdk/prettier.json"; +const prettierOptions = untypedPrettierOptions as prettier.Options; + +const compilerOptions: ts.CompilerOptions = { + target: ts.ScriptTarget.ESNext, + module: ts.ModuleKind.ES2015 +}; + +const NEWLINE_SIGIL = "\n//@@TS-MAGIC-NEWLINE@@\n"; +const NEWLINE_SIGIL_SEARCH = /\n\s*\/\/@@TS-MAGIC-NEWLINE@@\n/; + +/** + * A set of replacements to perform. Structured as an array of doubles: + * + * [, ] + * + * Given as arguments to string.replace. Called in this order. + */ +const REGEX_STACK: Array<[RegExp, string]> = [ + // import * as dotenv ... -> require("dotenv").config() + [ + /import\s+\*\s+as\s+dotenv\s+from\s*"dotenv"\s*;\s*\n\s*dotenv.config\({[^{]*}\)\s*;\s*/, + 'require("dotenv").config();\n\n' + ], // Needs some special handling + // import { ... } from -> const { ... } = require + [/import\s+({[^}]+})\s+from\s*("[^"]+");/gs, "const $1 = require($2);"], + [/import\s+([^\s]+)\s+from\s*("[^"]+");/g, "const $1 = require($2);"], + [/import\s+\*\s+as\s+([^\s]+)\s+from\s*("[^"]+");/g, "const $1 = require($2);"], + [/export async function main/, "async function main"] +]; + +/** + * Handles the formatting of the resulting JS text. + */ +function postTransform(outText: string, _inText: string): string { + // Replace the sigils that we inserted + let text = outText.split(NEWLINE_SIGIL_SEARCH).join("\n\n"); + + // Format first so that we can write matching regexps + // that are humanly comprehensible + text = prettier.format(text, prettierOptions); + + for (const [match, replacement] of REGEX_STACK) { + text = text.replace(match, replacement); + } + + // Format once more for the final output. + return prettier.format(text, prettierOptions); +} + +export default leafCommand(commandInfo, async (options) => { + if (options.args.length !== 2) { + throw new Error("Wrong number of arguments. Got " + options.args.length + " but expected 2."); + } + + const [src, dest] = options.args.map(path.normalize); + + const srcText = (await fs.readFile(src)).toString("utf-8"); + + // TypeScript doesn't preserve newlines in compiled JS output, + // but we can pre-process each blank line by replacing it with a special + // sigil (in a comment, since TS preserves comments + const processedSrcText = srcText.split(/\n\s*\n/).join(NEWLINE_SIGIL); + + const output = ts.transpileModule(processedSrcText, { + compilerOptions, + fileName: src + }); + + await fs.ensureDir(path.dirname(dest)); + await fs.writeFile(dest, postTransform(output.outputText, srcText)); + + return true; +}); diff --git a/common/tools/dev-tool/src/framework/CommandInfo.ts b/common/tools/dev-tool/src/framework/CommandInfo.ts new file mode 100644 index 000000000000..8e8e197479b7 --- /dev/null +++ b/common/tools/dev-tool/src/framework/CommandInfo.ts @@ -0,0 +1,70 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license + +/** + * Information about this command + */ +export interface CommandInfo { + /** + * Name of this command + */ + name: string; + + /** + * One line of help text to be printed by the `dev-tool help` command + */ + description: string; + + /** + * Argument configuration for this command + * + * Used for type-checked argument parsing and help text. + * + * The options keys "help", "args", and "--" will be discarded, as they are handled internally. + */ + options?: Options; +} + +/** + * Structure for definining options of a command, represented as + * a map from option name to a description, argument kind (string or boolean), + * optional default value, and optional short name (one-letter alias) + */ +export interface CommandOptions { + [k: string]: { + /** + * Optional one-letter alias + */ + shortName?: string; + /** + * Help text for this option + */ + description: string; + /** + * Whether or not the option may be specified multiple times + * + * Default: false + */ + allowMultiple?: boolean; + } & OptionDescription; +} + +export type OptionDescription = StringOptionDescription | BooleanOptionDescription; + +/** + * Option description for a string argument + */ +export interface StringOptionDescription { + kind: "string"; + default?: string; +} + +/** + * Option description for a boolean argument + */ +export interface BooleanOptionDescription { + kind: "boolean"; + default?: boolean; + // minimist seemingly cannot handle booleans specified multiple times + allowMultiple?: false; +} diff --git a/common/tools/dev-tool/src/framework/CommandModule.ts b/common/tools/dev-tool/src/framework/CommandModule.ts new file mode 100644 index 000000000000..a5345a5d28b6 --- /dev/null +++ b/common/tools/dev-tool/src/framework/CommandModule.ts @@ -0,0 +1,28 @@ +import { CommandInfo, CommandOptions } from "./CommandInfo"; + +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license + +/** + * A command for use with the dev-tool + */ +export interface CommandModule { + /** + * The main async function of the command. + * + * @param args the arguments passed to the command + * + * @returns a promise resolving to `true` if the command succeeded, `false` otherwise + */ + default: (...args: string[]) => Promise; + + /** + * Metadata information about this subcommand + */ + commandInfo: CommandInfo; +} + +/** + * A map from command name to an async function that loads its module + */ +export type CommandLoader = { [k: string]: () => Promise> }; diff --git a/common/tools/dev-tool/src/framework/command.ts b/common/tools/dev-tool/src/framework/command.ts new file mode 100644 index 000000000000..0996eef7e8b9 --- /dev/null +++ b/common/tools/dev-tool/src/framework/command.ts @@ -0,0 +1,141 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license + +import { CommandLoader } from "./CommandModule"; +import { createPrinter } from "../util/printer"; +import { printCommandUsage, commandStack } from "./printCommandUsage"; +import { ParsedOptions, parseOptions } from "./parseOptions"; +import { CommandInfo, CommandOptions } from "./CommandInfo"; + +/** + * Utility type that makes the type of the "allowMultiple" key in + * any options descriptions strictly "undefined" when it is not + * specified in the context of a refined extending type + */ +export type StrictAllowMultiple = { + [K in keyof Opts]: boolean extends Opts[K]["allowMultiple"] + ? Opts[K] & { allowMultiple?: undefined } + : Opts[K]; +}; + +/** + * Create a CommandInfo object that describes a command and its functionality. + * + * For the best type-checking support, please ensure that the `options` parameter + * is given to this function as a literal. + * + * Example: + * + * ```typescript + * export const commandInfo = describe( + * "resolve", + * "display information about the project that owns a directory", + * { + * directory: { + * shortName: "d", + * kind: "string", + * description: "base directory for resolution (uses CWD if unset)", + * allowMultiple: true + * }, + * quiet: { + * shortName: "q", + * kind: "boolean", + * default: false, + * description: "output only the directory name with no extra formatting" + * } + * } + * ); + * ``` + * + * @param name the name of this command + * @param description a one-line description of this command's functionality + * @param options the command's command-line options descriptions (see: {@link CommandOptions}) + */ +export function makeCommandInfo( + name: string, + description: string, + options?: Opts +): CommandInfo> { + return { + name, + description, + options: options as StrictAllowMultiple + }; +} + +/** + * Create a subcommand handler that will delegate handling + * to a set of lower-order subcommands. + * + * @param info a the CommandInfo object that describes this command + * @param commands map from subcommand name to module implementing that command + */ +export function subCommand>( + info: Info, + commands: CommandLoader +): (...args: string[]) => Promise { + const log = createPrinter(info.name); + return async (...rawArgs: string[]) => { + commandStack.push(info.name); + + const options = parseOptions(rawArgs, info.options); + + log.debug("Parsed command line:", JSON.stringify(options)); + + if (options.help) { + await printCommandUsage(info, commands); + return true; + } + + const commandName = options.args[0]; + const commandArgs = options.args.slice(1); + + if (commandName === undefined) { + log.error("No sub-command provided."); + await printCommandUsage(info, commands, console.error); + process.exit(1); + } + + log.debug(`$ ${commandName} ${commandArgs?.join(" ") ?? ""}`); + + if (Object.prototype.hasOwnProperty.call(commands, commandName)) { + const commandModule = await commands[commandName](); + + const status = await commandModule.default(...commandArgs); + + if (!status) { + log.error("Errors occurred. See the output above."); + } + return status; + } else { + log.error("No such sub-command:", commandName); + await printCommandUsage(info, commands, console.error); + process.exit(1); + } + }; +} + +/** + * Construct a command that runs a handler when invoked. + * + * @param info the CommandInfo object that describes this command + * @param handler a function to handle the execution of the command + */ +export function leafCommand>( + info: Info, + handler: (options: ParsedOptions>) => Promise +): (...args: string[]) => Promise { + return async (...args: string[]): Promise => { + const options = parseOptions(args, info.options); + + commandStack.push(info.name); + + // --help is treated specially + if (options.help) { + await printCommandUsage(info); + return true; + } + + return handler(options as ParsedOptions>); + }; +} diff --git a/common/tools/dev-tool/src/framework/parseOptions.ts b/common/tools/dev-tool/src/framework/parseOptions.ts new file mode 100644 index 000000000000..7ea15944c6b0 --- /dev/null +++ b/common/tools/dev-tool/src/framework/parseOptions.ts @@ -0,0 +1,140 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license + +import getArgs from "minimist"; + +import { createPrinter } from "../util/printer"; +import { CommandOptions, StringOptionDescription, BooleanOptionDescription } from "./CommandInfo"; + +const { debug: parseDebug, error: parseError } = createPrinter("parseOptions"); + +/** + * This helper type implements the logic for determining the + * type of an option according to its possible multiplicity + */ +export type MaybeMultiple = boolean extends P ? T | T[] : true extends P ? T[] : T; + +/** + * The real type of an option parsed from an OptionDescription + */ +export type OptionFor = MaybeMultiple< + Opt["allowMultiple"], + Opt extends StringOptionDescription + ? string + : Opt extends BooleanOptionDescription + ? boolean + : string | boolean +>; + +/** + * The type of the Options map produced by {@link parseOptions} + * given a const input type Opts that extends CommandOptions. + * + * You should probably not use this type directly. It is designed + * to be inferred when using {@link leafCommand}. + * + * Make sure the input type is declared const, otherwise a + * fully dynamic map will be produced. + */ +export type ParsedOptions = { + /** + * If the argument "--" was encountered when parsing, this property + * holds all arguments that occurred after the "--" + */ + "--"?: string[] | undefined; + /** + * Array of arguments to the command + */ + args: string[]; +} & { + // If no default is specified, then the type will be implicitly or'd + // with undefined + [K in Exclude]: undefined extends Opts[K]["default"] + ? OptionFor | undefined + : OptionFor; +}; + +/** + * Helper function to convert an args array to a parsed argument map. + * + * This is a strongly-typed wrapper around `minimist`. + * + * You should probably not use this function directly. The + * options should be parsed and their types should be inferred + * from {@link leafCommand}. + * + * @param args input array of arg strings from argv + * @param options option map of a command + */ +export function parseOptions( + args: string[], + opts?: Opts +): ParsedOptions> { + // If options are not provided, use an empty set + const options: CommandOptions = opts ?? {}; + + const keys = Object.keys(options); + const argMap = getArgs(args, { + // Once an unidentified argument is encountered, stop parsing + stopEarly: true, + // Use type information for hinting to minimist about how arguments should + // be handled + boolean: ["help", ...keys.filter((k) => options[k].kind === "boolean")], + string: keys.filter((k) => options[k].kind === "string"), + // Roll up the optional short-names into aliases + alias: keys.reduce( + (o, key) => + options[key].shortName !== undefined + ? { ...o, [options[key].shortName as string]: key } + : o, + {} + ), + // Roll up the default values into the arg parser + default: { + ...keys.reduce( + (o, key) => + options[key].default !== undefined ? { ...o, [key]: options[key].default } : o, + {} + ), + help: false + } + }); + + parseDebug("Parsed args:", JSON.stringify(argMap)); + + const result: ParsedOptions = { help: argMap.help, args: argMap._ }; + + function expectType(key: string, value: T, expected: string): void { + if (Array.isArray(value)) { + parseError(`Too many arguments for "${key}"`); + throw new Error(`More than one value for "${key}" was given, but only one was expected`); + } else if (typeof value !== expected && typeof value !== "undefined") { + parseError(`Bad argument: "${key}" = ${value}`); + throw new Error( + `Value of argument "${key}" was a ${typeof value} but a ${expected} was expected.` + ); + } + } + + // Type validation + for (const k of keys) { + result[k] = argMap[k]; + const opt = options[k]; + if (!opt.allowMultiple) { + expectType(k, result[k], opt.kind); + } else if (Array.isArray(result[k])) { + // allowMultiple === true, check all + for (const val of result[k] as (string | boolean)[]) { + expectType(k, val, opt.kind); + } + } else if (result[k] !== undefined) { + // allowMultiple === true, wrap + expectType(k, result[k], opt.kind); + result[k] = [result[k] as string | boolean]; + } + } + + parseDebug("Final arguments:", JSON.stringify(result)); + + return result as ParsedOptions>; +} diff --git a/common/tools/dev-tool/src/framework/printCommandUsage.ts b/common/tools/dev-tool/src/framework/printCommandUsage.ts new file mode 100644 index 000000000000..bf27316addd2 --- /dev/null +++ b/common/tools/dev-tool/src/framework/printCommandUsage.ts @@ -0,0 +1,65 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license + +import { CommandLoader } from "./CommandModule"; +import { CommandInfo, CommandOptions } from "./CommandInfo"; + +/** + * The stack of subcommands executed so far + * + * Used in help output. + */ +export const commandStack: string[] = []; + +/** + * Prints the help information for a given command + * + * @param info CommandInfo structure to use in printing command information + * @param subCommands optional CommandLoader structure that defines subcommand usage + * @param println optionally override the default printer + */ +export async function printCommandUsage( + info: CommandInfo, + subCommands?: CommandLoader, + println: (...values: string[]) => void = console.log +): Promise { + println(`${info.name} - ${info.description}\n`); + println( + `Usage: ${commandStack.join(" ")} [OPTIONS] ${ + subCommands !== undefined ? "COMMAND [... COMMAND-OPTIONS]" : "" + }\n` + ); + + // OPTIONS info + println("Options:"); + println(" --help\t display this help message"); + if (info.options) { + for (const [k, option] of Object.entries(info.options)) { + const shortName = option.shortName !== undefined ? `-${option.shortName},` : ""; + const valueType = option.kind !== "boolean" ? "" : ""; + const acceptsMulti = + option.kind === "string" && option.allowMultiple ? " (can be set multiple times)" : ""; + println(` ${shortName}--${k}\t${valueType} ${option.description}${acceptsMulti}`); + } + } + + // COMMAND info + if (subCommands) { + println(); + println("COMMAND indicates the subcommand to be run. It can be one of the following:\n"); + + // Compute the number of tabs needed to separate commands from + // docstrings assuming a default command-line tabstop of 8 + const tabs = Math.ceil( + (Math.max(...Object.keys(subCommands).map((key) => key.length + 2)) + 1) / 8 + ); + + for (const [command, load] of Object.entries(subCommands)) { + const module = await load(); + const indent = "\t".repeat(tabs - Math.floor((command.length + 2) / 8)); + println(` ${command}${indent}${module.commandInfo.description}`); + } + } + + println(); +} diff --git a/common/tools/dev-tool/src/index.ts b/common/tools/dev-tool/src/index.ts new file mode 100644 index 000000000000..0b33ab9c9a3a --- /dev/null +++ b/common/tools/dev-tool/src/index.ts @@ -0,0 +1,12 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +import chalk from "chalk"; + +import { baseCommand } from "./commands"; + +// The main command is implemented using the same `subCommand` method. +baseCommand(...process.argv.slice(2)).catch((err) => { + console.trace(chalk.red("[Internal Error]", err.stack)); + process.exit(1); +}); diff --git a/common/tools/dev-tool/src/util/findMatchingFiles.ts b/common/tools/dev-tool/src/util/findMatchingFiles.ts new file mode 100644 index 000000000000..4e1249652864 --- /dev/null +++ b/common/tools/dev-tool/src/util/findMatchingFiles.ts @@ -0,0 +1,84 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license + +import fs from "fs-extra"; +import path from "path"; +import { createPrinter } from "./printer"; + +const { debug } = createPrinter("find-matching-files"); + +/** + * File information used during breadth-first search + */ +interface FileInfo { + dir: string; + fullPath: string; + name: string; + stat: fs.Stats; +} + +/** + * Options for {@link findMatchingFiles} + */ +export interface FindOptions { + ignore: string[]; +} + +const defaultFindOptions: FindOptions = { + ignore: [] +}; + +/** + * Breadth-first search for files matching a given predicate + * + * @param dir The root of the sample tree to search + * @param matches Predicate that decides whether or not a file entry is included + * @param options options bag for + */ +export async function* findMatchingFiles( + dir: string, + matches: (name: string, entry: fs.Stats) => boolean, + findOptions?: Partial +) { + const q: FileInfo[] = []; + + const options: FindOptions = { ...defaultFindOptions, ...findOptions }; + + async function enqueueAll(dir: string) { + const files = await fs.readdir(dir); + for (const file of files) { + const fullPath = path.join(dir, file); + q.push({ + dir, + fullPath, + name: file, + stat: await fs.stat(fullPath) + }); + } + } + + await enqueueAll(dir); + + while (q.length) { + const info = q.shift() as FileInfo; + + if (options.ignore.includes(info.name)) { + debug("Ignoring", info.fullPath); + continue; + } + + if (info.stat.isDirectory()) { + await enqueueAll(info.fullPath); + } else if (matches(info.name, info.stat)) { + yield info.fullPath; + } else if ( + info.stat.isBlockDevice() || + info.stat.isCharacterDevice() || + info.stat.isFIFO() || + info.stat.isSocket() || + info.stat.isSymbolicLink() + ) { + debug("Encountered a special file in the sample tree. Skipping:", info.fullPath); + } + } +} diff --git a/common/tools/dev-tool/src/util/printer.ts b/common/tools/dev-tool/src/util/printer.ts new file mode 100644 index 000000000000..a5934c8da567 --- /dev/null +++ b/common/tools/dev-tool/src/util/printer.ts @@ -0,0 +1,144 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +/* eslint-disable @typescript-eslint/no-explicit-any */ + +import chalk from "chalk"; +import path from "path"; + +const printModes = ["info", "warn", "error", "success", "debug"] as const; + +export type Fn = (...values: any[]) => T; +export type ModeMap = { [k in typeof printModes[number]]: T }; + +/** + * The interface that describes the Printer produced by {@link createPrinter} + */ +export interface Printer extends ModeMap { + (...values: any[]): void; +} + +export interface PrinterBackend { + error: Fn; + log: Fn; + info: Fn; + warn: Fn; + trace: Fn; +} + +/** + * The object that is used to write output. + */ +let backend: PrinterBackend = { + error: console.error, + log: console.log, + info: console.info, + warn: console.warn, + trace: console.trace +}; + +/** + * Change the backend used to print output. This function will + * replace the methods of the existing backend with those specified + * in `update`, but will leave unspecified methods intact. + * + * @param backend partial specification of a PrinterBackend + */ +export function updateBackend(update: Partial): void { + backend = { + ...backend, + ...update + }; +} + +/** + * Gets the filename of the calling function + */ +function getCaller(): NodeJS.CallSite | undefined { + const savedPrepareStackTrace = Error.prepareStackTrace; + + let caller: NodeJS.CallSite | undefined = undefined; + try { + const error = (new Error() as any) as { stack: NodeJS.CallSite[] }; + + Error.prepareStackTrace = (_, stack) => stack; + + const next = () => error.stack.shift(); + + const current = next(); + + while (error.stack.length > 0 && current !== caller) { + caller = next(); + } + // eslint-disable-next-line no-empty + } catch (_) {} + + Error.prepareStackTrace = savedPrepareStackTrace; + + return caller; +} + +const colors: ModeMap> = { + info: chalk.blueBright, + warn: chalk.yellow, + error: chalk.red, + debug: chalk.magenta, + success: chalk.green +}; + +const finalLogger: ModeMap = { + info(...values) { + backend.info(...values); + }, + warn(...values) { + backend.warn(...values); + }, + error(...values) { + backend.error(...values); + }, + debug(...values: string[]) { + if (process.env.DEBUG) { + const caller = getCaller(); + const fileName = caller + ?.getFileName() + ?.split(path.join("azure-sdk-for-js", "common", "tools", "dev-tool")); + const callerInfo = `(@ ${fileName ? fileName : ""}#${caller?.getFunctionName() ?? + ""}:${caller?.getLineNumber()}:${caller?.getColumnNumber()})`; + backend.error(values[0], colors.debug(callerInfo), ...values.slice(1)); + } + }, + success: console.info +}; + +/** + * Create a pre-configured console printer for a given namespace. + * + * ```javascript + * const log = createPrinter("my-command"); + * ``` + * + * The printer can be called directly (`log("A message")`), or a + * log level can be specified (`log.error("An error message")`). + * + * The printer outputs `[]` before each message and colorizes terminal + * output as appropriate using `chalk` according to the log level. The colors are: + * + * - no log level (called directly): white + * - info: bright blue (ANSI #12) + * - warn: yellow (ANSI #3) + * - error: red (ANSI #1) + * - debug: magenta (ANSI #5) + * - success: green (ANSI #2) + * + * @param name the namespace to format log messages with + */ +export function createPrinter(name: string): Printer { + const prefix = "[" + name + "]"; + const base = ((...values: string[]) => console.log(chalk.reset(prefix, ...values))) as Printer; + + for (const mode of printModes) { + base[mode] = (...values: string[]) => + finalLogger[mode](...[prefix, ...values].map((value: string) => colors[mode](value))); + } + return base; +} diff --git a/common/tools/dev-tool/src/util/resolveProject.ts b/common/tools/dev-tool/src/util/resolveProject.ts new file mode 100644 index 000000000000..71be20ebeb64 --- /dev/null +++ b/common/tools/dev-tool/src/util/resolveProject.ts @@ -0,0 +1,98 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +import fs from "fs-extra"; +import path from "path"; + +import { createPrinter } from "./printer"; + +const { debug } = createPrinter("resolve-project"); + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +type PackageJson = any; + +/** + * Information about an Azure SDK for JS package + */ +export interface ProjectInfo { + /** + * The name of the package + */ + name: string; + /** + * An absolute path to the package directory + */ + path: string; + /** + * The package SemVer string, e.g. 1.0.0-preview.3 or 4.0.0 + */ + version: string; + /** + * The package info object (result of reading/parsing package.json) + */ + packageJson: PackageJson; +} + +async function isAzureSDKPackage(fileName: string): Promise { + const f = await import(fileName); + + if ((f.name as string).startsWith("@azure/")) { + return true; + } else { + return false; + } +} + +async function findAzSDKPackageJson(directory: string): Promise<[string, PackageJson]> { + const files = await fs.readdir(directory); + + if (files.includes("rush.json")) { + throw new Error("Reached monorepo root, but no matching Azure SDK package was found."); + } + + for (const file of files) { + if (file === "package.json") { + const fullPath = path.join(directory, file); + const packageObject = (await import(fullPath)).default; + if (await isAzureSDKPackage(fullPath)) { + return [directory, packageObject]; + } + debug(`found package.json at ${fullPath}, but it is not an Azure SDK package`); + } + } + + const nextPath = path.resolve(path.join(directory, "..")); + + if (nextPath === directory) { + throw new Error("Reached filesystem root, but no matching Azure SDK package was found."); + } + + return findAzSDKPackageJson(nextPath); +} + +/** + * Determine which Azure SDK project a given directory belongs to. + * + * @param workingDirectory the directory to resolve the package from + * @returns the package info for the SDK project that owns the given directory + */ +export async function resolveProject(workingDirectory: string): Promise { + if (!fs.existsSync(workingDirectory)) { + throw new Error(`No such file or directory: ${workingDirectory}`); + } + + const directory = await fs.stat(workingDirectory); + + if (!directory.isDirectory()) { + throw new Error(`${workingDirectory} is not a directory`); + } + + const [path, packageJson] = await findAzSDKPackageJson(workingDirectory); + + return { + name: packageJson.name, + path, + version: packageJson.version, + packageJson + }; +} diff --git a/common/tools/dev-tool/test/framework.spec.ts b/common/tools/dev-tool/test/framework.spec.ts new file mode 100644 index 000000000000..07e5530942c2 --- /dev/null +++ b/common/tools/dev-tool/test/framework.spec.ts @@ -0,0 +1,85 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +import { assert } from "chai"; + +import { parseOptions } from "../src/framework/parseOptions"; +import { makeCommandInfo, subCommand, leafCommand } from "../src/framework/command"; + +import { updateBackend } from "../src/util/printer"; + +const simpleCommandInfo = makeCommandInfo("simple", "a simple command", { + simpleArg: { + kind: "string", + description: "a simple argument", + allowMultiple: false, + default: "foo" + } +}); + +interface SimpleExpectedOptionsType { + simpleArg: string; + help?: boolean; + args?: string[]; +} + +describe("Command Framework", () => { + before(() => { + // Silence the logger + updateBackend({ + error: () => {}, + warn: () => {}, + info: () => {}, + log: () => {} + }); + }); + + describe("subCommand", () => { + it("simple dispatcher", async () => { + const dispatcher = subCommand( + { name: "test", description: "a sub-command dispatcher" }, + { + sub: async () => ({ + commandInfo: { name: "sub", description: "a leaf command" }, + default: leafCommand({ name: "sub", description: "a leaf command" }, async () => true) + }), + fail: async () => ({ + commandInfo: { name: "fail", description: "a command that fails" }, + default: leafCommand( + { name: "fail", description: "a command that fails" }, + async () => false + ) + }) + } + ); + + assert.isTrue(await dispatcher("sub")); + assert.isFalse(await dispatcher("fail")); + }); + }); + + describe("leafCommand", () => { + it("simple leaf command with argument", async () => { + const command = leafCommand(simpleCommandInfo, (opts: SimpleExpectedOptionsType) => { + if (opts.simpleArg === "yes") { + return Promise.resolve(true); + } else { + return Promise.resolve(false); + } + }); + + assert.isTrue(await command("--simpleArg", "yes")); + assert.isFalse(await command("--simpleArg", "no")); + }); + }); + + describe("parseOptions", () => { + it("simple", () => { + const opts: SimpleExpectedOptionsType = parseOptions( + ["--simpleArg", "test"], + simpleCommandInfo.options + ); + assert.equal(opts.simpleArg, "test"); + }); + }); +}); diff --git a/common/tools/dev-tool/test/resolveProject.spec.ts b/common/tools/dev-tool/test/resolveProject.spec.ts new file mode 100644 index 000000000000..6300962ed0cc --- /dev/null +++ b/common/tools/dev-tool/test/resolveProject.spec.ts @@ -0,0 +1,30 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license + +import { assert, use as chaiUse } from "chai"; +import chaiPromises from "chai-as-promised"; +chaiUse(chaiPromises); + +import path from "path"; + +import { resolveProject } from "../src/util/resolveProject"; + +describe("Project Resolution", async () => { + it("resolution halts at monorepo root", async () => { + await assert.isRejected(resolveProject(path.join(__dirname, "..", "..")), /monorepo root/); + }); + + it("resolution halts at filesystem root", async () => { + const p = path.join(__dirname, "..", "..", "..", "..", ".."); + await assert.isRejected(resolveProject(p), /filesystem root/); + }); + + it("resolution finds dev-tool package", async () => { + const packageInfo = await resolveProject(__dirname); + assert.equal(packageInfo.name, "@azure/dev-tool"); + assert.match( + packageInfo.path, + new RegExp(`.*${path.sep}${path.join("azure-sdk-for-js", "common", "tools", "dev-tool")}`) + ); + }); +}); diff --git a/common/tools/dev-tool/tsconfig.json b/common/tools/dev-tool/tsconfig.json new file mode 100644 index 000000000000..af4008fc8754 --- /dev/null +++ b/common/tools/dev-tool/tsconfig.json @@ -0,0 +1,23 @@ +{ + "compilerOptions": { + "target": "ES2015", + "module": "commonjs", + "moduleResolution": "node", + "noEmit": true, + "esModuleInterop": true, + + "lib": ["ES6", "ESNext.AsyncIterable"], + + "newLine": "LF", + "strict": true, + "alwaysStrict": true, + "noImplicitAny": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "downlevelIteration": true, + + "resolveJsonModule": true + }, + "exclude": ["node_modules"], + "include": ["./src/**/*.ts", "./test/**/*.ts"] +} diff --git a/eng/tools/dependency-testing/templates/package.json b/eng/tools/dependency-testing/templates/package.json index 3317602807d2..dc0230ca92b4 100644 --- a/eng/tools/dependency-testing/templates/package.json +++ b/eng/tools/dependency-testing/templates/package.json @@ -9,7 +9,7 @@ "scripts": { "build": "tsc -p .", "integration-test:browser": "karma start --single-run", - "integration-test:node": "nyc mocha -r esm --require source-map-support/register --reporter ./mocha-multi-reporter.js --timeout 180000 --full-trace 'dist/**/*.js' --exit", + "integration-test:node": "nyc mocha -r esm --require source-map-support/register --reporter ./mocha-multi-reporter.js --timeout 250000 --full-trace 'dist/**/*.js' --exit", "integration-test": "npm run integration-test:node && npm run integration-test:browser" }, "repository": { diff --git a/rush.json b/rush.json index 0b74f4267aba..328cd4e515e9 100644 --- a/rush.json +++ b/rush.json @@ -402,6 +402,11 @@ "projectFolder": "sdk/cosmosdb/cosmos", "versionPolicyName": "client" }, + { + "packageName": "@azure/dev-tool", + "projectFolder": "common/tools/dev-tool", + "versionPolicyName": "utility" + }, { "packageName": "@azure/event-hubs", "projectFolder": "sdk/eventhub/event-hubs", diff --git a/sdk/appconfiguration/app-configuration/package.json b/sdk/appconfiguration/app-configuration/package.json index 722652a37107..f3cde4b100a0 100644 --- a/sdk/appconfiguration/app-configuration/package.json +++ b/sdk/appconfiguration/app-configuration/package.json @@ -47,7 +47,7 @@ "build:test": "npm run build:test:node && npm run build:test:browser", "build:test:node": "tsc -p . && cross-env ONLY_NODE=true rollup -c rollup.test.config.js 2>&1", "build:test:browser": "tsc -p . && cross-env ONLY_BROWSER=true rollup -c rollup.test.config.js 2>&1", - "build:samples": "node ../../../common/scripts/prep-samples.js && cd samples && tsc", + "build:samples": "dev-tool samples prep && cd dist-samples && tsc", "check-format": "prettier --list-different --config ../../.prettierrc.json --ignore-path ../../.prettierignore \"src/**/*.ts\" \"test/**/*.ts\" \"*.{js,json}\"", "clean": "rimraf dist dist-esm dist-browser test-dist test-browser types *.tgz *.log", "coverage": "nyc --reporter=lcov --exclude-after-remap=false mocha -t 120000 test-dist/index.js --reporter ../../../common/tools/mocha-multi-reporter.js", @@ -88,6 +88,7 @@ "tslib": "^2.0.0" }, "devDependencies": { + "@azure/dev-tool": "^1.0.0", "@azure/identity": "^1.1.0-preview", "@azure/test-utils-recorder": "^1.0.0", "@microsoft/api-extractor": "7.7.11", diff --git a/sdk/appconfiguration/app-configuration/test/auth.spec.ts b/sdk/appconfiguration/app-configuration/test/auth.spec.ts index d70b275cebb2..774a1cb4be88 100644 --- a/sdk/appconfiguration/app-configuration/test/auth.spec.ts +++ b/sdk/appconfiguration/app-configuration/test/auth.spec.ts @@ -15,8 +15,8 @@ describe("Authentication", () => { credsAndEndpoint = getTokenAuthenticationCredential() || this.skip(); }); - afterEach(function() { - recorder.stop(); + afterEach(async function() { + await recorder.stop(); }); it("invalid connection string gives a decent error message", () => { diff --git a/sdk/appconfiguration/app-configuration/test/etags.spec.ts b/sdk/appconfiguration/app-configuration/test/etags.spec.ts index 2f903741f4cb..b5f392d760e8 100644 --- a/sdk/appconfiguration/app-configuration/test/etags.spec.ts +++ b/sdk/appconfiguration/app-configuration/test/etags.spec.ts @@ -28,7 +28,7 @@ describe("etags", () => { afterEach(async function() { await deleteKeyCompletely([key], client); - recorder.stop(); + await recorder.stop(); }); // etag usage is 'opt-in' via the onlyIfChanged/onlyIfUnchanged options for certain calls diff --git a/sdk/appconfiguration/app-configuration/test/index.readonlytests.spec.ts b/sdk/appconfiguration/app-configuration/test/index.readonlytests.spec.ts index 9500c3a455e7..b1ba3e010de7 100644 --- a/sdk/appconfiguration/app-configuration/test/index.readonlytests.spec.ts +++ b/sdk/appconfiguration/app-configuration/test/index.readonlytests.spec.ts @@ -28,7 +28,7 @@ describe("AppConfigurationClient (set|clear)ReadOnly", () => { afterEach(async function() { await deleteKeyCompletely([testConfigSetting.key], client); - recorder.stop(); + await recorder.stop(); }); it("basic", async function() { diff --git a/sdk/appconfiguration/app-configuration/test/index.spec.ts b/sdk/appconfiguration/app-configuration/test/index.spec.ts index 83b99bcf3267..6f33a6b07d76 100644 --- a/sdk/appconfiguration/app-configuration/test/index.spec.ts +++ b/sdk/appconfiguration/app-configuration/test/index.spec.ts @@ -24,8 +24,8 @@ describe("AppConfigurationClient", () => { client = createAppConfigurationClientForTests() || this.skip(); }); - afterEach(function() { - recorder.stop(); + afterEach(async function() { + await recorder.stop(); }); describe("simple usages", () => { diff --git a/sdk/appconfiguration/app-configuration/test/internal/http.spec.ts b/sdk/appconfiguration/app-configuration/test/internal/http.spec.ts index 234dd1244e7d..a7cf9165bcd7 100644 --- a/sdk/appconfiguration/app-configuration/test/internal/http.spec.ts +++ b/sdk/appconfiguration/app-configuration/test/internal/http.spec.ts @@ -108,8 +108,8 @@ describe("http request related tests", function() { client = createAppConfigurationClientForTests() || this.skip(); }); - afterEach(function() { - recorder.stop(); + afterEach(async function() { + await recorder.stop(); }); it("custom client request ID", async () => { diff --git a/sdk/appconfiguration/app-configuration/test/throwOrNotThrow.spec.ts b/sdk/appconfiguration/app-configuration/test/throwOrNotThrow.spec.ts index c83ee5bc006e..8cbd12ca2523 100644 --- a/sdk/appconfiguration/app-configuration/test/throwOrNotThrow.spec.ts +++ b/sdk/appconfiguration/app-configuration/test/throwOrNotThrow.spec.ts @@ -22,8 +22,8 @@ describe("Various error cases", () => { client = createAppConfigurationClientForTests() || this.skip(); }); - afterEach(function() { - recorder.stop(); + afterEach(async function() { + await recorder.stop(); }); describe("throws", () => { diff --git a/sdk/eventhub/event-hubs/package.json b/sdk/eventhub/event-hubs/package.json index d6e0b66d28eb..4e340bec665a 100644 --- a/sdk/eventhub/event-hubs/package.json +++ b/sdk/eventhub/event-hubs/package.json @@ -46,7 +46,7 @@ "audit": "node ../../../common/scripts/rush-audit.js && rimraf node_modules package-lock.json && npm i --package-lock-only 2>&1 && npm audit", "build:browser": "tsc -p . && cross-env ONLY_BROWSER=true rollup -c 2>&1", "build:node": "tsc -p . && cross-env ONLY_NODE=true rollup -c 2>&1", - "build:samples": "node ../../../common/scripts/prep-samples.js && cd samples && tsc", + "build:samples": "dev-tool samples prep && cd dist-samples && tsc", "build:test:browser": "tsc -p . && cross-env ONLY_BROWSER=true rollup -c rollup.test.config.js 2>&1", "build:test:node": "tsc -p . && cross-env ONLY_NODE=true rollup -c rollup.test.config.js 2>&1", "build:test": "tsc -p . && rollup -c rollup.test.config.js 2>&1", @@ -93,6 +93,7 @@ "uuid": "^8.1.0" }, "devDependencies": { + "@azure/dev-tool": "^1.0.0", "@azure/eslint-plugin-azure-sdk": "^3.0.0", "@azure/identity": "^1.1.0-preview", "@microsoft/api-extractor": "7.7.11", diff --git a/sdk/eventhub/event-hubs/test/README.md b/sdk/eventhub/event-hubs/test/README.md index 8cca67972557..158403f844d8 100644 --- a/sdk/eventhub/event-hubs/test/README.md +++ b/sdk/eventhub/event-hubs/test/README.md @@ -33,8 +33,8 @@ The following steps will help you setup the AAD credentials. ### Assign owner role to the registered application - In the Azure portal, go to your Azure Event Hubs namespace and assign the **Azure Event Hubs Data Owner** role to the registered application. -- This can be done from `Role assignment` section of `Access control (IAM)` tab (in the left-side-navbar of your Azure Event Hubs namespace in the Azure portal)
- _Doing this would allow the registered application manage the resource, i.e., entity creation, deletion, etc.,_
+- This can be done from `Role assignment` section of `Access control (IAM)` tab (in the left-side-navbar of your Azure Event Hubs namespace in the Azure portal) + _Doing this would allow the registered application manage the resource, i.e., entity creation, deletion, etc._ - For more information on securing your Azure Event Hubs namespace: [Learn more](https://docs.microsoft.com/en-us/azure/event-hubs/authorize-access-event-hubs) ![Impressions](https://azure-sdk-impressions.azurewebsites.net/api/impressions/azure-sdk-for-js%2Fsdk%2Feventhub%2Fevent-hubs%2Ftest%2FREADME.png) diff --git a/sdk/formrecognizer/ai-form-recognizer/package.json b/sdk/formrecognizer/ai-form-recognizer/package.json index 45519dbdf55e..9a9489e620c5 100644 --- a/sdk/formrecognizer/ai-form-recognizer/package.json +++ b/sdk/formrecognizer/ai-form-recognizer/package.json @@ -49,14 +49,12 @@ "build:autorest": "autorest ./swagger/README.md --typescript --package-version=1.0.0-preview.4 --version=3.0.6267", "build:browser": "tsc -p . && cross-env ONLY_BROWSER=true rollup -c 2>&1", "build:node": "tsc -p . && cross-env ONLY_NODE=true rollup -c 2>&1", - "build:samples": "node ../../../common/scripts/prep-samples.js && cd samples && tsc -p .", + "build:samples": "dev-tool samples prep && cd dist-samples && tsc -p .", "build:test": "tsc -p . && rollup -c rollup.test.config.js 2>&1", "build": "tsc -p . && rollup -c 2>&1 && api-extractor run --local", "check-format": "prettier --list-different --config ../../.prettierrc.json --ignore-path ../../.prettierignore --ignore-path ../../.prettierignore \"src/**/*.ts\" \"test/**/*.ts\" \"*.{js,json}\"", "clean": "rimraf dist dist-esm dist-browser dist-test test-browser temp types *.tgz *.log", - "execute:js-samples": "node ../../../common/scripts/run-samples.js samples/javascript/", - "execute:ts-samples": "node ../../../common/scripts/run-samples.js samples/typescript/dist/samples/typescript/src/", - "execute:samples": "npm run build:samples && npm run execute:js-samples && npm run execute:ts-samples", + "execute:samples": "npm run build:samples && dev-tool samples run samples/javascript/ && dev-tool samples run dist-samples/typescript/dist/dist-samples/typescript/src/", "extract-api": "tsc -p . && api-extractor run --local", "format": "prettier --write --config ../../.prettierrc.json --ignore-path ../../.prettierignore --ignore-path ../../.prettierignore \"src/**/*.ts\" \"test/**/*.ts\" \"*.{js,json}\"", "integration-test:browser": "karma start --single-run", @@ -87,6 +85,7 @@ "tslib": "^2.0.0" }, "devDependencies": { + "@azure/dev-tool": "^1.0.0", "@azure/eslint-plugin-azure-sdk": "^3.0.0", "@azure/identity": "^1.1.0-preview", "@azure/test-utils-recorder": "^1.0.0", diff --git a/sdk/formrecognizer/ai-form-recognizer/test/browser/formrecognizerclient.spec.ts b/sdk/formrecognizer/ai-form-recognizer/test/browser/formrecognizerclient.spec.ts index 1400f751f571..4009f8440e47 100644 --- a/sdk/formrecognizer/ai-form-recognizer/test/browser/formrecognizerclient.spec.ts +++ b/sdk/formrecognizer/ai-form-recognizer/test/browser/formrecognizerclient.spec.ts @@ -16,9 +16,9 @@ describe("FormRecognizerClient browser only", () => { ({ recorder, client } = createRecordedRecognizerClient(this, apiKey)); }); - afterEach(function() { + afterEach(async function() { if (recorder) { - recorder.stop(); + await recorder.stop(); } }); diff --git a/sdk/formrecognizer/ai-form-recognizer/test/browser/formtrainingclient.spec.ts b/sdk/formrecognizer/ai-form-recognizer/test/browser/formtrainingclient.spec.ts index 524daa217c27..f3363ba65a05 100644 --- a/sdk/formrecognizer/ai-form-recognizer/test/browser/formtrainingclient.spec.ts +++ b/sdk/formrecognizer/ai-form-recognizer/test/browser/formtrainingclient.spec.ts @@ -33,9 +33,9 @@ describe("FormTrainingClient browser only", () => { ); }); - afterEach(function() { + afterEach(async function() { if (recorder) { - recorder.stop(); + await recorder.stop(); } }); @@ -214,9 +214,9 @@ describe("FormRecognizerClient custom form recognition browser only", () => { ({ recorder, client: recognizerClient } = createRecordedRecognizerClient(this, apiKey)); }); - afterEach(function() { + afterEach(async function() { if (recorder) { - recorder.stop(); + await recorder.stop(); } }); it("recognizes form url unlabeled model", async () => { diff --git a/sdk/formrecognizer/ai-form-recognizer/test/node/formrecognizerclient.spec.ts b/sdk/formrecognizer/ai-form-recognizer/test/node/formrecognizerclient.spec.ts index 4bec0ebcc6ac..fa7ce1ecbb10 100644 --- a/sdk/formrecognizer/ai-form-recognizer/test/node/formrecognizerclient.spec.ts +++ b/sdk/formrecognizer/ai-form-recognizer/test/node/formrecognizerclient.spec.ts @@ -19,9 +19,9 @@ describe("FormRecognizerClient NodeJS only", () => { ({ recorder, client } = createRecordedRecognizerClient(this, apiKey)); }); - afterEach(function() { + afterEach(async function() { if (recorder) { - recorder.stop(); + await recorder.stop(); } }); @@ -157,9 +157,9 @@ describe("[AAD] FormRecognizerClient NodeJS only", () => { ({ recorder, client } = createRecordedRecognizerClient(this)); }); - afterEach(function() { + afterEach(async function() { if (recorder) { - recorder.stop(); + await recorder.stop(); } }); diff --git a/sdk/formrecognizer/ai-form-recognizer/test/node/formtrainingclient.spec.ts b/sdk/formrecognizer/ai-form-recognizer/test/node/formtrainingclient.spec.ts index a7b3d1adca57..3812ed482ada 100644 --- a/sdk/formrecognizer/ai-form-recognizer/test/node/formtrainingclient.spec.ts +++ b/sdk/formrecognizer/ai-form-recognizer/test/node/formtrainingclient.spec.ts @@ -35,9 +35,9 @@ describe("FormTrainingClient NodeJS only", () => { ({ recorder, client: trainingClient } = createRecordedTrainingClient(this, apiKey)); }); - afterEach(function() { + afterEach(async function() { if (recorder) { - recorder.stop(); + await recorder.stop(); } }); @@ -237,9 +237,9 @@ describe("FormRecognizerClient form recognition NodeJS", () => { ({ recorder, client: recognizerClient } = createRecordedRecognizerClient(this, apiKey)); }); - afterEach(function() { + afterEach(async function() { if (recorder) { - recorder.stop(); + await recorder.stop(); } }); @@ -396,9 +396,9 @@ describe("[AAD] FormTrainingClient NodeJS only", () => { ({ recorder, client: trainingClient } = createRecordedTrainingClient(this)); }); - afterEach(function() { + afterEach(async function() { if (recorder) { - recorder.stop(); + await recorder.stop(); } }); diff --git a/sdk/identity/identity/README.md b/sdk/identity/identity/README.md index 918f723612fd..96f667dbbf77 100644 --- a/sdk/identity/identity/README.md +++ b/sdk/identity/identity/README.md @@ -22,7 +22,7 @@ npm install --save @azure/identity ## Key concepts -If this is your first time using `@azure/identity` or the Microsoft identity platform (Azure Active Directory), we recommend that you read [Using `@azure/identity` with Microsoft Identity Platform](/documentation/using-azure-identity.md) first. This document will give you a deeper understanding of the platform and how to configure your Azure account correctly. +If this is your first time using `@azure/identity` or the Microsoft identity platform (Azure Active Directory), we recommend that you read [Using `@azure/identity` with Microsoft Identity Platform](https://github.com/Azure/azure-sdk-for-js/blob/master/documentation/using-azure-identity.md) first. This document will give you a deeper understanding of the platform and how to configure your Azure account correctly. ### Credentials diff --git a/sdk/keyvault/keyvault-certificates/karma.conf.js b/sdk/keyvault/keyvault-certificates/karma.conf.js index 38ec4db2cb18..105085fe393b 100644 --- a/sdk/keyvault/keyvault-certificates/karma.conf.js +++ b/sdk/keyvault/keyvault-certificates/karma.conf.js @@ -104,7 +104,7 @@ module.exports = function(config) { singleRun: false, concurrency: 1, - browserNoActivityTimeout: 180000, + browserNoActivityTimeout: 250000, browserDisconnectTimeout: 10000, browserDisconnectTolerance: 3, browserConsoleLogOptions: { @@ -116,7 +116,7 @@ module.exports = function(config) { mocha: { // change Karma's debug.html to the mocha web reporter reporter: "html", - timeout: "180000" + timeout: "250000" } } }); diff --git a/sdk/keyvault/keyvault-certificates/package.json b/sdk/keyvault/keyvault-certificates/package.json index 26f3463ee9a1..6fba3d468b52 100644 --- a/sdk/keyvault/keyvault-certificates/package.json +++ b/sdk/keyvault/keyvault-certificates/package.json @@ -40,20 +40,19 @@ }, "scripts": { "audit": "node ../../../common/scripts/rush-audit.js && rimraf node_modules package-lock.json && npm i --package-lock-only 2>&1 && npm audit", - "build:samples": "node ../../../common/scripts/prep-samples.js && cd samples && tsc", + "build:minify": "uglifyjs -c -m --comments --source-map \"content='./dist/index.js.map'\" -o ./dist/index.min.js ./dist/index.js 2>&1", + "build:samples": "dev-tool samples prep && cd dist-samples && tsc", "build:es6": "tsc -p tsconfig.json", "build:nodebrowser": "rollup -c 2>&1", "build:test": "npm run build:es6 && rollup -c rollup.test.config.js 2>&1", "build": "npm run extract-api && npm run build:es6 && npm run build:nodebrowser", "check-format": "prettier --list-different --config ../../.prettierrc.json --ignore-path ../../.prettierignore \"src/**/*.ts\" \"test/**/*.ts\" \"*.{js,json}\"", "clean": "rimraf dist-esm dist-test typings *.tgz *.log samples/typescript/dist", - "execute:js-samples": "node ../../../common/scripts/run-samples.js samples/javascript/", - "execute:ts-samples": "node ../../../common/scripts/run-samples.js samples/typescript/dist/keyvault-certificates/samples/typescript/src/", - "execute:samples": "npm run build:samples && npm run execute:js-samples && npm run execute:ts-samples", + "execute:samples": "npm run build:samples && dev-tool samples run dist-samples/javascript dist-samples/typescript/dist/keyvault-certificates/dist-samples/typescript/src/", "extract-api": "tsc -p . && api-extractor run --local", "format": "prettier --write --config ../../.prettierrc.json --ignore-path ../../.prettierignore \"src/**/*.ts\" \"samples/*.ts\" \"test/**/*.ts\" \"*.{js,json}\"", "integration-test:browser": "karma start --single-run", - "integration-test:node": "nyc mocha -r esm --require source-map-support/register --reporter ../../../common/tools/mocha-multi-reporter.js --timeout 180000 --full-trace dist-esm/**/*.spec.js", + "integration-test:node": "nyc mocha -r esm --require source-map-support/register --reporter ../../../common/tools/mocha-multi-reporter.js --timeout 250000 --full-trace dist-esm/**/*.spec.js", "integration-test:node:no-timeout": "nyc mocha -r esm --require source-map-support/register --reporter ../../../common/tools/mocha-multi-reporter.js --no-timeouts --full-trace dist-esm/**/*.spec.js", "integration-test": "npm run integration-test:node && npm run integration-test:browser", "lint:fix": "eslint package.json api-extractor.json src test --ext .ts --fix --fix-type [problem,suggestion]", @@ -66,7 +65,7 @@ "test:node": "npm run clean && npm run build:test && npm run unit-test:node", "test": "npm run clean && npm run build:test && npm run unit-test", "unit-test:browser": "karma start --single-run", - "unit-test:node": "mocha --require source-map-support/register --reporter ../../../common/tools/mocha-multi-reporter.js --timeout 180000 --full-trace dist-test/index.node.js", + "unit-test:node": "mocha --require source-map-support/register --reporter ../../../common/tools/mocha-multi-reporter.js --timeout 250000 --full-trace dist-test/index.node.js", "unit-test:node:no-timeout": "mocha --require source-map-support/register --reporter ../../../common/tools/mocha-multi-reporter.js --no-timeouts --full-trace dist-test/index.node.js", "unit-test": "npm run unit-test:node && npm run unit-test:browser" }, @@ -94,6 +93,7 @@ "tslib": "^2.0.0" }, "devDependencies": { + "@azure/dev-tool": "^1.0.0", "@azure/eslint-plugin-azure-sdk": "^3.0.0", "@azure/identity": "^1.1.0-preview", "@azure/keyvault-secrets": "^4.1.0-preview.2", diff --git a/sdk/keyvault/keyvault-certificates/test/internal/challengeBasedAuthenticationPolicy.spec.ts b/sdk/keyvault/keyvault-certificates/test/internal/challengeBasedAuthenticationPolicy.spec.ts index 9f3d9b9b4574..4e521a888aa7 100644 --- a/sdk/keyvault/keyvault-certificates/test/internal/challengeBasedAuthenticationPolicy.spec.ts +++ b/sdk/keyvault/keyvault-certificates/test/internal/challengeBasedAuthenticationPolicy.spec.ts @@ -41,7 +41,7 @@ describe("Challenge based authentication tests", () => { }); afterEach(async function() { - recorder.stop(); + await recorder.stop(); }); // The tests follow diff --git a/sdk/keyvault/keyvault-certificates/test/public/CRUD.spec.ts b/sdk/keyvault/keyvault-certificates/test/public/CRUD.spec.ts index 16bf25f4a35b..b317aebdac61 100644 --- a/sdk/keyvault/keyvault-certificates/test/public/CRUD.spec.ts +++ b/sdk/keyvault/keyvault-certificates/test/public/CRUD.spec.ts @@ -44,7 +44,7 @@ describe("Certificates client - create, read, update and delete", () => { }); afterEach(async function() { - recorder.stop(); + await recorder.stop(); }); // The tests follow diff --git a/sdk/keyvault/keyvault-certificates/test/public/list.spec.ts b/sdk/keyvault/keyvault-certificates/test/public/list.spec.ts index 3858711303b6..832cb4cd862e 100644 --- a/sdk/keyvault/keyvault-certificates/test/public/list.spec.ts +++ b/sdk/keyvault/keyvault-certificates/test/public/list.spec.ts @@ -35,7 +35,7 @@ describe("Certificates client - list certificates in various ways", () => { }); afterEach(async function() { - recorder.stop(); + await recorder.stop(); }); // The tests follow diff --git a/sdk/keyvault/keyvault-certificates/test/public/lro.create.spec.ts b/sdk/keyvault/keyvault-certificates/test/public/lro.create.spec.ts index 9bdfcc03c536..0319285aff35 100644 --- a/sdk/keyvault/keyvault-certificates/test/public/lro.create.spec.ts +++ b/sdk/keyvault/keyvault-certificates/test/public/lro.create.spec.ts @@ -26,7 +26,7 @@ describe("Certificates client - LRO - create", () => { }); afterEach(async function() { - recorder.stop(); + await recorder.stop(); }); // The tests follow diff --git a/sdk/keyvault/keyvault-certificates/test/public/lro.delete.spec.ts b/sdk/keyvault/keyvault-certificates/test/public/lro.delete.spec.ts index cbe6519e58b8..54d6628eb0ed 100644 --- a/sdk/keyvault/keyvault-certificates/test/public/lro.delete.spec.ts +++ b/sdk/keyvault/keyvault-certificates/test/public/lro.delete.spec.ts @@ -26,7 +26,7 @@ describe("Certificates client - lro - delete", () => { }); afterEach(async function() { - recorder.stop(); + await recorder.stop(); }); // The tests follow diff --git a/sdk/keyvault/keyvault-certificates/test/public/lro.operation.spec.ts b/sdk/keyvault/keyvault-certificates/test/public/lro.operation.spec.ts index f77689d8a09f..3f617de0025b 100644 --- a/sdk/keyvault/keyvault-certificates/test/public/lro.operation.spec.ts +++ b/sdk/keyvault/keyvault-certificates/test/public/lro.operation.spec.ts @@ -30,7 +30,7 @@ describe("Certificates client - LRO - certificate operation", () => { }); afterEach(async function() { - recorder.stop(); + await recorder.stop(); }); // The tests follow diff --git a/sdk/keyvault/keyvault-certificates/test/public/lro.recover.spec.ts b/sdk/keyvault/keyvault-certificates/test/public/lro.recover.spec.ts index 4d17ee5fd345..4f615e7d8024 100644 --- a/sdk/keyvault/keyvault-certificates/test/public/lro.recover.spec.ts +++ b/sdk/keyvault/keyvault-certificates/test/public/lro.recover.spec.ts @@ -27,7 +27,7 @@ describe("Certificates client - LRO - recoverDelete", () => { }); afterEach(async function() { - recorder.stop(); + await recorder.stop(); }); // The tests follow diff --git a/sdk/keyvault/keyvault-certificates/test/public/mergeAndImport.spec.ts b/sdk/keyvault/keyvault-certificates/test/public/mergeAndImport.spec.ts index 1b4ed7b7b146..a4ae9d649cd0 100644 --- a/sdk/keyvault/keyvault-certificates/test/public/mergeAndImport.spec.ts +++ b/sdk/keyvault/keyvault-certificates/test/public/mergeAndImport.spec.ts @@ -36,7 +36,7 @@ describe("Certificates client - merge and import certificates", () => { }); afterEach(async function() { - recorder.stop(); + await recorder.stop(); }); // The tests follow diff --git a/sdk/keyvault/keyvault-certificates/test/public/recoverBackupRestore.spec.ts b/sdk/keyvault/keyvault-certificates/test/public/recoverBackupRestore.spec.ts index bbfc4c700c29..3ed56c429381 100644 --- a/sdk/keyvault/keyvault-certificates/test/public/recoverBackupRestore.spec.ts +++ b/sdk/keyvault/keyvault-certificates/test/public/recoverBackupRestore.spec.ts @@ -32,7 +32,7 @@ describe("Certificates client - restore certificates and recover backups", () => }); afterEach(async function() { - recorder.stop(); + await recorder.stop(); }); // The tests follow diff --git a/sdk/keyvault/keyvault-keys/package.json b/sdk/keyvault/keyvault-keys/package.json index f5b8bfd46924..2a823dfdec8e 100644 --- a/sdk/keyvault/keyvault-keys/package.json +++ b/sdk/keyvault/keyvault-keys/package.json @@ -40,16 +40,15 @@ }, "scripts": { "audit": "node ../../../common/scripts/rush-audit.js && rimraf node_modules package-lock.json && npm i --package-lock-only 2>&1 && npm audit", - "build:samples": "node ../../../common/scripts/prep-samples.js && cd samples && tsc", + "build:minify": "uglifyjs -c -m --comments --source-map \"content='./dist/index.js.map'\" -o ./dist/index.min.js ./dist/index.js 2>&1", + "build:samples": "dev-tool samples prep && cd dist-samples && tsc", "build:es6": "tsc -p tsconfig.json", "build:nodebrowser": "rollup -c 2>&1", "build:test": "npm run build:es6 && rollup -c rollup.test.config.js 2>&1", "build": "npm run extract-api && npm run build:es6 && npm run build:nodebrowser", "check-format": "prettier --list-different --config ../../.prettierrc.json --ignore-path ../../.prettierignore \"src/**/*.ts\" \"test/**/*.ts\" \"*.{js,json}\"", "clean": "rimraf dist dist-esm dist-test types *.tgz *.log dist-browser statistics.html coverage && rimraf src/**/*.js && rimraf test/**/*.js", - "execute:js-samples": "node ../../../common/scripts/run-samples.js samples/javascript/", - "execute:ts-samples": "node ../../../common/scripts/run-samples.js samples/typescript/dist/keyvault-keys/samples/typescript/src/", - "execute:samples": "npm run build:samples && npm run execute:js-samples && npm run execute:ts-samples", + "execute:samples": "npm run build:samples && dev-tool samples run dist-samples/javascript dist-samples/typescript/dist/keyvault-keys/dist-samples/typescript/src/", "extract-api": "tsc -p . && api-extractor run --local", "format": "prettier --write --config ../../.prettierrc.json --ignore-path ../../.prettierignore \"src/**/*.ts\" \"test/**/*.ts\" \"*.{js,json}\"", "integration-test:browser": "karma start --single-run", @@ -94,6 +93,7 @@ }, "devDependencies": { "@azure/abort-controller": "^1.0.0", + "@azure/dev-tool": "^1.0.0", "@azure/eslint-plugin-azure-sdk": "^3.0.0", "@azure/identity": "^1.1.0-preview", "@azure/test-utils-recorder": "^1.0.0", diff --git a/sdk/keyvault/keyvault-keys/test/internal/challengeBasedAuthenticationPolicy.spec.ts b/sdk/keyvault/keyvault-keys/test/internal/challengeBasedAuthenticationPolicy.spec.ts index e08a92a5f214..b4b116efc511 100644 --- a/sdk/keyvault/keyvault-keys/test/internal/challengeBasedAuthenticationPolicy.spec.ts +++ b/sdk/keyvault/keyvault-keys/test/internal/challengeBasedAuthenticationPolicy.spec.ts @@ -35,7 +35,7 @@ describe("Challenge based authentication tests", () => { }); afterEach(async function() { - recorder.stop(); + await recorder.stop(); }); // The tests follow diff --git a/sdk/keyvault/keyvault-keys/test/public/CRUD.spec.ts b/sdk/keyvault/keyvault-keys/test/public/CRUD.spec.ts index 9973b0a35479..ab1f8347a189 100644 --- a/sdk/keyvault/keyvault-keys/test/public/CRUD.spec.ts +++ b/sdk/keyvault/keyvault-keys/test/public/CRUD.spec.ts @@ -33,7 +33,7 @@ describe("Keys client - create, read, update and delete operations", () => { }); afterEach(async function() { - recorder.stop(); + await recorder.stop(); }); // The tests follow diff --git a/sdk/keyvault/keyvault-keys/test/public/crypto.spec.ts b/sdk/keyvault/keyvault-keys/test/public/crypto.spec.ts index dc68eafd4e12..80212b7ebffb 100644 --- a/sdk/keyvault/keyvault-keys/test/public/crypto.spec.ts +++ b/sdk/keyvault/keyvault-keys/test/public/crypto.spec.ts @@ -45,7 +45,7 @@ describe("CryptographyClient (all decrypts happen remotely)", () => { afterEach(async function() { if (!this.currentTest?.isPending()) { await testClient.flushKey(keyName); - recorder.stop(); + await recorder.stop(); } }); diff --git a/sdk/keyvault/keyvault-keys/test/public/import.spec.ts b/sdk/keyvault/keyvault-keys/test/public/import.spec.ts index 26d6bd577ef1..2788491f14f5 100644 --- a/sdk/keyvault/keyvault-keys/test/public/import.spec.ts +++ b/sdk/keyvault/keyvault-keys/test/public/import.spec.ts @@ -25,7 +25,7 @@ describe("Keys client - import keys", () => { }); afterEach(async function() { - recorder.stop(); + await recorder.stop(); }); // The tests follow diff --git a/sdk/keyvault/keyvault-keys/test/public/list.spec.ts b/sdk/keyvault/keyvault-keys/test/public/list.spec.ts index 391809083310..40367a5c4664 100644 --- a/sdk/keyvault/keyvault-keys/test/public/list.spec.ts +++ b/sdk/keyvault/keyvault-keys/test/public/list.spec.ts @@ -26,7 +26,7 @@ describe("Keys client - list keys in various ways", () => { }); afterEach(async function() { - recorder.stop(); + await recorder.stop(); }); // The tests follow diff --git a/sdk/keyvault/keyvault-keys/test/public/lro.delete.spec.ts b/sdk/keyvault/keyvault-keys/test/public/lro.delete.spec.ts index 2027944164a2..0ed4ab39d9a0 100644 --- a/sdk/keyvault/keyvault-keys/test/public/lro.delete.spec.ts +++ b/sdk/keyvault/keyvault-keys/test/public/lro.delete.spec.ts @@ -26,7 +26,7 @@ describe("Keys client - Long Running Operations - delete", () => { }); afterEach(async function() { - recorder.stop(); + await recorder.stop(); }); // The tests follow diff --git a/sdk/keyvault/keyvault-keys/test/public/lro.recoverDelete.spec.ts b/sdk/keyvault/keyvault-keys/test/public/lro.recoverDelete.spec.ts index cbfd6557798e..315d3d0fa0fe 100644 --- a/sdk/keyvault/keyvault-keys/test/public/lro.recoverDelete.spec.ts +++ b/sdk/keyvault/keyvault-keys/test/public/lro.recoverDelete.spec.ts @@ -27,7 +27,7 @@ describe("Keys client - Long Running Operations - recoverDelete", () => { }); afterEach(async function() { - recorder.stop(); + await recorder.stop(); }); // The tests follow diff --git a/sdk/keyvault/keyvault-keys/test/public/recoverBackupRestore.spec.ts b/sdk/keyvault/keyvault-keys/test/public/recoverBackupRestore.spec.ts index deb437cc5d31..8d44516442b6 100644 --- a/sdk/keyvault/keyvault-keys/test/public/recoverBackupRestore.spec.ts +++ b/sdk/keyvault/keyvault-keys/test/public/recoverBackupRestore.spec.ts @@ -27,7 +27,7 @@ describe("Keys client - restore keys and recover backups", () => { }); afterEach(async function() { - recorder.stop(); + await recorder.stop(); }); // The tests follow diff --git a/sdk/keyvault/keyvault-secrets/package.json b/sdk/keyvault/keyvault-secrets/package.json index 93c01a8231a8..7c7edf278dcf 100644 --- a/sdk/keyvault/keyvault-secrets/package.json +++ b/sdk/keyvault/keyvault-secrets/package.json @@ -43,16 +43,15 @@ }, "scripts": { "audit": "node ../../../common/scripts/rush-audit.js && rimraf node_modules package-lock.json && npm i --package-lock-only 2>&1 && npm audit", - "build:samples": "node ../../../common/scripts/prep-samples.js && cd samples && tsc", + "build:minify": "uglifyjs -c -m --comments --source-map \"content='./dist/index.js.map'\" -o ./dist/index.min.js ./dist/index.js 2>&1", + "build:samples": "dev-tool samples prep && cd dist-samples && tsc", "build:es6": "tsc -p tsconfig.json", "build:nodebrowser": "rollup -c 2>&1", "build:test": "npm run build:es6 && rollup -c rollup.test.config.js 2>&1", "build": "npm run extract-api && npm run build:es6 && npm run build:nodebrowser", "check-format": "prettier --list-different --config ../../.prettierrc.json --ignore-path ../../.prettierignore \"src/**/*.ts\" \"test/**/*.ts\" \"*.{js,json}\"", "clean": "rimraf dist dist-esm dist-test types *.tgz *.log dist-browser statistics.html coverage && rimraf src/**/*.js && rimraf test/**/*.js", - "execute:js-samples": "node ../../../common/scripts/run-samples.js samples/javascript/", - "execute:ts-samples": "node ../../../common/scripts/run-samples.js samples/typescript/dist/keyvault-secrets/samples/typescript/src/", - "execute:samples": "npm run build:samples && npm run execute:js-samples && npm run execute:ts-samples", + "execute:samples": "npm run build:samples && dev-tool samples run dist-samples/javascript dist-samples/typescript/dist/keyvault-secrets/dist-samples/typescript/src/", "extract-api": "tsc -p . && api-extractor run --local", "format": "prettier --write --config ../../.prettierrc.json --ignore-path ../../.prettierignore \"src/**/*.ts\" \"test/**/*.ts\" \"*.{js,json}\"", "integration-test:browser": "karma start --single-run", @@ -97,6 +96,7 @@ "tslib": "^2.0.0" }, "devDependencies": { + "@azure/dev-tool": "^1.0.0", "@azure/eslint-plugin-azure-sdk": "^3.0.0", "@azure/identity": "^1.1.0-preview", "@azure/test-utils-recorder": "^1.0.0", diff --git a/sdk/keyvault/keyvault-secrets/test/internal/challengeBasedAuthenticationPolicy.spec.ts b/sdk/keyvault/keyvault-secrets/test/internal/challengeBasedAuthenticationPolicy.spec.ts index af362a4f19fb..93b07af149e2 100644 --- a/sdk/keyvault/keyvault-secrets/test/internal/challengeBasedAuthenticationPolicy.spec.ts +++ b/sdk/keyvault/keyvault-secrets/test/internal/challengeBasedAuthenticationPolicy.spec.ts @@ -35,7 +35,7 @@ describe("Challenge based authentication tests", () => { }); afterEach(async function() { - recorder.stop(); + await recorder.stop(); }); // The tests follow diff --git a/sdk/keyvault/keyvault-secrets/test/public/CRUD.spec.ts b/sdk/keyvault/keyvault-secrets/test/public/CRUD.spec.ts index ec127fa594f3..ecbe8b655f61 100644 --- a/sdk/keyvault/keyvault-secrets/test/public/CRUD.spec.ts +++ b/sdk/keyvault/keyvault-secrets/test/public/CRUD.spec.ts @@ -28,7 +28,7 @@ describe("Secret client - create, read, update and delete operations", () => { }); afterEach(async function() { - recorder.stop(); + await recorder.stop(); }); // The tests follow diff --git a/sdk/keyvault/keyvault-secrets/test/public/list.spec.ts b/sdk/keyvault/keyvault-secrets/test/public/list.spec.ts index fe862cc07bec..0b88522d563c 100644 --- a/sdk/keyvault/keyvault-secrets/test/public/list.spec.ts +++ b/sdk/keyvault/keyvault-secrets/test/public/list.spec.ts @@ -30,7 +30,7 @@ describe("Secret client - list secrets in various ways", () => { }); afterEach(async function() { - recorder.stop(); + await recorder.stop(); }); // The tests follow diff --git a/sdk/keyvault/keyvault-secrets/test/public/lro.delete.spec.ts b/sdk/keyvault/keyvault-secrets/test/public/lro.delete.spec.ts index ed4b4fad761b..dd1aa09114e0 100644 --- a/sdk/keyvault/keyvault-secrets/test/public/lro.delete.spec.ts +++ b/sdk/keyvault/keyvault-secrets/test/public/lro.delete.spec.ts @@ -27,7 +27,7 @@ describe("Secrets client - Long Running Operations - delete", () => { }); afterEach(async function() { - recorder.stop(); + await recorder.stop(); }); // The tests follow diff --git a/sdk/keyvault/keyvault-secrets/test/public/lro.recover.spec.ts b/sdk/keyvault/keyvault-secrets/test/public/lro.recover.spec.ts index daffe1caf3f9..87d222faa074 100644 --- a/sdk/keyvault/keyvault-secrets/test/public/lro.recover.spec.ts +++ b/sdk/keyvault/keyvault-secrets/test/public/lro.recover.spec.ts @@ -27,7 +27,7 @@ describe("Secrets client - Long Running Operations - recoverDelete", () => { }); afterEach(async function() { - recorder.stop(); + await recorder.stop(); }); // The tests follow diff --git a/sdk/keyvault/keyvault-secrets/test/public/recoverBackupRestore.spec.ts b/sdk/keyvault/keyvault-secrets/test/public/recoverBackupRestore.spec.ts index 5e6fc01114bd..e209aa36cf1b 100644 --- a/sdk/keyvault/keyvault-secrets/test/public/recoverBackupRestore.spec.ts +++ b/sdk/keyvault/keyvault-secrets/test/public/recoverBackupRestore.spec.ts @@ -27,7 +27,7 @@ describe("Secret client - restore secrets and recover backups", () => { }); afterEach(async function() { - recorder.stop(); + await recorder.stop(); }); // The tests follow diff --git a/sdk/mariadb/arm-mariadb/LICENSE.txt b/sdk/mariadb/arm-mariadb/LICENSE.txt index b73b4a1293c3..ea8fb1516028 100644 --- a/sdk/mariadb/arm-mariadb/LICENSE.txt +++ b/sdk/mariadb/arm-mariadb/LICENSE.txt @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2019 Microsoft +Copyright (c) 2020 Microsoft Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/sdk/mariadb/arm-mariadb/README.md b/sdk/mariadb/arm-mariadb/README.md index 7a1dfd50bfe0..dd6a492ef740 100644 --- a/sdk/mariadb/arm-mariadb/README.md +++ b/sdk/mariadb/arm-mariadb/README.md @@ -19,8 +19,9 @@ npm install @azure/arm-mariadb ##### Install @azure/ms-rest-nodeauth +- Please install minimum version of `"@azure/ms-rest-nodeauth": "^3.0.0"`. ```bash -npm install @azure/ms-rest-nodeauth +npm install @azure/ms-rest-nodeauth@"^3.0.0" ``` ##### Sample code @@ -99,4 +100,4 @@ See https://github.com/Azure/ms-rest-browserauth to learn how to authenticate to - [Microsoft Azure SDK for Javascript](https://github.com/Azure/azure-sdk-for-js) -![Impressions](https://azure-sdk-impressions.azurewebsites.net/api/impressions/azure-sdk-for-js%2Fsdk%2Fmariadb%2Farm-mariadb%2FREADME.png) +![Impressions](https://azure-sdk-impressions.azurewebsites.net/api/impressions/azure-sdk-for-js/sdk/mariadb/arm-mariadb/README.png) diff --git a/sdk/mariadb/arm-mariadb/package.json b/sdk/mariadb/arm-mariadb/package.json index d9d6d2e1e6d0..390d67319e76 100644 --- a/sdk/mariadb/arm-mariadb/package.json +++ b/sdk/mariadb/arm-mariadb/package.json @@ -4,9 +4,9 @@ "description": "MariaDBManagementClient Library with typescript type definitions for node.js and browser.", "version": "1.4.0", "dependencies": { - "@azure/ms-rest-azure-js": "^1.3.2", - "@azure/ms-rest-js": "^1.8.1", - "tslib": "^1.9.3" + "@azure/ms-rest-azure-js": "^2.0.1", + "@azure/ms-rest-js": "^2.0.4", + "tslib": "^1.10.0" }, "keywords": [ "node", @@ -20,11 +20,11 @@ "module": "./esm/mariaDBManagementClient.js", "types": "./esm/mariaDBManagementClient.d.ts", "devDependencies": { - "typescript": "^3.1.1", - "rollup": "^0.66.2", - "rollup-plugin-node-resolve": "^3.4.0", + "typescript": "^3.5.3", + "rollup": "^1.18.0", + "rollup-plugin-node-resolve": "^5.2.0", "rollup-plugin-sourcemaps": "^0.4.2", - "uglify-js": "^3.4.9" + "uglify-js": "^3.6.0" }, "homepage": "https://github.com/Azure/azure-sdk-for-js/tree/master/sdk/mariadb/arm-mariadb", "repository": { diff --git a/sdk/mariadb/arm-mariadb/rollup.config.js b/sdk/mariadb/arm-mariadb/rollup.config.js index 5735360934e7..ee799d1882f8 100644 --- a/sdk/mariadb/arm-mariadb/rollup.config.js +++ b/sdk/mariadb/arm-mariadb/rollup.config.js @@ -29,7 +29,7 @@ const config = { */` }, plugins: [ - nodeResolve({ module: true }), + nodeResolve({ mainFields: ['module', 'main'] }), sourcemaps() ] }; diff --git a/sdk/mariadb/arm-mariadb/src/mariaDBManagementClient.ts b/sdk/mariadb/arm-mariadb/src/mariaDBManagementClient.ts index b88492aa13ab..6a44946eb457 100644 --- a/sdk/mariadb/arm-mariadb/src/mariaDBManagementClient.ts +++ b/sdk/mariadb/arm-mariadb/src/mariaDBManagementClient.ts @@ -9,8 +9,10 @@ */ import * as msRest from "@azure/ms-rest-js"; +import * as msRestAzure from "@azure/ms-rest-azure-js"; import * as Models from "./models"; import * as Mappers from "./models/mappers"; +import * as Parameters from "./models/parameters"; import * as operations from "./operations"; import { MariaDBManagementClientContext } from "./mariaDBManagementClientContext"; @@ -26,13 +28,22 @@ class MariaDBManagementClient extends MariaDBManagementClientContext { logFiles: operations.LogFiles; locationBasedPerformanceTier: operations.LocationBasedPerformanceTier; checkNameAvailability: operations.CheckNameAvailability; - serverSecurityAlertPolicies: operations.ServerSecurityAlertPolicies; operations: operations.Operations; + queryTexts: operations.QueryTexts; + topQueryStatistics: operations.TopQueryStatistics; + waitStatistics: operations.WaitStatistics; + advisors: operations.Advisors; + recommendedActions: operations.RecommendedActions; + locationBasedRecommendedActionSessionsOperationStatus: operations.LocationBasedRecommendedActionSessionsOperationStatus; + locationBasedRecommendedActionSessionsResult: operations.LocationBasedRecommendedActionSessionsResult; + privateEndpointConnections: operations.PrivateEndpointConnections; + privateLinkResources: operations.PrivateLinkResources; + serverSecurityAlertPolicies: operations.ServerSecurityAlertPolicies; /** * Initializes a new instance of the MariaDBManagementClient class. * @param credentials Credentials needed for the client to connect to Azure. - * @param subscriptionId The subscription ID that identifies an Azure subscription. + * @param subscriptionId The ID of the target subscription. * @param [options] The parameter options */ constructor(credentials: msRest.ServiceClientCredentials, subscriptionId: string, options?: Models.MariaDBManagementClientOptions) { @@ -46,12 +57,83 @@ class MariaDBManagementClient extends MariaDBManagementClientContext { this.logFiles = new operations.LogFiles(this); this.locationBasedPerformanceTier = new operations.LocationBasedPerformanceTier(this); this.checkNameAvailability = new operations.CheckNameAvailability(this); - this.serverSecurityAlertPolicies = new operations.ServerSecurityAlertPolicies(this); this.operations = new operations.Operations(this); + this.queryTexts = new operations.QueryTexts(this); + this.topQueryStatistics = new operations.TopQueryStatistics(this); + this.waitStatistics = new operations.WaitStatistics(this); + this.advisors = new operations.Advisors(this); + this.recommendedActions = new operations.RecommendedActions(this); + this.locationBasedRecommendedActionSessionsOperationStatus = new operations.LocationBasedRecommendedActionSessionsOperationStatus(this); + this.locationBasedRecommendedActionSessionsResult = new operations.LocationBasedRecommendedActionSessionsResult(this); + this.privateEndpointConnections = new operations.PrivateEndpointConnections(this); + this.privateLinkResources = new operations.PrivateLinkResources(this); + this.serverSecurityAlertPolicies = new operations.ServerSecurityAlertPolicies(this); + } + + /** + * Create recommendation action session for the advisor. + * @param resourceGroupName The name of the resource group. The name is case insensitive. + * @param serverName The name of the server. + * @param advisorName The advisor name for recommendation action. + * @param databaseName The name of the database. + * @param [options] The optional parameters + * @returns Promise + */ + createRecommendedActionSession(resourceGroupName: string, serverName: string, advisorName: string, databaseName: string, options?: msRest.RequestOptionsBase): Promise { + return this.beginCreateRecommendedActionSession(resourceGroupName,serverName,advisorName,databaseName,options) + .then(lroPoller => lroPoller.pollUntilFinished()); + } + + /** + * Create recommendation action session for the advisor. + * @param resourceGroupName The name of the resource group. The name is case insensitive. + * @param serverName The name of the server. + * @param advisorName The advisor name for recommendation action. + * @param databaseName The name of the database. + * @param [options] The optional parameters + * @returns Promise + */ + beginCreateRecommendedActionSession(resourceGroupName: string, serverName: string, advisorName: string, databaseName: string, options?: msRest.RequestOptionsBase): Promise { + return this.sendLRORequest( + { + resourceGroupName, + serverName, + advisorName, + databaseName, + options + }, + beginCreateRecommendedActionSessionOperationSpec, + options); } } // Operation Specifications +const serializer = new msRest.Serializer(Mappers); +const beginCreateRecommendedActionSessionOperationSpec: msRest.OperationSpec = { + httpMethod: "POST", + path: "subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.DBforMariaDB/servers/{serverName}/advisors/{advisorName}/createRecommendedActionSession", + urlParameters: [ + Parameters.subscriptionId, + Parameters.resourceGroupName, + Parameters.serverName, + Parameters.advisorName + ], + queryParameters: [ + Parameters.apiVersion, + Parameters.databaseName + ], + headerParameters: [ + Parameters.acceptLanguage + ], + responses: { + 200: {}, + 202: {}, + default: { + bodyMapper: Mappers.CloudError + } + }, + serializer +}; export { MariaDBManagementClient, diff --git a/sdk/mariadb/arm-mariadb/src/mariaDBManagementClientContext.ts b/sdk/mariadb/arm-mariadb/src/mariaDBManagementClientContext.ts index 9c249c826287..af21bd14795b 100644 --- a/sdk/mariadb/arm-mariadb/src/mariaDBManagementClientContext.ts +++ b/sdk/mariadb/arm-mariadb/src/mariaDBManagementClientContext.ts @@ -17,13 +17,13 @@ const packageVersion = "1.4.0"; export class MariaDBManagementClientContext extends msRestAzure.AzureServiceClient { credentials: msRest.ServiceClientCredentials; - subscriptionId: string; apiVersion?: string; + subscriptionId: string; /** * Initializes a new instance of the MariaDBManagementClient class. * @param credentials Credentials needed for the client to connect to Azure. - * @param subscriptionId The subscription ID that identifies an Azure subscription. + * @param subscriptionId The ID of the target subscription. * @param [options] The parameter options */ constructor(credentials: msRest.ServiceClientCredentials, subscriptionId: string, options?: Models.MariaDBManagementClientOptions) { diff --git a/sdk/mariadb/arm-mariadb/src/models/advisorsMappers.ts b/sdk/mariadb/arm-mariadb/src/models/advisorsMappers.ts new file mode 100644 index 000000000000..28075c62a591 --- /dev/null +++ b/sdk/mariadb/arm-mariadb/src/models/advisorsMappers.ts @@ -0,0 +1,40 @@ +/* + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + * Changes may cause incorrect behavior and will be lost if the code is regenerated. + */ + +export { + discriminators, + Advisor, + AdvisorsResultList, + AzureEntityResource, + BaseResource, + CloudError, + Configuration, + Database, + FirewallRule, + LogFile, + PrivateEndpointConnection, + PrivateEndpointProperty, + PrivateLinkResource, + PrivateLinkResourceProperties, + PrivateLinkServiceConnectionStateProperty, + ProxyResource, + QueryStatistic, + QueryText, + RecommendationAction, + Resource, + Server, + ServerPrivateEndpointConnection, + ServerPrivateEndpointConnectionProperties, + ServerPrivateLinkServiceConnectionStateProperty, + ServerSecurityAlertPolicy, + Sku, + StorageProfile, + TrackedResource, + VirtualNetworkRule, + WaitStatistic +} from "../models/mappers"; diff --git a/sdk/mariadb/arm-mariadb/src/models/configurationsMappers.ts b/sdk/mariadb/arm-mariadb/src/models/configurationsMappers.ts index 3df779f095a3..292b40b1fcf0 100644 --- a/sdk/mariadb/arm-mariadb/src/models/configurationsMappers.ts +++ b/sdk/mariadb/arm-mariadb/src/models/configurationsMappers.ts @@ -8,6 +8,8 @@ export { discriminators, + Advisor, + AzureEntityResource, BaseResource, CloudError, Configuration, @@ -15,11 +17,24 @@ export { Database, FirewallRule, LogFile, + PrivateEndpointConnection, + PrivateEndpointProperty, + PrivateLinkResource, + PrivateLinkResourceProperties, + PrivateLinkServiceConnectionStateProperty, ProxyResource, + QueryStatistic, + QueryText, + RecommendationAction, + Resource, Server, + ServerPrivateEndpointConnection, + ServerPrivateEndpointConnectionProperties, + ServerPrivateLinkServiceConnectionStateProperty, ServerSecurityAlertPolicy, Sku, StorageProfile, TrackedResource, - VirtualNetworkRule + VirtualNetworkRule, + WaitStatistic } from "../models/mappers"; diff --git a/sdk/mariadb/arm-mariadb/src/models/databasesMappers.ts b/sdk/mariadb/arm-mariadb/src/models/databasesMappers.ts index aab1065ee094..18406ca68c66 100644 --- a/sdk/mariadb/arm-mariadb/src/models/databasesMappers.ts +++ b/sdk/mariadb/arm-mariadb/src/models/databasesMappers.ts @@ -8,6 +8,8 @@ export { discriminators, + Advisor, + AzureEntityResource, BaseResource, CloudError, Configuration, @@ -15,11 +17,24 @@ export { DatabaseListResult, FirewallRule, LogFile, + PrivateEndpointConnection, + PrivateEndpointProperty, + PrivateLinkResource, + PrivateLinkResourceProperties, + PrivateLinkServiceConnectionStateProperty, ProxyResource, + QueryStatistic, + QueryText, + RecommendationAction, + Resource, Server, + ServerPrivateEndpointConnection, + ServerPrivateEndpointConnectionProperties, + ServerPrivateLinkServiceConnectionStateProperty, ServerSecurityAlertPolicy, Sku, StorageProfile, TrackedResource, - VirtualNetworkRule + VirtualNetworkRule, + WaitStatistic } from "../models/mappers"; diff --git a/sdk/mariadb/arm-mariadb/src/models/firewallRulesMappers.ts b/sdk/mariadb/arm-mariadb/src/models/firewallRulesMappers.ts index 2b819a0b71bc..05616495b802 100644 --- a/sdk/mariadb/arm-mariadb/src/models/firewallRulesMappers.ts +++ b/sdk/mariadb/arm-mariadb/src/models/firewallRulesMappers.ts @@ -8,6 +8,8 @@ export { discriminators, + Advisor, + AzureEntityResource, BaseResource, CloudError, Configuration, @@ -15,11 +17,24 @@ export { FirewallRule, FirewallRuleListResult, LogFile, + PrivateEndpointConnection, + PrivateEndpointProperty, + PrivateLinkResource, + PrivateLinkResourceProperties, + PrivateLinkServiceConnectionStateProperty, ProxyResource, + QueryStatistic, + QueryText, + RecommendationAction, + Resource, Server, + ServerPrivateEndpointConnection, + ServerPrivateEndpointConnectionProperties, + ServerPrivateLinkServiceConnectionStateProperty, ServerSecurityAlertPolicy, Sku, StorageProfile, TrackedResource, - VirtualNetworkRule + VirtualNetworkRule, + WaitStatistic } from "../models/mappers"; diff --git a/sdk/mariadb/arm-mariadb/src/models/index.ts b/sdk/mariadb/arm-mariadb/src/models/index.ts index 5fd1820dc05a..74f9d7a1bbf4 100644 --- a/sdk/mariadb/arm-mariadb/src/models/index.ts +++ b/sdk/mariadb/arm-mariadb/src/models/index.ts @@ -12,38 +12,106 @@ import * as msRest from "@azure/ms-rest-js"; export { BaseResource, CloudError }; /** - * Resource properties. + * An interface representing PrivateEndpointProperty. */ -export interface ProxyResource extends BaseResource { +export interface PrivateEndpointProperty extends BaseResource { /** - * Resource ID + * Resource id of the private endpoint. + */ + id?: string; +} + +/** + * An interface representing ServerPrivateLinkServiceConnectionStateProperty. + */ +export interface ServerPrivateLinkServiceConnectionStateProperty { + /** + * The private link service connection status. Possible values include: 'Approved', 'Pending', + * 'Rejected', 'Disconnected' + */ + status: PrivateLinkServiceConnectionStateStatus; + /** + * The private link service connection description. + */ + description: string; + /** + * The actions required for private link service connection. Possible values include: 'None' + * **NOTE: This property will not be serialized. It can only be populated by the server.** + */ + readonly actionsRequired?: PrivateLinkServiceConnectionStateActionsRequire; +} + +/** + * Properties of a private endpoint connection. + */ +export interface ServerPrivateEndpointConnectionProperties { + /** + * Private endpoint which the connection belongs to. + */ + privateEndpoint?: PrivateEndpointProperty; + /** + * Connection state of the private endpoint connection. + */ + privateLinkServiceConnectionState?: ServerPrivateLinkServiceConnectionStateProperty; + /** + * State of the private endpoint connection. Possible values include: 'Approving', 'Ready', + * 'Dropping', 'Failed', 'Rejecting' + * **NOTE: This property will not be serialized. It can only be populated by the server.** + */ + readonly provisioningState?: PrivateEndpointProvisioningState; +} + +/** + * A private endpoint connection under a server + */ +export interface ServerPrivateEndpointConnection { + /** + * Resource Id of the private endpoint connection. + * **NOTE: This property will not be serialized. It can only be populated by the server.** + */ + readonly id?: string; + /** + * Private endpoint connection properties + * **NOTE: This property will not be serialized. It can only be populated by the server.** + */ + readonly properties?: ServerPrivateEndpointConnectionProperties; +} + +/** + * An interface representing Resource. + */ +export interface Resource extends BaseResource { + /** + * Fully qualified resource Id for the resource. Ex - + * /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/{resourceProviderNamespace}/{resourceType}/{resourceName} * **NOTE: This property will not be serialized. It can only be populated by the server.** */ readonly id?: string; /** - * Resource name. + * The name of the resource * **NOTE: This property will not be serialized. It can only be populated by the server.** */ readonly name?: string; /** - * Resource type. + * The type of the resource. Ex- Microsoft.Compute/virtualMachines or + * Microsoft.Storage/storageAccounts. * **NOTE: This property will not be serialized. It can only be populated by the server.** */ readonly type?: string; } /** - * Resource properties including location and tags for track resources. + * The resource model definition for a ARM tracked top level resource */ -export interface TrackedResource extends ProxyResource { +export interface TrackedResource extends Resource { /** - * The location the resource resides in. + * Resource tags. */ - location: string; + tags?: { [propertyName: string]: string }; /** - * Application-specific metadata in the form of key-value pairs. + * The geo-location where the resource lives */ - tags?: { [propertyName: string]: string }; + location: string; } /** @@ -90,6 +158,11 @@ export interface ServerPropertiesForCreate { * 'Disabled' */ sslEnforcement?: SslEnforcementEnum; + /** + * Whether or not public network access is allowed for this server. Value is optional but if + * passed in, must be 'Enabled' or 'Disabled'. Possible values include: 'Enabled', 'Disabled' + */ + publicNetworkAccess?: PublicNetworkAccessEnum; /** * Storage profile of a server. */ @@ -113,6 +186,11 @@ export interface ServerPropertiesForDefaultCreate { * 'Disabled' */ sslEnforcement?: SslEnforcementEnum; + /** + * Whether or not public network access is allowed for this server. Value is optional but if + * passed in, must be 'Enabled' or 'Disabled'. Possible values include: 'Enabled', 'Disabled' + */ + publicNetworkAccess?: PublicNetworkAccessEnum; /** * Storage profile of a server. */ @@ -145,6 +223,11 @@ export interface ServerPropertiesForRestore { * 'Disabled' */ sslEnforcement?: SslEnforcementEnum; + /** + * Whether or not public network access is allowed for this server. Value is optional but if + * passed in, must be 'Enabled' or 'Disabled'. Possible values include: 'Enabled', 'Disabled' + */ + publicNetworkAccess?: PublicNetworkAccessEnum; /** * Storage profile of a server. */ @@ -177,6 +260,11 @@ export interface ServerPropertiesForGeoRestore { * 'Disabled' */ sslEnforcement?: SslEnforcementEnum; + /** + * Whether or not public network access is allowed for this server. Value is optional but if + * passed in, must be 'Enabled' or 'Disabled'. Possible values include: 'Enabled', 'Disabled' + */ + publicNetworkAccess?: PublicNetworkAccessEnum; /** * Storage profile of a server. */ @@ -204,6 +292,11 @@ export interface ServerPropertiesForReplica { * 'Disabled' */ sslEnforcement?: SslEnforcementEnum; + /** + * Whether or not public network access is allowed for this server. Value is optional but if + * passed in, must be 'Enabled' or 'Disabled'. Possible values include: 'Enabled', 'Disabled' + */ + publicNetworkAccess?: PublicNetworkAccessEnum; /** * Storage profile of a server. */ @@ -292,6 +385,16 @@ export interface Server extends TrackedResource { * The maximum number of replicas that a master server can have. */ replicaCapacity?: number; + /** + * Whether or not public network access is allowed for this server. Value is optional but if + * passed in, must be 'Enabled' or 'Disabled'. Possible values include: 'Enabled', 'Disabled' + */ + publicNetworkAccess?: PublicNetworkAccessEnum; + /** + * List of private endpoint connections on a server + * **NOTE: This property will not be serialized. It can only be populated by the server.** + */ + readonly privateEndpointConnections?: ServerPrivateEndpointConnection[]; } /** @@ -341,6 +444,11 @@ export interface ServerUpdateParameters { * 'Disabled' */ sslEnforcement?: SslEnforcementEnum; + /** + * Whether or not public network access is allowed for this server. Value is optional but if + * passed in, must be 'Enabled' or 'Disabled'. Possible values include: 'Enabled', 'Disabled' + */ + publicNetworkAccess?: PublicNetworkAccessEnum; /** * The replication role of the server. */ @@ -351,6 +459,13 @@ export interface ServerUpdateParameters { tags?: { [propertyName: string]: string }; } +/** + * The resource model definition for a ARM proxy resource. It will have everything other than + * required location and tags + */ +export interface ProxyResource extends Resource { +} + /** * Represents a server firewall rule. */ @@ -610,141 +725,623 @@ export interface NameAvailability { } /** - * A server security alert policy. + * The resource management error additional info. */ -export interface ServerSecurityAlertPolicy extends ProxyResource { +export interface ErrorAdditionalInfo { /** - * Specifies the state of the policy, whether it is enabled or disabled. Possible values include: - * 'Enabled', 'Disabled' + * The additional info type. + * **NOTE: This property will not be serialized. It can only be populated by the server.** */ - state: ServerSecurityAlertPolicyState; + readonly type?: string; /** - * Specifies an array of alerts that are disabled. Allowed values are: Sql_Injection, - * Sql_Injection_Vulnerability, Access_Anomaly + * The additional info. + * **NOTE: This property will not be serialized. It can only be populated by the server.** */ - disabledAlerts?: string[]; + readonly info?: any; +} + +/** + * The resource management error response. + */ +export interface ErrorResponse { /** - * Specifies an array of e-mail addresses to which the alert is sent. + * The error code. + * **NOTE: This property will not be serialized. It can only be populated by the server.** */ - emailAddresses?: string[]; + readonly code?: string; /** - * Specifies that the alert is sent to the account administrators. + * The error message. + * **NOTE: This property will not be serialized. It can only be populated by the server.** */ - emailAccountAdmins?: boolean; + readonly message?: string; /** - * Specifies the blob storage endpoint (e.g. https://MyAccount.blob.core.windows.net). This blob - * storage will hold all Threat Detection audit logs. + * The error target. + * **NOTE: This property will not be serialized. It can only be populated by the server.** */ - storageEndpoint?: string; + readonly target?: string; /** - * Specifies the identifier key of the Threat Detection audit storage account. + * The error details. + * **NOTE: This property will not be serialized. It can only be populated by the server.** */ - storageAccountAccessKey?: string; + readonly details?: ErrorResponse[]; /** - * Specifies the number of days to keep in the Threat Detection audit logs. + * The error additional info. + * **NOTE: This property will not be serialized. It can only be populated by the server.** */ - retentionDays?: number; + readonly additionalInfo?: ErrorAdditionalInfo[]; } /** - * An interface representing MariaDBManagementClientOptions. + * The resource model definition for a Azure Resource Manager resource with an etag. */ -export interface MariaDBManagementClientOptions extends AzureServiceClientOptions { - baseUri?: string; +export interface AzureEntityResource extends Resource { + /** + * Resource Etag. + * **NOTE: This property will not be serialized. It can only be populated by the server.** + */ + readonly etag?: string; } /** - * @interface - * A list of servers. - * @extends Array + * Represents a Query Text. */ -export interface ServerListResult extends Array { +export interface QueryText extends ProxyResource { + /** + * Query identifier unique to the server. + */ + queryId?: string; + /** + * Query text. + */ + queryText?: string; } /** - * @interface - * A list of firewall rules. - * @extends Array + * Input to get top query statistics */ -export interface FirewallRuleListResult extends Array { +export interface TopQueryStatisticsInput { + /** + * Max number of top queries to return. + */ + numberOfTopQueries: number; + /** + * Aggregation function name. + */ + aggregationFunction: string; + /** + * Observed metric name. + */ + observedMetric: string; + /** + * Observation start time. + */ + observationStartTime: Date; + /** + * Observation end time. + */ + observationEndTime: Date; + /** + * Aggregation interval type in ISO 8601 format. + */ + aggregationWindow: string; } /** - * @interface - * A list of virtual network rules. - * @extends Array + * Represents a Query Statistic. */ -export interface VirtualNetworkRuleListResult extends Array { +export interface QueryStatistic extends ProxyResource { /** - * Link to retrieve next page of results. - * **NOTE: This property will not be serialized. It can only be populated by the server.** + * Database query identifier. */ - readonly nextLink?: string; + queryId?: string; + /** + * Observation start time. + */ + startTime?: Date; + /** + * Observation end time. + */ + endTime?: Date; + /** + * Aggregation function name. + */ + aggregationFunction?: string; + /** + * The list of database names. + */ + databaseNames?: string[]; + /** + * Number of query executions in this time interval. + */ + queryExecutionCount?: number; + /** + * Metric name. + */ + metricName?: string; + /** + * Metric display name. + */ + metricDisplayName?: string; + /** + * Metric value. + */ + metricValue?: number; + /** + * Metric value unit. + */ + metricValueUnit?: string; } /** - * @interface - * A List of databases. - * @extends Array + * Input to get wait statistics */ -export interface DatabaseListResult extends Array { +export interface WaitStatisticsInput { + /** + * Observation start time. + */ + observationStartTime: Date; + /** + * Observation end time. + */ + observationEndTime: Date; + /** + * Aggregation interval type in ISO 8601 format. + */ + aggregationWindow: string; } /** - * @interface - * A list of server configurations. - * @extends Array + * Represents a Wait Statistic. */ -export interface ConfigurationListResult extends Array { +export interface WaitStatistic extends ProxyResource { + /** + * Observation start time. + */ + startTime?: Date; + /** + * Observation end time. + */ + endTime?: Date; + /** + * Wait event name. + */ + eventName?: string; + /** + * Wait event type name. + */ + eventTypeName?: string; + /** + * Database query identifier. + */ + queryId?: number; + /** + * Database Name. + */ + databaseName?: string; + /** + * Database user identifier. + */ + userId?: number; + /** + * Wait event count observed in this time interval. + */ + count?: number; + /** + * Total time of wait in milliseconds in this time interval. + */ + totalTimeInMs?: number; } /** - * @interface - * A list of log files. - * @extends Array + * Represents a recommendation action advisor. */ -export interface LogFileListResult extends Array { +export interface Advisor extends ProxyResource { + /** + * The properties of a recommendation action advisor. + */ + properties?: any; } /** - * @interface - * A list of performance tiers. - * @extends Array + * Represents a Recommendation Action. */ -export interface PerformanceTierListResult extends Array { +export interface RecommendationAction extends ProxyResource { + /** + * Advisor name. + */ + advisorName?: string; + /** + * Recommendation action session identifier. + */ + sessionId?: string; + /** + * Recommendation action identifier. + */ + actionId?: number; + /** + * Recommendation action creation time. + */ + createdTime?: Date; + /** + * Recommendation action expiration time. + */ + expirationTime?: Date; + /** + * Recommendation action reason. + */ + reason?: string; + /** + * Recommendation action type. + */ + recommendationType?: string; + /** + * Recommendation action details. + */ + details?: { [propertyName: string]: string }; } /** - * Defines values for ServerVersion. - * Possible values include: '5.6', '5.7' - * @readonly - * @enum {string} + * Recommendation action session operation status. */ -export type ServerVersion = '5.6' | '5.7'; +export interface RecommendedActionSessionsOperationStatus { + /** + * Operation identifier. + */ + name?: string; + /** + * Operation start time. + */ + startTime?: Date; + /** + * Operation status. + */ + status?: string; +} /** - * Defines values for SslEnforcementEnum. - * Possible values include: 'Enabled', 'Disabled' - * @readonly - * @enum {string} + * An interface representing PrivateLinkServiceConnectionStateProperty. */ -export type SslEnforcementEnum = 'Enabled' | 'Disabled'; +export interface PrivateLinkServiceConnectionStateProperty { + /** + * The private link service connection status. + */ + status: string; + /** + * The private link service connection description. + */ + description: string; + /** + * The actions required for private link service connection. + * **NOTE: This property will not be serialized. It can only be populated by the server.** + */ + readonly actionsRequired?: string; +} /** - * Defines values for ServerState. - * Possible values include: 'Ready', 'Dropping', 'Disabled' - * @readonly - * @enum {string} + * A private endpoint connection */ -export type ServerState = 'Ready' | 'Dropping' | 'Disabled'; +export interface PrivateEndpointConnection extends ProxyResource { + /** + * Private endpoint which the connection belongs to. + */ + privateEndpoint?: PrivateEndpointProperty; + /** + * Connection state of the private endpoint connection. + */ + privateLinkServiceConnectionState?: PrivateLinkServiceConnectionStateProperty; + /** + * State of the private endpoint connection. + * **NOTE: This property will not be serialized. It can only be populated by the server.** + */ + readonly provisioningState?: string; +} /** - * Defines values for GeoRedundantBackup. - * Possible values include: 'Enabled', 'Disabled' - * @readonly - * @enum {string} + * Tags object for patch operations. */ -export type GeoRedundantBackup = 'Enabled' | 'Disabled'; +export interface TagsObject { + /** + * Resource tags. + */ + tags?: { [propertyName: string]: string }; +} + +/** + * Properties of a private link resource. + */ +export interface PrivateLinkResourceProperties { + /** + * The private link resource group id. + * **NOTE: This property will not be serialized. It can only be populated by the server.** + */ + readonly groupId?: string; + /** + * The private link resource required member names. + * **NOTE: This property will not be serialized. It can only be populated by the server.** + */ + readonly requiredMembers?: string[]; +} + +/** + * A private link resource + */ +export interface PrivateLinkResource extends ProxyResource { + /** + * The private link resource group id. + * **NOTE: This property will not be serialized. It can only be populated by the server.** + */ + readonly properties?: PrivateLinkResourceProperties; +} + +/** + * A server security alert policy. + */ +export interface ServerSecurityAlertPolicy extends ProxyResource { + /** + * Specifies the state of the policy, whether it is enabled or disabled. Possible values include: + * 'Enabled', 'Disabled' + */ + state: ServerSecurityAlertPolicyState; + /** + * Specifies an array of alerts that are disabled. Allowed values are: Sql_Injection, + * Sql_Injection_Vulnerability, Access_Anomaly + */ + disabledAlerts?: string[]; + /** + * Specifies an array of e-mail addresses to which the alert is sent. + */ + emailAddresses?: string[]; + /** + * Specifies that the alert is sent to the account administrators. + */ + emailAccountAdmins?: boolean; + /** + * Specifies the blob storage endpoint (e.g. https://MyAccount.blob.core.windows.net). This blob + * storage will hold all Threat Detection audit logs. + */ + storageEndpoint?: string; + /** + * Specifies the identifier key of the Threat Detection audit storage account. + */ + storageAccountAccessKey?: string; + /** + * Specifies the number of days to keep in the Threat Detection audit logs. + */ + retentionDays?: number; +} + +/** + * Optional Parameters. + */ +export interface RecommendedActionsListByServerOptionalParams extends msRest.RequestOptionsBase { + /** + * The recommendation action session identifier. + */ + sessionId?: string; +} + +/** + * An interface representing MariaDBManagementClientOptions. + */ +export interface MariaDBManagementClientOptions extends AzureServiceClientOptions { + baseUri?: string; +} + +/** + * @interface + * A list of servers. + * @extends Array + */ +export interface ServerListResult extends Array { +} + +/** + * @interface + * A list of firewall rules. + * @extends Array + */ +export interface FirewallRuleListResult extends Array { +} + +/** + * @interface + * A list of virtual network rules. + * @extends Array + */ +export interface VirtualNetworkRuleListResult extends Array { + /** + * Link to retrieve next page of results. + * **NOTE: This property will not be serialized. It can only be populated by the server.** + */ + readonly nextLink?: string; +} + +/** + * @interface + * A List of databases. + * @extends Array + */ +export interface DatabaseListResult extends Array { +} + +/** + * @interface + * A list of server configurations. + * @extends Array + */ +export interface ConfigurationListResult extends Array { +} + +/** + * @interface + * A list of log files. + * @extends Array + */ +export interface LogFileListResult extends Array { +} + +/** + * @interface + * A list of performance tiers. + * @extends Array + */ +export interface PerformanceTierListResult extends Array { +} + +/** + * @interface + * A list of query texts. + * @extends Array + */ +export interface QueryTextsResultList extends Array { + /** + * Link to retrieve next page of results. + * **NOTE: This property will not be serialized. It can only be populated by the server.** + */ + readonly nextLink?: string; +} + +/** + * @interface + * A list of query statistics. + * @extends Array + */ +export interface TopQueryStatisticsResultList extends Array { + /** + * Link to retrieve next page of results. + * **NOTE: This property will not be serialized. It can only be populated by the server.** + */ + readonly nextLink?: string; +} + +/** + * @interface + * A list of wait statistics. + * @extends Array + */ +export interface WaitStatisticsResultList extends Array { + /** + * Link to retrieve next page of results. + * **NOTE: This property will not be serialized. It can only be populated by the server.** + */ + readonly nextLink?: string; +} + +/** + * @interface + * A list of query statistics. + * @extends Array + */ +export interface AdvisorsResultList extends Array { + /** + * Link to retrieve next page of results. + * **NOTE: This property will not be serialized. It can only be populated by the server.** + */ + readonly nextLink?: string; +} + +/** + * @interface + * A list of recommendation actions. + * @extends Array + */ +export interface RecommendationActionsResultList extends Array { + /** + * Link to retrieve next page of results. + * **NOTE: This property will not be serialized. It can only be populated by the server.** + */ + readonly nextLink?: string; +} + +/** + * @interface + * A list of private endpoint connections. + * @extends Array + */ +export interface PrivateEndpointConnectionListResult extends Array { + /** + * Link to retrieve next page of results. + * **NOTE: This property will not be serialized. It can only be populated by the server.** + */ + readonly nextLink?: string; +} + +/** + * @interface + * A list of private link resources + * @extends Array + */ +export interface PrivateLinkResourceListResult extends Array { + /** + * Link to retrieve next page of results. + * **NOTE: This property will not be serialized. It can only be populated by the server.** + */ + readonly nextLink?: string; +} + +/** + * Defines values for ServerVersion. + * Possible values include: '5.6', '5.7' + * @readonly + * @enum {string} + */ +export type ServerVersion = '5.6' | '5.7'; + +/** + * Defines values for SslEnforcementEnum. + * Possible values include: 'Enabled', 'Disabled' + * @readonly + * @enum {string} + */ +export type SslEnforcementEnum = 'Enabled' | 'Disabled'; + +/** + * Defines values for PublicNetworkAccessEnum. + * Possible values include: 'Enabled', 'Disabled' + * @readonly + * @enum {string} + */ +export type PublicNetworkAccessEnum = 'Enabled' | 'Disabled'; + +/** + * Defines values for PrivateLinkServiceConnectionStateStatus. + * Possible values include: 'Approved', 'Pending', 'Rejected', 'Disconnected' + * @readonly + * @enum {string} + */ +export type PrivateLinkServiceConnectionStateStatus = 'Approved' | 'Pending' | 'Rejected' | 'Disconnected'; + +/** + * Defines values for PrivateLinkServiceConnectionStateActionsRequire. + * Possible values include: 'None' + * @readonly + * @enum {string} + */ +export type PrivateLinkServiceConnectionStateActionsRequire = 'None'; + +/** + * Defines values for PrivateEndpointProvisioningState. + * Possible values include: 'Approving', 'Ready', 'Dropping', 'Failed', 'Rejecting' + * @readonly + * @enum {string} + */ +export type PrivateEndpointProvisioningState = 'Approving' | 'Ready' | 'Dropping' | 'Failed' | 'Rejecting'; + +/** + * Defines values for ServerState. + * Possible values include: 'Ready', 'Dropping', 'Disabled' + * @readonly + * @enum {string} + */ +export type ServerState = 'Ready' | 'Dropping' | 'Disabled'; + +/** + * Defines values for GeoRedundantBackup. + * Possible values include: 'Enabled', 'Disabled' + * @readonly + * @enum {string} + */ +export type GeoRedundantBackup = 'Enabled' | 'Disabled'; /** * Defines values for StorageAutogrow. @@ -1347,9 +1944,309 @@ export type CheckNameAvailabilityExecuteResponse = NameAvailability & { }; /** - * Contains response data for the get operation. + * Contains response data for the list operation. + */ +export type OperationsListResponse = OperationListResult & { + /** + * The underlying HTTP response. + */ + _response: msRest.HttpResponse & { + /** + * The response body as text (string format) + */ + bodyAsText: string; + + /** + * The response body as parsed JSON or XML + */ + parsedBody: OperationListResult; + }; +}; + +/** + * Contains response data for the get operation. + */ +export type QueryTextsGetResponse = QueryText & { + /** + * The underlying HTTP response. + */ + _response: msRest.HttpResponse & { + /** + * The response body as text (string format) + */ + bodyAsText: string; + + /** + * The response body as parsed JSON or XML + */ + parsedBody: QueryText; + }; +}; + +/** + * Contains response data for the listByServer operation. + */ +export type QueryTextsListByServerResponse = QueryTextsResultList & { + /** + * The underlying HTTP response. + */ + _response: msRest.HttpResponse & { + /** + * The response body as text (string format) + */ + bodyAsText: string; + + /** + * The response body as parsed JSON or XML + */ + parsedBody: QueryTextsResultList; + }; +}; + +/** + * Contains response data for the listByServerNext operation. + */ +export type QueryTextsListByServerNextResponse = QueryTextsResultList & { + /** + * The underlying HTTP response. + */ + _response: msRest.HttpResponse & { + /** + * The response body as text (string format) + */ + bodyAsText: string; + + /** + * The response body as parsed JSON or XML + */ + parsedBody: QueryTextsResultList; + }; +}; + +/** + * Contains response data for the get operation. + */ +export type TopQueryStatisticsGetResponse = QueryStatistic & { + /** + * The underlying HTTP response. + */ + _response: msRest.HttpResponse & { + /** + * The response body as text (string format) + */ + bodyAsText: string; + + /** + * The response body as parsed JSON or XML + */ + parsedBody: QueryStatistic; + }; +}; + +/** + * Contains response data for the listByServer operation. + */ +export type TopQueryStatisticsListByServerResponse = TopQueryStatisticsResultList & { + /** + * The underlying HTTP response. + */ + _response: msRest.HttpResponse & { + /** + * The response body as text (string format) + */ + bodyAsText: string; + + /** + * The response body as parsed JSON or XML + */ + parsedBody: TopQueryStatisticsResultList; + }; +}; + +/** + * Contains response data for the listByServerNext operation. + */ +export type TopQueryStatisticsListByServerNextResponse = TopQueryStatisticsResultList & { + /** + * The underlying HTTP response. + */ + _response: msRest.HttpResponse & { + /** + * The response body as text (string format) + */ + bodyAsText: string; + + /** + * The response body as parsed JSON or XML + */ + parsedBody: TopQueryStatisticsResultList; + }; +}; + +/** + * Contains response data for the get operation. + */ +export type WaitStatisticsGetResponse = WaitStatistic & { + /** + * The underlying HTTP response. + */ + _response: msRest.HttpResponse & { + /** + * The response body as text (string format) + */ + bodyAsText: string; + + /** + * The response body as parsed JSON or XML + */ + parsedBody: WaitStatistic; + }; +}; + +/** + * Contains response data for the listByServer operation. + */ +export type WaitStatisticsListByServerResponse = WaitStatisticsResultList & { + /** + * The underlying HTTP response. + */ + _response: msRest.HttpResponse & { + /** + * The response body as text (string format) + */ + bodyAsText: string; + + /** + * The response body as parsed JSON or XML + */ + parsedBody: WaitStatisticsResultList; + }; +}; + +/** + * Contains response data for the listByServerNext operation. + */ +export type WaitStatisticsListByServerNextResponse = WaitStatisticsResultList & { + /** + * The underlying HTTP response. + */ + _response: msRest.HttpResponse & { + /** + * The response body as text (string format) + */ + bodyAsText: string; + + /** + * The response body as parsed JSON or XML + */ + parsedBody: WaitStatisticsResultList; + }; +}; + +/** + * Contains response data for the get operation. + */ +export type AdvisorsGetResponse = Advisor & { + /** + * The underlying HTTP response. + */ + _response: msRest.HttpResponse & { + /** + * The response body as text (string format) + */ + bodyAsText: string; + + /** + * The response body as parsed JSON or XML + */ + parsedBody: Advisor; + }; +}; + +/** + * Contains response data for the listByServer operation. + */ +export type AdvisorsListByServerResponse = AdvisorsResultList & { + /** + * The underlying HTTP response. + */ + _response: msRest.HttpResponse & { + /** + * The response body as text (string format) + */ + bodyAsText: string; + + /** + * The response body as parsed JSON or XML + */ + parsedBody: AdvisorsResultList; + }; +}; + +/** + * Contains response data for the listByServerNext operation. + */ +export type AdvisorsListByServerNextResponse = AdvisorsResultList & { + /** + * The underlying HTTP response. + */ + _response: msRest.HttpResponse & { + /** + * The response body as text (string format) + */ + bodyAsText: string; + + /** + * The response body as parsed JSON or XML + */ + parsedBody: AdvisorsResultList; + }; +}; + +/** + * Contains response data for the get operation. + */ +export type RecommendedActionsGetResponse = RecommendationAction & { + /** + * The underlying HTTP response. + */ + _response: msRest.HttpResponse & { + /** + * The response body as text (string format) + */ + bodyAsText: string; + + /** + * The response body as parsed JSON or XML + */ + parsedBody: RecommendationAction; + }; +}; + +/** + * Contains response data for the listByServer operation. + */ +export type RecommendedActionsListByServerResponse = RecommendationActionsResultList & { + /** + * The underlying HTTP response. + */ + _response: msRest.HttpResponse & { + /** + * The response body as text (string format) + */ + bodyAsText: string; + + /** + * The response body as parsed JSON or XML + */ + parsedBody: RecommendationActionsResultList; + }; +}; + +/** + * Contains response data for the listByServerNext operation. */ -export type ServerSecurityAlertPoliciesGetResponse = ServerSecurityAlertPolicy & { +export type RecommendedActionsListByServerNextResponse = RecommendationActionsResultList & { /** * The underlying HTTP response. */ @@ -1362,14 +2259,94 @@ export type ServerSecurityAlertPoliciesGetResponse = ServerSecurityAlertPolicy & /** * The response body as parsed JSON or XML */ - parsedBody: ServerSecurityAlertPolicy; + parsedBody: RecommendationActionsResultList; + }; +}; + +/** + * Contains response data for the get operation. + */ +export type LocationBasedRecommendedActionSessionsOperationStatusGetResponse = RecommendedActionSessionsOperationStatus & { + /** + * The underlying HTTP response. + */ + _response: msRest.HttpResponse & { + /** + * The response body as text (string format) + */ + bodyAsText: string; + + /** + * The response body as parsed JSON or XML + */ + parsedBody: RecommendedActionSessionsOperationStatus; + }; +}; + +/** + * Contains response data for the list operation. + */ +export type LocationBasedRecommendedActionSessionsResultListResponse = RecommendationActionsResultList & { + /** + * The underlying HTTP response. + */ + _response: msRest.HttpResponse & { + /** + * The response body as text (string format) + */ + bodyAsText: string; + + /** + * The response body as parsed JSON or XML + */ + parsedBody: RecommendationActionsResultList; + }; +}; + +/** + * Contains response data for the listNext operation. + */ +export type LocationBasedRecommendedActionSessionsResultListNextResponse = RecommendationActionsResultList & { + /** + * The underlying HTTP response. + */ + _response: msRest.HttpResponse & { + /** + * The response body as text (string format) + */ + bodyAsText: string; + + /** + * The response body as parsed JSON or XML + */ + parsedBody: RecommendationActionsResultList; + }; +}; + +/** + * Contains response data for the get operation. + */ +export type PrivateEndpointConnectionsGetResponse = PrivateEndpointConnection & { + /** + * The underlying HTTP response. + */ + _response: msRest.HttpResponse & { + /** + * The response body as text (string format) + */ + bodyAsText: string; + + /** + * The response body as parsed JSON or XML + */ + parsedBody: PrivateEndpointConnection; }; }; /** * Contains response data for the createOrUpdate operation. */ -export type ServerSecurityAlertPoliciesCreateOrUpdateResponse = ServerSecurityAlertPolicy & { +export type PrivateEndpointConnectionsCreateOrUpdateResponse = PrivateEndpointConnection & { /** * The underlying HTTP response. */ @@ -1382,14 +2359,174 @@ export type ServerSecurityAlertPoliciesCreateOrUpdateResponse = ServerSecurityAl /** * The response body as parsed JSON or XML */ - parsedBody: ServerSecurityAlertPolicy; + parsedBody: PrivateEndpointConnection; + }; +}; + +/** + * Contains response data for the updateTags operation. + */ +export type PrivateEndpointConnectionsUpdateTagsResponse = PrivateEndpointConnection & { + /** + * The underlying HTTP response. + */ + _response: msRest.HttpResponse & { + /** + * The response body as text (string format) + */ + bodyAsText: string; + + /** + * The response body as parsed JSON or XML + */ + parsedBody: PrivateEndpointConnection; + }; +}; + +/** + * Contains response data for the listByServer operation. + */ +export type PrivateEndpointConnectionsListByServerResponse = PrivateEndpointConnectionListResult & { + /** + * The underlying HTTP response. + */ + _response: msRest.HttpResponse & { + /** + * The response body as text (string format) + */ + bodyAsText: string; + + /** + * The response body as parsed JSON or XML + */ + parsedBody: PrivateEndpointConnectionListResult; }; }; /** * Contains response data for the beginCreateOrUpdate operation. */ -export type ServerSecurityAlertPoliciesBeginCreateOrUpdateResponse = ServerSecurityAlertPolicy & { +export type PrivateEndpointConnectionsBeginCreateOrUpdateResponse = PrivateEndpointConnection & { + /** + * The underlying HTTP response. + */ + _response: msRest.HttpResponse & { + /** + * The response body as text (string format) + */ + bodyAsText: string; + + /** + * The response body as parsed JSON or XML + */ + parsedBody: PrivateEndpointConnection; + }; +}; + +/** + * Contains response data for the beginUpdateTags operation. + */ +export type PrivateEndpointConnectionsBeginUpdateTagsResponse = PrivateEndpointConnection & { + /** + * The underlying HTTP response. + */ + _response: msRest.HttpResponse & { + /** + * The response body as text (string format) + */ + bodyAsText: string; + + /** + * The response body as parsed JSON or XML + */ + parsedBody: PrivateEndpointConnection; + }; +}; + +/** + * Contains response data for the listByServerNext operation. + */ +export type PrivateEndpointConnectionsListByServerNextResponse = PrivateEndpointConnectionListResult & { + /** + * The underlying HTTP response. + */ + _response: msRest.HttpResponse & { + /** + * The response body as text (string format) + */ + bodyAsText: string; + + /** + * The response body as parsed JSON or XML + */ + parsedBody: PrivateEndpointConnectionListResult; + }; +}; + +/** + * Contains response data for the listByServer operation. + */ +export type PrivateLinkResourcesListByServerResponse = PrivateLinkResourceListResult & { + /** + * The underlying HTTP response. + */ + _response: msRest.HttpResponse & { + /** + * The response body as text (string format) + */ + bodyAsText: string; + + /** + * The response body as parsed JSON or XML + */ + parsedBody: PrivateLinkResourceListResult; + }; +}; + +/** + * Contains response data for the get operation. + */ +export type PrivateLinkResourcesGetResponse = PrivateLinkResource & { + /** + * The underlying HTTP response. + */ + _response: msRest.HttpResponse & { + /** + * The response body as text (string format) + */ + bodyAsText: string; + + /** + * The response body as parsed JSON or XML + */ + parsedBody: PrivateLinkResource; + }; +}; + +/** + * Contains response data for the listByServerNext operation. + */ +export type PrivateLinkResourcesListByServerNextResponse = PrivateLinkResourceListResult & { + /** + * The underlying HTTP response. + */ + _response: msRest.HttpResponse & { + /** + * The response body as text (string format) + */ + bodyAsText: string; + + /** + * The response body as parsed JSON or XML + */ + parsedBody: PrivateLinkResourceListResult; + }; +}; + +/** + * Contains response data for the get operation. + */ +export type ServerSecurityAlertPoliciesGetResponse = ServerSecurityAlertPolicy & { /** * The underlying HTTP response. */ @@ -1407,9 +2544,9 @@ export type ServerSecurityAlertPoliciesBeginCreateOrUpdateResponse = ServerSecur }; /** - * Contains response data for the list operation. + * Contains response data for the createOrUpdate operation. */ -export type OperationsListResponse = OperationListResult & { +export type ServerSecurityAlertPoliciesCreateOrUpdateResponse = ServerSecurityAlertPolicy & { /** * The underlying HTTP response. */ @@ -1422,6 +2559,26 @@ export type OperationsListResponse = OperationListResult & { /** * The response body as parsed JSON or XML */ - parsedBody: OperationListResult; + parsedBody: ServerSecurityAlertPolicy; + }; +}; + +/** + * Contains response data for the beginCreateOrUpdate operation. + */ +export type ServerSecurityAlertPoliciesBeginCreateOrUpdateResponse = ServerSecurityAlertPolicy & { + /** + * The underlying HTTP response. + */ + _response: msRest.HttpResponse & { + /** + * The response body as text (string format) + */ + bodyAsText: string; + + /** + * The response body as parsed JSON or XML + */ + parsedBody: ServerSecurityAlertPolicy; }; }; diff --git a/sdk/mariadb/arm-mariadb/src/models/locationBasedRecommendedActionSessionsOperationStatusMappers.ts b/sdk/mariadb/arm-mariadb/src/models/locationBasedRecommendedActionSessionsOperationStatusMappers.ts new file mode 100644 index 000000000000..79bc08f8d3d3 --- /dev/null +++ b/sdk/mariadb/arm-mariadb/src/models/locationBasedRecommendedActionSessionsOperationStatusMappers.ts @@ -0,0 +1,13 @@ +/* + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + * Changes may cause incorrect behavior and will be lost if the code is regenerated. + */ + +export { + discriminators, + CloudError, + RecommendedActionSessionsOperationStatus +} from "../models/mappers"; diff --git a/sdk/mariadb/arm-mariadb/src/models/locationBasedRecommendedActionSessionsResultMappers.ts b/sdk/mariadb/arm-mariadb/src/models/locationBasedRecommendedActionSessionsResultMappers.ts new file mode 100644 index 000000000000..ba1a27fdfbbe --- /dev/null +++ b/sdk/mariadb/arm-mariadb/src/models/locationBasedRecommendedActionSessionsResultMappers.ts @@ -0,0 +1,40 @@ +/* + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + * Changes may cause incorrect behavior and will be lost if the code is regenerated. + */ + +export { + discriminators, + Advisor, + AzureEntityResource, + BaseResource, + CloudError, + Configuration, + Database, + FirewallRule, + LogFile, + PrivateEndpointConnection, + PrivateEndpointProperty, + PrivateLinkResource, + PrivateLinkResourceProperties, + PrivateLinkServiceConnectionStateProperty, + ProxyResource, + QueryStatistic, + QueryText, + RecommendationAction, + RecommendationActionsResultList, + Resource, + Server, + ServerPrivateEndpointConnection, + ServerPrivateEndpointConnectionProperties, + ServerPrivateLinkServiceConnectionStateProperty, + ServerSecurityAlertPolicy, + Sku, + StorageProfile, + TrackedResource, + VirtualNetworkRule, + WaitStatistic +} from "../models/mappers"; diff --git a/sdk/mariadb/arm-mariadb/src/models/logFilesMappers.ts b/sdk/mariadb/arm-mariadb/src/models/logFilesMappers.ts index b6832542b835..4ae3c12c67bf 100644 --- a/sdk/mariadb/arm-mariadb/src/models/logFilesMappers.ts +++ b/sdk/mariadb/arm-mariadb/src/models/logFilesMappers.ts @@ -8,6 +8,8 @@ export { discriminators, + Advisor, + AzureEntityResource, BaseResource, CloudError, Configuration, @@ -15,11 +17,24 @@ export { FirewallRule, LogFile, LogFileListResult, + PrivateEndpointConnection, + PrivateEndpointProperty, + PrivateLinkResource, + PrivateLinkResourceProperties, + PrivateLinkServiceConnectionStateProperty, ProxyResource, + QueryStatistic, + QueryText, + RecommendationAction, + Resource, Server, + ServerPrivateEndpointConnection, + ServerPrivateEndpointConnectionProperties, + ServerPrivateLinkServiceConnectionStateProperty, ServerSecurityAlertPolicy, Sku, StorageProfile, TrackedResource, - VirtualNetworkRule + VirtualNetworkRule, + WaitStatistic } from "../models/mappers"; diff --git a/sdk/mariadb/arm-mariadb/src/models/mappers.ts b/sdk/mariadb/arm-mariadb/src/models/mappers.ts index ed38ecdfbf78..e623cf8c80a7 100644 --- a/sdk/mariadb/arm-mariadb/src/models/mappers.ts +++ b/sdk/mariadb/arm-mariadb/src/models/mappers.ts @@ -12,11 +12,114 @@ import * as msRest from "@azure/ms-rest-js"; export const CloudError = CloudErrorMapper; export const BaseResource = BaseResourceMapper; -export const ProxyResource: msRest.CompositeMapper = { - serializedName: "ProxyResource", +export const PrivateEndpointProperty: msRest.CompositeMapper = { + serializedName: "PrivateEndpointProperty", type: { name: "Composite", - className: "ProxyResource", + className: "PrivateEndpointProperty", + modelProperties: { + id: { + serializedName: "id", + type: { + name: "String" + } + } + } + } +}; + +export const ServerPrivateLinkServiceConnectionStateProperty: msRest.CompositeMapper = { + serializedName: "ServerPrivateLinkServiceConnectionStateProperty", + type: { + name: "Composite", + className: "ServerPrivateLinkServiceConnectionStateProperty", + modelProperties: { + status: { + required: true, + serializedName: "status", + type: { + name: "String" + } + }, + description: { + required: true, + serializedName: "description", + type: { + name: "String" + } + }, + actionsRequired: { + readOnly: true, + serializedName: "actionsRequired", + type: { + name: "String" + } + } + } + } +}; + +export const ServerPrivateEndpointConnectionProperties: msRest.CompositeMapper = { + serializedName: "ServerPrivateEndpointConnectionProperties", + type: { + name: "Composite", + className: "ServerPrivateEndpointConnectionProperties", + modelProperties: { + privateEndpoint: { + serializedName: "privateEndpoint", + type: { + name: "Composite", + className: "PrivateEndpointProperty" + } + }, + privateLinkServiceConnectionState: { + serializedName: "privateLinkServiceConnectionState", + type: { + name: "Composite", + className: "ServerPrivateLinkServiceConnectionStateProperty" + } + }, + provisioningState: { + readOnly: true, + serializedName: "provisioningState", + type: { + name: "String" + } + } + } + } +}; + +export const ServerPrivateEndpointConnection: msRest.CompositeMapper = { + serializedName: "ServerPrivateEndpointConnection", + type: { + name: "Composite", + className: "ServerPrivateEndpointConnection", + modelProperties: { + id: { + readOnly: true, + serializedName: "id", + type: { + name: "String" + } + }, + properties: { + readOnly: true, + serializedName: "properties", + type: { + name: "Composite", + className: "ServerPrivateEndpointConnectionProperties" + } + } + } + } +}; + +export const Resource: msRest.CompositeMapper = { + serializedName: "Resource", + type: { + name: "Composite", + className: "Resource", modelProperties: { id: { readOnly: true, @@ -49,14 +152,7 @@ export const TrackedResource: msRest.CompositeMapper = { name: "Composite", className: "TrackedResource", modelProperties: { - ...ProxyResource.type.modelProperties, - location: { - required: true, - serializedName: "location", - type: { - name: "String" - } - }, + ...Resource.type.modelProperties, tags: { serializedName: "tags", type: { @@ -67,6 +163,13 @@ export const TrackedResource: msRest.CompositeMapper = { } } } + }, + location: { + required: true, + serializedName: "location", + type: { + name: "String" + } } } } @@ -133,6 +236,12 @@ export const ServerPropertiesForCreate: msRest.CompositeMapper = { ] } }, + publicNetworkAccess: { + serializedName: "publicNetworkAccess", + type: { + name: "String" + } + }, storageProfile: { serializedName: "storageProfile", type: { @@ -369,6 +478,25 @@ export const Server: msRest.CompositeMapper = { type: { name: "Number" } + }, + publicNetworkAccess: { + serializedName: "properties.publicNetworkAccess", + type: { + name: "String" + } + }, + privateEndpointConnections: { + readOnly: true, + serializedName: "properties.privateEndpointConnections", + type: { + name: "Sequence", + element: { + type: { + name: "Composite", + className: "ServerPrivateEndpointConnection" + } + } + } } } } @@ -459,6 +587,12 @@ export const ServerUpdateParameters: msRest.CompositeMapper = { ] } }, + publicNetworkAccess: { + serializedName: "properties.publicNetworkAccess", + type: { + name: "String" + } + }, replicationRole: { serializedName: "properties.replicationRole", type: { @@ -480,6 +614,17 @@ export const ServerUpdateParameters: msRest.CompositeMapper = { } }; +export const ProxyResource: msRest.CompositeMapper = { + serializedName: "ProxyResource", + type: { + name: "Composite", + className: "ProxyResource", + modelProperties: { + ...Resource.type.modelProperties + } + } +}; + export const FirewallRule: msRest.CompositeMapper = { serializedName: "FirewallRule", type: { @@ -901,88 +1046,79 @@ export const NameAvailability: msRest.CompositeMapper = { } }; -export const ServerSecurityAlertPolicy: msRest.CompositeMapper = { - serializedName: "ServerSecurityAlertPolicy", +export const ErrorAdditionalInfo: msRest.CompositeMapper = { + serializedName: "ErrorAdditionalInfo", type: { name: "Composite", - className: "ServerSecurityAlertPolicy", + className: "ErrorAdditionalInfo", modelProperties: { - ...ProxyResource.type.modelProperties, - state: { - required: true, - serializedName: "properties.state", - type: { - name: "Enum", - allowedValues: [ - "Enabled", - "Disabled" - ] - } - }, - disabledAlerts: { - serializedName: "properties.disabledAlerts", + type: { + readOnly: true, + serializedName: "type", type: { - name: "Sequence", - element: { - type: { - name: "String" - } - } + name: "String" } }, - emailAddresses: { - serializedName: "properties.emailAddresses", + info: { + readOnly: true, + serializedName: "info", type: { - name: "Sequence", - element: { - type: { - name: "String" - } - } + name: "Object" } - }, - emailAccountAdmins: { - serializedName: "properties.emailAccountAdmins", + } + } + } +}; + +export const ErrorResponse: msRest.CompositeMapper = { + serializedName: "ErrorResponse", + type: { + name: "Composite", + className: "ErrorResponse", + modelProperties: { + code: { + readOnly: true, + serializedName: "code", type: { - name: "Boolean" + name: "String" } }, - storageEndpoint: { - serializedName: "properties.storageEndpoint", + message: { + readOnly: true, + serializedName: "message", type: { name: "String" } }, - storageAccountAccessKey: { - serializedName: "properties.storageAccountAccessKey", + target: { + readOnly: true, + serializedName: "target", type: { name: "String" } }, - retentionDays: { - serializedName: "properties.retentionDays", + details: { + readOnly: true, + serializedName: "details", type: { - name: "Number" + name: "Sequence", + element: { + type: { + name: "Composite", + className: "ErrorResponse" + } + } } - } - } - } -}; - -export const ServerListResult: msRest.CompositeMapper = { - serializedName: "ServerListResult", - type: { - name: "Composite", - className: "ServerListResult", - modelProperties: { - value: { - serializedName: "", + }, + additionalInfo: { + readOnly: true, + serializedName: "additionalInfo", type: { name: "Sequence", element: { type: { name: "Composite", - className: "Server" + className: "ErrorAdditionalInfo" } } } @@ -991,50 +1127,39 @@ export const ServerListResult: msRest.CompositeMapper = { } }; -export const FirewallRuleListResult: msRest.CompositeMapper = { - serializedName: "FirewallRuleListResult", +export const AzureEntityResource: msRest.CompositeMapper = { + serializedName: "AzureEntityResource", type: { name: "Composite", - className: "FirewallRuleListResult", + className: "AzureEntityResource", modelProperties: { - value: { - serializedName: "", + ...Resource.type.modelProperties, + etag: { + readOnly: true, + serializedName: "etag", type: { - name: "Sequence", - element: { - type: { - name: "Composite", - className: "FirewallRule" - } - } + name: "String" } } } } }; -export const VirtualNetworkRuleListResult: msRest.CompositeMapper = { - serializedName: "VirtualNetworkRuleListResult", +export const QueryText: msRest.CompositeMapper = { + serializedName: "QueryText", type: { name: "Composite", - className: "VirtualNetworkRuleListResult", + className: "QueryText", modelProperties: { - value: { - readOnly: true, - serializedName: "", + ...ProxyResource.type.modelProperties, + queryId: { + serializedName: "properties.queryId", type: { - name: "Sequence", - element: { - type: { - name: "Composite", - className: "VirtualNetworkRule" - } - } + name: "String" } }, - nextLink: { - readOnly: true, - serializedName: "nextLink", + queryText: { + serializedName: "properties.queryText", type: { name: "String" } @@ -1043,21 +1168,628 @@ export const VirtualNetworkRuleListResult: msRest.CompositeMapper = { } }; -export const DatabaseListResult: msRest.CompositeMapper = { - serializedName: "DatabaseListResult", +export const TopQueryStatisticsInput: msRest.CompositeMapper = { + serializedName: "TopQueryStatisticsInput", type: { name: "Composite", - className: "DatabaseListResult", + className: "TopQueryStatisticsInput", modelProperties: { - value: { - serializedName: "", + numberOfTopQueries: { + required: true, + serializedName: "properties.numberOfTopQueries", type: { - name: "Sequence", - element: { - type: { - name: "Composite", - className: "Database" - } + name: "Number" + } + }, + aggregationFunction: { + required: true, + serializedName: "properties.aggregationFunction", + type: { + name: "String" + } + }, + observedMetric: { + required: true, + serializedName: "properties.observedMetric", + type: { + name: "String" + } + }, + observationStartTime: { + required: true, + serializedName: "properties.observationStartTime", + type: { + name: "DateTime" + } + }, + observationEndTime: { + required: true, + serializedName: "properties.observationEndTime", + type: { + name: "DateTime" + } + }, + aggregationWindow: { + required: true, + serializedName: "properties.aggregationWindow", + type: { + name: "String" + } + } + } + } +}; + +export const QueryStatistic: msRest.CompositeMapper = { + serializedName: "QueryStatistic", + type: { + name: "Composite", + className: "QueryStatistic", + modelProperties: { + ...ProxyResource.type.modelProperties, + queryId: { + serializedName: "properties.queryId", + type: { + name: "String" + } + }, + startTime: { + serializedName: "properties.startTime", + type: { + name: "DateTime" + } + }, + endTime: { + serializedName: "properties.endTime", + type: { + name: "DateTime" + } + }, + aggregationFunction: { + serializedName: "properties.aggregationFunction", + type: { + name: "String" + } + }, + databaseNames: { + serializedName: "properties.databaseNames", + type: { + name: "Sequence", + element: { + type: { + name: "String" + } + } + } + }, + queryExecutionCount: { + serializedName: "properties.queryExecutionCount", + type: { + name: "Number" + } + }, + metricName: { + serializedName: "properties.metricName", + type: { + name: "String" + } + }, + metricDisplayName: { + serializedName: "properties.metricDisplayName", + type: { + name: "String" + } + }, + metricValue: { + serializedName: "properties.metricValue", + type: { + name: "Number" + } + }, + metricValueUnit: { + serializedName: "properties.metricValueUnit", + type: { + name: "String" + } + } + } + } +}; + +export const WaitStatisticsInput: msRest.CompositeMapper = { + serializedName: "WaitStatisticsInput", + type: { + name: "Composite", + className: "WaitStatisticsInput", + modelProperties: { + observationStartTime: { + required: true, + serializedName: "properties.observationStartTime", + type: { + name: "DateTime" + } + }, + observationEndTime: { + required: true, + serializedName: "properties.observationEndTime", + type: { + name: "DateTime" + } + }, + aggregationWindow: { + required: true, + serializedName: "properties.aggregationWindow", + type: { + name: "String" + } + } + } + } +}; + +export const WaitStatistic: msRest.CompositeMapper = { + serializedName: "WaitStatistic", + type: { + name: "Composite", + className: "WaitStatistic", + modelProperties: { + ...ProxyResource.type.modelProperties, + startTime: { + serializedName: "properties.startTime", + type: { + name: "DateTime" + } + }, + endTime: { + serializedName: "properties.endTime", + type: { + name: "DateTime" + } + }, + eventName: { + serializedName: "properties.eventName", + type: { + name: "String" + } + }, + eventTypeName: { + serializedName: "properties.eventTypeName", + type: { + name: "String" + } + }, + queryId: { + serializedName: "properties.queryId", + type: { + name: "Number" + } + }, + databaseName: { + serializedName: "properties.databaseName", + type: { + name: "String" + } + }, + userId: { + serializedName: "properties.userId", + type: { + name: "Number" + } + }, + count: { + serializedName: "properties.count", + type: { + name: "Number" + } + }, + totalTimeInMs: { + serializedName: "properties.totalTimeInMs", + type: { + name: "Number" + } + } + } + } +}; + +export const Advisor: msRest.CompositeMapper = { + serializedName: "Advisor", + type: { + name: "Composite", + className: "Advisor", + modelProperties: { + ...ProxyResource.type.modelProperties, + properties: { + serializedName: "properties", + type: { + name: "Object" + } + } + } + } +}; + +export const RecommendationAction: msRest.CompositeMapper = { + serializedName: "RecommendationAction", + type: { + name: "Composite", + className: "RecommendationAction", + modelProperties: { + ...ProxyResource.type.modelProperties, + advisorName: { + serializedName: "properties.advisorName", + type: { + name: "String" + } + }, + sessionId: { + serializedName: "properties.sessionId", + type: { + name: "String" + } + }, + actionId: { + serializedName: "properties.actionId", + type: { + name: "Number" + } + }, + createdTime: { + serializedName: "properties.createdTime", + type: { + name: "DateTime" + } + }, + expirationTime: { + serializedName: "properties.expirationTime", + type: { + name: "DateTime" + } + }, + reason: { + serializedName: "properties.reason", + type: { + name: "String" + } + }, + recommendationType: { + serializedName: "properties.recommendationType", + type: { + name: "String" + } + }, + details: { + serializedName: "properties.details", + type: { + name: "Dictionary", + value: { + type: { + name: "String" + } + } + } + } + } + } +}; + +export const RecommendedActionSessionsOperationStatus: msRest.CompositeMapper = { + serializedName: "RecommendedActionSessionsOperationStatus", + type: { + name: "Composite", + className: "RecommendedActionSessionsOperationStatus", + modelProperties: { + name: { + serializedName: "name", + type: { + name: "String" + } + }, + startTime: { + serializedName: "startTime", + type: { + name: "DateTime" + } + }, + status: { + serializedName: "status", + type: { + name: "String" + } + } + } + } +}; + +export const PrivateLinkServiceConnectionStateProperty: msRest.CompositeMapper = { + serializedName: "PrivateLinkServiceConnectionStateProperty", + type: { + name: "Composite", + className: "PrivateLinkServiceConnectionStateProperty", + modelProperties: { + status: { + required: true, + serializedName: "status", + type: { + name: "String" + } + }, + description: { + required: true, + serializedName: "description", + type: { + name: "String" + } + }, + actionsRequired: { + readOnly: true, + serializedName: "actionsRequired", + type: { + name: "String" + } + } + } + } +}; + +export const PrivateEndpointConnection: msRest.CompositeMapper = { + serializedName: "PrivateEndpointConnection", + type: { + name: "Composite", + className: "PrivateEndpointConnection", + modelProperties: { + ...ProxyResource.type.modelProperties, + privateEndpoint: { + serializedName: "properties.privateEndpoint", + type: { + name: "Composite", + className: "PrivateEndpointProperty" + } + }, + privateLinkServiceConnectionState: { + serializedName: "properties.privateLinkServiceConnectionState", + type: { + name: "Composite", + className: "PrivateLinkServiceConnectionStateProperty" + } + }, + provisioningState: { + readOnly: true, + serializedName: "properties.provisioningState", + type: { + name: "String" + } + } + } + } +}; + +export const TagsObject: msRest.CompositeMapper = { + serializedName: "TagsObject", + type: { + name: "Composite", + className: "TagsObject", + modelProperties: { + tags: { + serializedName: "tags", + type: { + name: "Dictionary", + value: { + type: { + name: "String" + } + } + } + } + } + } +}; + +export const PrivateLinkResourceProperties: msRest.CompositeMapper = { + serializedName: "PrivateLinkResourceProperties", + type: { + name: "Composite", + className: "PrivateLinkResourceProperties", + modelProperties: { + groupId: { + readOnly: true, + serializedName: "groupId", + type: { + name: "String" + } + }, + requiredMembers: { + readOnly: true, + serializedName: "requiredMembers", + type: { + name: "Sequence", + element: { + type: { + name: "String" + } + } + } + } + } + } +}; + +export const PrivateLinkResource: msRest.CompositeMapper = { + serializedName: "PrivateLinkResource", + type: { + name: "Composite", + className: "PrivateLinkResource", + modelProperties: { + ...ProxyResource.type.modelProperties, + properties: { + readOnly: true, + serializedName: "properties", + type: { + name: "Composite", + className: "PrivateLinkResourceProperties" + } + } + } + } +}; + +export const ServerSecurityAlertPolicy: msRest.CompositeMapper = { + serializedName: "ServerSecurityAlertPolicy", + type: { + name: "Composite", + className: "ServerSecurityAlertPolicy", + modelProperties: { + ...ProxyResource.type.modelProperties, + state: { + required: true, + serializedName: "properties.state", + type: { + name: "Enum", + allowedValues: [ + "Enabled", + "Disabled" + ] + } + }, + disabledAlerts: { + serializedName: "properties.disabledAlerts", + type: { + name: "Sequence", + element: { + type: { + name: "String" + } + } + } + }, + emailAddresses: { + serializedName: "properties.emailAddresses", + type: { + name: "Sequence", + element: { + type: { + name: "String" + } + } + } + }, + emailAccountAdmins: { + serializedName: "properties.emailAccountAdmins", + type: { + name: "Boolean" + } + }, + storageEndpoint: { + serializedName: "properties.storageEndpoint", + type: { + name: "String" + } + }, + storageAccountAccessKey: { + serializedName: "properties.storageAccountAccessKey", + type: { + name: "String" + } + }, + retentionDays: { + serializedName: "properties.retentionDays", + type: { + name: "Number" + } + } + } + } +}; + +export const ServerListResult: msRest.CompositeMapper = { + serializedName: "ServerListResult", + type: { + name: "Composite", + className: "ServerListResult", + modelProperties: { + value: { + serializedName: "", + type: { + name: "Sequence", + element: { + type: { + name: "Composite", + className: "Server" + } + } + } + } + } + } +}; + +export const FirewallRuleListResult: msRest.CompositeMapper = { + serializedName: "FirewallRuleListResult", + type: { + name: "Composite", + className: "FirewallRuleListResult", + modelProperties: { + value: { + serializedName: "", + type: { + name: "Sequence", + element: { + type: { + name: "Composite", + className: "FirewallRule" + } + } + } + } + } + } +}; + +export const VirtualNetworkRuleListResult: msRest.CompositeMapper = { + serializedName: "VirtualNetworkRuleListResult", + type: { + name: "Composite", + className: "VirtualNetworkRuleListResult", + modelProperties: { + value: { + readOnly: true, + serializedName: "", + type: { + name: "Sequence", + element: { + type: { + name: "Composite", + className: "VirtualNetworkRule" + } + } + } + }, + nextLink: { + readOnly: true, + serializedName: "nextLink", + type: { + name: "String" + } + } + } + } +}; + +export const DatabaseListResult: msRest.CompositeMapper = { + serializedName: "DatabaseListResult", + type: { + name: "Composite", + className: "DatabaseListResult", + modelProperties: { + value: { + serializedName: "", + type: { + name: "Sequence", + element: { + type: { + name: "Composite", + className: "Database" + } } } } @@ -1131,6 +1863,216 @@ export const PerformanceTierListResult: msRest.CompositeMapper = { } }; +export const QueryTextsResultList: msRest.CompositeMapper = { + serializedName: "QueryTextsResultList", + type: { + name: "Composite", + className: "QueryTextsResultList", + modelProperties: { + value: { + readOnly: true, + serializedName: "", + type: { + name: "Sequence", + element: { + type: { + name: "Composite", + className: "QueryText" + } + } + } + }, + nextLink: { + readOnly: true, + serializedName: "nextLink", + type: { + name: "String" + } + } + } + } +}; + +export const TopQueryStatisticsResultList: msRest.CompositeMapper = { + serializedName: "TopQueryStatisticsResultList", + type: { + name: "Composite", + className: "TopQueryStatisticsResultList", + modelProperties: { + value: { + readOnly: true, + serializedName: "", + type: { + name: "Sequence", + element: { + type: { + name: "Composite", + className: "QueryStatistic" + } + } + } + }, + nextLink: { + readOnly: true, + serializedName: "nextLink", + type: { + name: "String" + } + } + } + } +}; + +export const WaitStatisticsResultList: msRest.CompositeMapper = { + serializedName: "WaitStatisticsResultList", + type: { + name: "Composite", + className: "WaitStatisticsResultList", + modelProperties: { + value: { + readOnly: true, + serializedName: "", + type: { + name: "Sequence", + element: { + type: { + name: "Composite", + className: "WaitStatistic" + } + } + } + }, + nextLink: { + readOnly: true, + serializedName: "nextLink", + type: { + name: "String" + } + } + } + } +}; + +export const AdvisorsResultList: msRest.CompositeMapper = { + serializedName: "AdvisorsResultList", + type: { + name: "Composite", + className: "AdvisorsResultList", + modelProperties: { + value: { + readOnly: true, + serializedName: "", + type: { + name: "Sequence", + element: { + type: { + name: "Composite", + className: "Advisor" + } + } + } + }, + nextLink: { + readOnly: true, + serializedName: "nextLink", + type: { + name: "String" + } + } + } + } +}; + +export const RecommendationActionsResultList: msRest.CompositeMapper = { + serializedName: "RecommendationActionsResultList", + type: { + name: "Composite", + className: "RecommendationActionsResultList", + modelProperties: { + value: { + readOnly: true, + serializedName: "", + type: { + name: "Sequence", + element: { + type: { + name: "Composite", + className: "RecommendationAction" + } + } + } + }, + nextLink: { + readOnly: true, + serializedName: "nextLink", + type: { + name: "String" + } + } + } + } +}; + +export const PrivateEndpointConnectionListResult: msRest.CompositeMapper = { + serializedName: "PrivateEndpointConnectionListResult", + type: { + name: "Composite", + className: "PrivateEndpointConnectionListResult", + modelProperties: { + value: { + readOnly: true, + serializedName: "", + type: { + name: "Sequence", + element: { + type: { + name: "Composite", + className: "PrivateEndpointConnection" + } + } + } + }, + nextLink: { + readOnly: true, + serializedName: "nextLink", + type: { + name: "String" + } + } + } + } +}; + +export const PrivateLinkResourceListResult: msRest.CompositeMapper = { + serializedName: "PrivateLinkResourceListResult", + type: { + name: "Composite", + className: "PrivateLinkResourceListResult", + modelProperties: { + value: { + readOnly: true, + serializedName: "", + type: { + name: "Sequence", + element: { + type: { + name: "Composite", + className: "PrivateLinkResource" + } + } + } + }, + nextLink: { + readOnly: true, + serializedName: "nextLink", + type: { + name: "String" + } + } + } + } +}; + export const discriminators = { 'ServerPropertiesForCreate' : ServerPropertiesForCreate, 'ServerPropertiesForCreate.Default' : ServerPropertiesForDefaultCreate, diff --git a/sdk/mariadb/arm-mariadb/src/models/parameters.ts b/sdk/mariadb/arm-mariadb/src/models/parameters.ts index 7dbc0227f6c5..ba66ff1cce3a 100644 --- a/sdk/mariadb/arm-mariadb/src/models/parameters.ts +++ b/sdk/mariadb/arm-mariadb/src/models/parameters.ts @@ -20,11 +20,24 @@ export const acceptLanguage: msRest.OperationParameter = { } } }; +export const advisorName: msRest.OperationURLParameter = { + parameterPath: "advisorName", + mapper: { + required: true, + serializedName: "advisorName", + type: { + name: "String" + } + } +}; export const apiVersion: msRest.OperationQueryParameter = { parameterPath: "apiVersion", mapper: { required: true, serializedName: "api-version", + constraints: { + MinLength: 1 + }, type: { name: "String" } @@ -60,6 +73,16 @@ export const firewallRuleName: msRest.OperationURLParameter = { } } }; +export const groupName: msRest.OperationURLParameter = { + parameterPath: "groupName", + mapper: { + required: true, + serializedName: "groupName", + type: { + name: "String" + } + } +}; export const locationName: msRest.OperationURLParameter = { parameterPath: "locationName", mapper: { @@ -81,11 +104,82 @@ export const nextPageLink: msRest.OperationURLParameter = { }, skipEncoding: true }; +export const operationId: msRest.OperationURLParameter = { + parameterPath: "operationId", + mapper: { + required: true, + serializedName: "operationId", + type: { + name: "String" + } + } +}; +export const privateEndpointConnectionName: msRest.OperationURLParameter = { + parameterPath: "privateEndpointConnectionName", + mapper: { + required: true, + serializedName: "privateEndpointConnectionName", + type: { + name: "String" + } + } +}; +export const queryId: msRest.OperationURLParameter = { + parameterPath: "queryId", + mapper: { + required: true, + serializedName: "queryId", + type: { + name: "String" + } + } +}; +export const queryIds: msRest.OperationQueryParameter = { + parameterPath: "queryIds", + mapper: { + required: true, + serializedName: "queryIds", + type: { + name: "Sequence", + element: { + type: { + name: "String" + } + } + } + }, + collectionFormat: msRest.QueryCollectionFormat.Multi +}; +export const queryStatisticId: msRest.OperationURLParameter = { + parameterPath: "queryStatisticId", + mapper: { + required: true, + serializedName: "queryStatisticId", + type: { + name: "String" + } + } +}; +export const recommendedActionName: msRest.OperationURLParameter = { + parameterPath: "recommendedActionName", + mapper: { + required: true, + serializedName: "recommendedActionName", + type: { + name: "String" + } + } +}; export const resourceGroupName: msRest.OperationURLParameter = { parameterPath: "resourceGroupName", mapper: { required: true, serializedName: "resourceGroupName", + constraints: { + MaxLength: 90, + MinLength: 1, + Pattern: /^[-\w\._\(\)]+$/ + }, type: { name: "String" } @@ -113,11 +207,26 @@ export const serverName: msRest.OperationURLParameter = { } } }; +export const sessionId: msRest.OperationQueryParameter = { + parameterPath: [ + "options", + "sessionId" + ], + mapper: { + serializedName: "sessionId", + type: { + name: "String" + } + } +}; export const subscriptionId: msRest.OperationURLParameter = { parameterPath: "subscriptionId", mapper: { required: true, serializedName: "subscriptionId", + constraints: { + MinLength: 1 + }, type: { name: "String" } @@ -133,3 +242,13 @@ export const virtualNetworkRuleName: msRest.OperationURLParameter = { } } }; +export const waitStatisticsId: msRest.OperationURLParameter = { + parameterPath: "waitStatisticsId", + mapper: { + required: true, + serializedName: "waitStatisticsId", + type: { + name: "String" + } + } +}; diff --git a/sdk/mariadb/arm-mariadb/src/models/privateEndpointConnectionsMappers.ts b/sdk/mariadb/arm-mariadb/src/models/privateEndpointConnectionsMappers.ts new file mode 100644 index 000000000000..9363ddf44aa6 --- /dev/null +++ b/sdk/mariadb/arm-mariadb/src/models/privateEndpointConnectionsMappers.ts @@ -0,0 +1,43 @@ +/* + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + * Changes may cause incorrect behavior and will be lost if the code is regenerated. + */ + +export { + discriminators, + Advisor, + AzureEntityResource, + BaseResource, + CloudError, + Configuration, + Database, + ErrorAdditionalInfo, + ErrorResponse, + FirewallRule, + LogFile, + PrivateEndpointConnection, + PrivateEndpointConnectionListResult, + PrivateEndpointProperty, + PrivateLinkResource, + PrivateLinkResourceProperties, + PrivateLinkServiceConnectionStateProperty, + ProxyResource, + QueryStatistic, + QueryText, + RecommendationAction, + Resource, + Server, + ServerPrivateEndpointConnection, + ServerPrivateEndpointConnectionProperties, + ServerPrivateLinkServiceConnectionStateProperty, + ServerSecurityAlertPolicy, + Sku, + StorageProfile, + TagsObject, + TrackedResource, + VirtualNetworkRule, + WaitStatistic +} from "../models/mappers"; diff --git a/sdk/mariadb/arm-mariadb/src/models/privateLinkResourcesMappers.ts b/sdk/mariadb/arm-mariadb/src/models/privateLinkResourcesMappers.ts new file mode 100644 index 000000000000..10f9652bacd3 --- /dev/null +++ b/sdk/mariadb/arm-mariadb/src/models/privateLinkResourcesMappers.ts @@ -0,0 +1,42 @@ +/* + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + * Changes may cause incorrect behavior and will be lost if the code is regenerated. + */ + +export { + discriminators, + Advisor, + AzureEntityResource, + BaseResource, + CloudError, + Configuration, + Database, + ErrorAdditionalInfo, + ErrorResponse, + FirewallRule, + LogFile, + PrivateEndpointConnection, + PrivateEndpointProperty, + PrivateLinkResource, + PrivateLinkResourceListResult, + PrivateLinkResourceProperties, + PrivateLinkServiceConnectionStateProperty, + ProxyResource, + QueryStatistic, + QueryText, + RecommendationAction, + Resource, + Server, + ServerPrivateEndpointConnection, + ServerPrivateEndpointConnectionProperties, + ServerPrivateLinkServiceConnectionStateProperty, + ServerSecurityAlertPolicy, + Sku, + StorageProfile, + TrackedResource, + VirtualNetworkRule, + WaitStatistic +} from "../models/mappers"; diff --git a/sdk/mariadb/arm-mariadb/src/models/queryTextsMappers.ts b/sdk/mariadb/arm-mariadb/src/models/queryTextsMappers.ts new file mode 100644 index 000000000000..b76f04dadb18 --- /dev/null +++ b/sdk/mariadb/arm-mariadb/src/models/queryTextsMappers.ts @@ -0,0 +1,40 @@ +/* + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + * Changes may cause incorrect behavior and will be lost if the code is regenerated. + */ + +export { + discriminators, + Advisor, + AzureEntityResource, + BaseResource, + CloudError, + Configuration, + Database, + FirewallRule, + LogFile, + PrivateEndpointConnection, + PrivateEndpointProperty, + PrivateLinkResource, + PrivateLinkResourceProperties, + PrivateLinkServiceConnectionStateProperty, + ProxyResource, + QueryStatistic, + QueryText, + QueryTextsResultList, + RecommendationAction, + Resource, + Server, + ServerPrivateEndpointConnection, + ServerPrivateEndpointConnectionProperties, + ServerPrivateLinkServiceConnectionStateProperty, + ServerSecurityAlertPolicy, + Sku, + StorageProfile, + TrackedResource, + VirtualNetworkRule, + WaitStatistic +} from "../models/mappers"; diff --git a/sdk/mariadb/arm-mariadb/src/models/recommendedActionsMappers.ts b/sdk/mariadb/arm-mariadb/src/models/recommendedActionsMappers.ts new file mode 100644 index 000000000000..ba1a27fdfbbe --- /dev/null +++ b/sdk/mariadb/arm-mariadb/src/models/recommendedActionsMappers.ts @@ -0,0 +1,40 @@ +/* + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + * Changes may cause incorrect behavior and will be lost if the code is regenerated. + */ + +export { + discriminators, + Advisor, + AzureEntityResource, + BaseResource, + CloudError, + Configuration, + Database, + FirewallRule, + LogFile, + PrivateEndpointConnection, + PrivateEndpointProperty, + PrivateLinkResource, + PrivateLinkResourceProperties, + PrivateLinkServiceConnectionStateProperty, + ProxyResource, + QueryStatistic, + QueryText, + RecommendationAction, + RecommendationActionsResultList, + Resource, + Server, + ServerPrivateEndpointConnection, + ServerPrivateEndpointConnectionProperties, + ServerPrivateLinkServiceConnectionStateProperty, + ServerSecurityAlertPolicy, + Sku, + StorageProfile, + TrackedResource, + VirtualNetworkRule, + WaitStatistic +} from "../models/mappers"; diff --git a/sdk/mariadb/arm-mariadb/src/models/replicasMappers.ts b/sdk/mariadb/arm-mariadb/src/models/replicasMappers.ts index b86a44e417cd..15a6e005a354 100644 --- a/sdk/mariadb/arm-mariadb/src/models/replicasMappers.ts +++ b/sdk/mariadb/arm-mariadb/src/models/replicasMappers.ts @@ -8,18 +8,33 @@ export { discriminators, + Advisor, + AzureEntityResource, BaseResource, CloudError, Configuration, Database, FirewallRule, LogFile, + PrivateEndpointConnection, + PrivateEndpointProperty, + PrivateLinkResource, + PrivateLinkResourceProperties, + PrivateLinkServiceConnectionStateProperty, ProxyResource, + QueryStatistic, + QueryText, + RecommendationAction, + Resource, Server, ServerListResult, + ServerPrivateEndpointConnection, + ServerPrivateEndpointConnectionProperties, + ServerPrivateLinkServiceConnectionStateProperty, ServerSecurityAlertPolicy, Sku, StorageProfile, TrackedResource, - VirtualNetworkRule + VirtualNetworkRule, + WaitStatistic } from "../models/mappers"; diff --git a/sdk/mariadb/arm-mariadb/src/models/serverSecurityAlertPoliciesMappers.ts b/sdk/mariadb/arm-mariadb/src/models/serverSecurityAlertPoliciesMappers.ts index 9555ebb4e3ca..38bb4e801a32 100644 --- a/sdk/mariadb/arm-mariadb/src/models/serverSecurityAlertPoliciesMappers.ts +++ b/sdk/mariadb/arm-mariadb/src/models/serverSecurityAlertPoliciesMappers.ts @@ -8,17 +8,32 @@ export { discriminators, + Advisor, + AzureEntityResource, BaseResource, CloudError, Configuration, Database, FirewallRule, LogFile, + PrivateEndpointConnection, + PrivateEndpointProperty, + PrivateLinkResource, + PrivateLinkResourceProperties, + PrivateLinkServiceConnectionStateProperty, ProxyResource, + QueryStatistic, + QueryText, + RecommendationAction, + Resource, Server, + ServerPrivateEndpointConnection, + ServerPrivateEndpointConnectionProperties, + ServerPrivateLinkServiceConnectionStateProperty, ServerSecurityAlertPolicy, Sku, StorageProfile, TrackedResource, - VirtualNetworkRule + VirtualNetworkRule, + WaitStatistic } from "../models/mappers"; diff --git a/sdk/mariadb/arm-mariadb/src/models/serversMappers.ts b/sdk/mariadb/arm-mariadb/src/models/serversMappers.ts index 4495c8e37cdd..a3badfc85f00 100644 --- a/sdk/mariadb/arm-mariadb/src/models/serversMappers.ts +++ b/sdk/mariadb/arm-mariadb/src/models/serversMappers.ts @@ -8,16 +8,30 @@ export { discriminators, + Advisor, + AzureEntityResource, BaseResource, CloudError, Configuration, Database, FirewallRule, LogFile, + PrivateEndpointConnection, + PrivateEndpointProperty, + PrivateLinkResource, + PrivateLinkResourceProperties, + PrivateLinkServiceConnectionStateProperty, ProxyResource, + QueryStatistic, + QueryText, + RecommendationAction, + Resource, Server, ServerForCreate, ServerListResult, + ServerPrivateEndpointConnection, + ServerPrivateEndpointConnectionProperties, + ServerPrivateLinkServiceConnectionStateProperty, ServerPropertiesForCreate, ServerPropertiesForDefaultCreate, ServerPropertiesForGeoRestore, @@ -28,5 +42,6 @@ export { Sku, StorageProfile, TrackedResource, - VirtualNetworkRule + VirtualNetworkRule, + WaitStatistic } from "../models/mappers"; diff --git a/sdk/mariadb/arm-mariadb/src/models/topQueryStatisticsMappers.ts b/sdk/mariadb/arm-mariadb/src/models/topQueryStatisticsMappers.ts new file mode 100644 index 000000000000..d64ea301e572 --- /dev/null +++ b/sdk/mariadb/arm-mariadb/src/models/topQueryStatisticsMappers.ts @@ -0,0 +1,41 @@ +/* + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + * Changes may cause incorrect behavior and will be lost if the code is regenerated. + */ + +export { + discriminators, + Advisor, + AzureEntityResource, + BaseResource, + CloudError, + Configuration, + Database, + FirewallRule, + LogFile, + PrivateEndpointConnection, + PrivateEndpointProperty, + PrivateLinkResource, + PrivateLinkResourceProperties, + PrivateLinkServiceConnectionStateProperty, + ProxyResource, + QueryStatistic, + QueryText, + RecommendationAction, + Resource, + Server, + ServerPrivateEndpointConnection, + ServerPrivateEndpointConnectionProperties, + ServerPrivateLinkServiceConnectionStateProperty, + ServerSecurityAlertPolicy, + Sku, + StorageProfile, + TopQueryStatisticsInput, + TopQueryStatisticsResultList, + TrackedResource, + VirtualNetworkRule, + WaitStatistic +} from "../models/mappers"; diff --git a/sdk/mariadb/arm-mariadb/src/models/virtualNetworkRulesMappers.ts b/sdk/mariadb/arm-mariadb/src/models/virtualNetworkRulesMappers.ts index 08d2a62e7e38..6c9522cd555c 100644 --- a/sdk/mariadb/arm-mariadb/src/models/virtualNetworkRulesMappers.ts +++ b/sdk/mariadb/arm-mariadb/src/models/virtualNetworkRulesMappers.ts @@ -8,18 +8,33 @@ export { discriminators, + Advisor, + AzureEntityResource, BaseResource, CloudError, Configuration, Database, FirewallRule, LogFile, + PrivateEndpointConnection, + PrivateEndpointProperty, + PrivateLinkResource, + PrivateLinkResourceProperties, + PrivateLinkServiceConnectionStateProperty, ProxyResource, + QueryStatistic, + QueryText, + RecommendationAction, + Resource, Server, + ServerPrivateEndpointConnection, + ServerPrivateEndpointConnectionProperties, + ServerPrivateLinkServiceConnectionStateProperty, ServerSecurityAlertPolicy, Sku, StorageProfile, TrackedResource, VirtualNetworkRule, - VirtualNetworkRuleListResult + VirtualNetworkRuleListResult, + WaitStatistic } from "../models/mappers"; diff --git a/sdk/mariadb/arm-mariadb/src/models/waitStatisticsMappers.ts b/sdk/mariadb/arm-mariadb/src/models/waitStatisticsMappers.ts new file mode 100644 index 000000000000..7742f585b727 --- /dev/null +++ b/sdk/mariadb/arm-mariadb/src/models/waitStatisticsMappers.ts @@ -0,0 +1,41 @@ +/* + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + * Changes may cause incorrect behavior and will be lost if the code is regenerated. + */ + +export { + discriminators, + Advisor, + AzureEntityResource, + BaseResource, + CloudError, + Configuration, + Database, + FirewallRule, + LogFile, + PrivateEndpointConnection, + PrivateEndpointProperty, + PrivateLinkResource, + PrivateLinkResourceProperties, + PrivateLinkServiceConnectionStateProperty, + ProxyResource, + QueryStatistic, + QueryText, + RecommendationAction, + Resource, + Server, + ServerPrivateEndpointConnection, + ServerPrivateEndpointConnectionProperties, + ServerPrivateLinkServiceConnectionStateProperty, + ServerSecurityAlertPolicy, + Sku, + StorageProfile, + TrackedResource, + VirtualNetworkRule, + WaitStatistic, + WaitStatisticsInput, + WaitStatisticsResultList +} from "../models/mappers"; diff --git a/sdk/mariadb/arm-mariadb/src/operations/advisors.ts b/sdk/mariadb/arm-mariadb/src/operations/advisors.ts new file mode 100644 index 000000000000..9d22e3ca0b1f --- /dev/null +++ b/sdk/mariadb/arm-mariadb/src/operations/advisors.ts @@ -0,0 +1,198 @@ +/* + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + * Changes may cause incorrect behavior and will be lost if the code is + * regenerated. + */ + +import * as msRest from "@azure/ms-rest-js"; +import * as Models from "../models"; +import * as Mappers from "../models/advisorsMappers"; +import * as Parameters from "../models/parameters"; +import { MariaDBManagementClientContext } from "../mariaDBManagementClientContext"; + +/** Class representing a Advisors. */ +export class Advisors { + private readonly client: MariaDBManagementClientContext; + + /** + * Create a Advisors. + * @param {MariaDBManagementClientContext} client Reference to the service client. + */ + constructor(client: MariaDBManagementClientContext) { + this.client = client; + } + + /** + * Get a recommendation action advisor. + * @param resourceGroupName The name of the resource group. The name is case insensitive. + * @param serverName The name of the server. + * @param advisorName The advisor name for recommendation action. + * @param [options] The optional parameters + * @returns Promise + */ + get(resourceGroupName: string, serverName: string, advisorName: string, options?: msRest.RequestOptionsBase): Promise; + /** + * @param resourceGroupName The name of the resource group. The name is case insensitive. + * @param serverName The name of the server. + * @param advisorName The advisor name for recommendation action. + * @param callback The callback + */ + get(resourceGroupName: string, serverName: string, advisorName: string, callback: msRest.ServiceCallback): void; + /** + * @param resourceGroupName The name of the resource group. The name is case insensitive. + * @param serverName The name of the server. + * @param advisorName The advisor name for recommendation action. + * @param options The optional parameters + * @param callback The callback + */ + get(resourceGroupName: string, serverName: string, advisorName: string, options: msRest.RequestOptionsBase, callback: msRest.ServiceCallback): void; + get(resourceGroupName: string, serverName: string, advisorName: string, options?: msRest.RequestOptionsBase | msRest.ServiceCallback, callback?: msRest.ServiceCallback): Promise { + return this.client.sendOperationRequest( + { + resourceGroupName, + serverName, + advisorName, + options + }, + getOperationSpec, + callback) as Promise; + } + + /** + * List recommendation action advisors. + * @param resourceGroupName The name of the resource group. The name is case insensitive. + * @param serverName The name of the server. + * @param [options] The optional parameters + * @returns Promise + */ + listByServer(resourceGroupName: string, serverName: string, options?: msRest.RequestOptionsBase): Promise; + /** + * @param resourceGroupName The name of the resource group. The name is case insensitive. + * @param serverName The name of the server. + * @param callback The callback + */ + listByServer(resourceGroupName: string, serverName: string, callback: msRest.ServiceCallback): void; + /** + * @param resourceGroupName The name of the resource group. The name is case insensitive. + * @param serverName The name of the server. + * @param options The optional parameters + * @param callback The callback + */ + listByServer(resourceGroupName: string, serverName: string, options: msRest.RequestOptionsBase, callback: msRest.ServiceCallback): void; + listByServer(resourceGroupName: string, serverName: string, options?: msRest.RequestOptionsBase | msRest.ServiceCallback, callback?: msRest.ServiceCallback): Promise { + return this.client.sendOperationRequest( + { + resourceGroupName, + serverName, + options + }, + listByServerOperationSpec, + callback) as Promise; + } + + /** + * List recommendation action advisors. + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @param [options] The optional parameters + * @returns Promise + */ + listByServerNext(nextPageLink: string, options?: msRest.RequestOptionsBase): Promise; + /** + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @param callback The callback + */ + listByServerNext(nextPageLink: string, callback: msRest.ServiceCallback): void; + /** + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @param options The optional parameters + * @param callback The callback + */ + listByServerNext(nextPageLink: string, options: msRest.RequestOptionsBase, callback: msRest.ServiceCallback): void; + listByServerNext(nextPageLink: string, options?: msRest.RequestOptionsBase | msRest.ServiceCallback, callback?: msRest.ServiceCallback): Promise { + return this.client.sendOperationRequest( + { + nextPageLink, + options + }, + listByServerNextOperationSpec, + callback) as Promise; + } +} + +// Operation Specifications +const serializer = new msRest.Serializer(Mappers); +const getOperationSpec: msRest.OperationSpec = { + httpMethod: "GET", + path: "subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.DBforMariaDB/servers/{serverName}/advisors/{advisorName}", + urlParameters: [ + Parameters.subscriptionId, + Parameters.resourceGroupName, + Parameters.serverName, + Parameters.advisorName + ], + queryParameters: [ + Parameters.apiVersion + ], + headerParameters: [ + Parameters.acceptLanguage + ], + responses: { + 200: { + bodyMapper: Mappers.Advisor + }, + default: { + bodyMapper: Mappers.CloudError + } + }, + serializer +}; + +const listByServerOperationSpec: msRest.OperationSpec = { + httpMethod: "GET", + path: "subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.DBforMariaDB/servers/{serverName}/advisors", + urlParameters: [ + Parameters.subscriptionId, + Parameters.resourceGroupName, + Parameters.serverName + ], + queryParameters: [ + Parameters.apiVersion + ], + headerParameters: [ + Parameters.acceptLanguage + ], + responses: { + 200: { + bodyMapper: Mappers.AdvisorsResultList + }, + default: { + bodyMapper: Mappers.CloudError + } + }, + serializer +}; + +const listByServerNextOperationSpec: msRest.OperationSpec = { + httpMethod: "GET", + baseUrl: "https://management.azure.com", + path: "{nextLink}", + urlParameters: [ + Parameters.nextPageLink + ], + headerParameters: [ + Parameters.acceptLanguage + ], + responses: { + 200: { + bodyMapper: Mappers.AdvisorsResultList + }, + default: { + bodyMapper: Mappers.CloudError + } + }, + serializer +}; diff --git a/sdk/mariadb/arm-mariadb/src/operations/configurations.ts b/sdk/mariadb/arm-mariadb/src/operations/configurations.ts index 914801c0295b..21e6bbb81a4d 100644 --- a/sdk/mariadb/arm-mariadb/src/operations/configurations.ts +++ b/sdk/mariadb/arm-mariadb/src/operations/configurations.ts @@ -29,8 +29,7 @@ export class Configurations { /** * Updates a configuration of a server. - * @param resourceGroupName The name of the resource group that contains the resource. You can - * obtain this value from the Azure Resource Manager API or the portal. + * @param resourceGroupName The name of the resource group. The name is case insensitive. * @param serverName The name of the server. * @param configurationName The name of the server configuration. * @param parameters The required parameters for updating a server configuration. @@ -44,8 +43,7 @@ export class Configurations { /** * Gets information about a configuration of server. - * @param resourceGroupName The name of the resource group that contains the resource. You can - * obtain this value from the Azure Resource Manager API or the portal. + * @param resourceGroupName The name of the resource group. The name is case insensitive. * @param serverName The name of the server. * @param configurationName The name of the server configuration. * @param [options] The optional parameters @@ -53,16 +51,14 @@ export class Configurations { */ get(resourceGroupName: string, serverName: string, configurationName: string, options?: msRest.RequestOptionsBase): Promise; /** - * @param resourceGroupName The name of the resource group that contains the resource. You can - * obtain this value from the Azure Resource Manager API or the portal. + * @param resourceGroupName The name of the resource group. The name is case insensitive. * @param serverName The name of the server. * @param configurationName The name of the server configuration. * @param callback The callback */ get(resourceGroupName: string, serverName: string, configurationName: string, callback: msRest.ServiceCallback): void; /** - * @param resourceGroupName The name of the resource group that contains the resource. You can - * obtain this value from the Azure Resource Manager API or the portal. + * @param resourceGroupName The name of the resource group. The name is case insensitive. * @param serverName The name of the server. * @param configurationName The name of the server configuration. * @param options The optional parameters @@ -83,23 +79,20 @@ export class Configurations { /** * List all the configurations in a given server. - * @param resourceGroupName The name of the resource group that contains the resource. You can - * obtain this value from the Azure Resource Manager API or the portal. + * @param resourceGroupName The name of the resource group. The name is case insensitive. * @param serverName The name of the server. * @param [options] The optional parameters * @returns Promise */ listByServer(resourceGroupName: string, serverName: string, options?: msRest.RequestOptionsBase): Promise; /** - * @param resourceGroupName The name of the resource group that contains the resource. You can - * obtain this value from the Azure Resource Manager API or the portal. + * @param resourceGroupName The name of the resource group. The name is case insensitive. * @param serverName The name of the server. * @param callback The callback */ listByServer(resourceGroupName: string, serverName: string, callback: msRest.ServiceCallback): void; /** - * @param resourceGroupName The name of the resource group that contains the resource. You can - * obtain this value from the Azure Resource Manager API or the portal. + * @param resourceGroupName The name of the resource group. The name is case insensitive. * @param serverName The name of the server. * @param options The optional parameters * @param callback The callback @@ -118,8 +111,7 @@ export class Configurations { /** * Updates a configuration of a server. - * @param resourceGroupName The name of the resource group that contains the resource. You can - * obtain this value from the Azure Resource Manager API or the portal. + * @param resourceGroupName The name of the resource group. The name is case insensitive. * @param serverName The name of the server. * @param configurationName The name of the server configuration. * @param parameters The required parameters for updating a server configuration. diff --git a/sdk/mariadb/arm-mariadb/src/operations/databases.ts b/sdk/mariadb/arm-mariadb/src/operations/databases.ts index 3a6e5f71a0f1..095b7247e3fc 100644 --- a/sdk/mariadb/arm-mariadb/src/operations/databases.ts +++ b/sdk/mariadb/arm-mariadb/src/operations/databases.ts @@ -29,8 +29,7 @@ export class Databases { /** * Creates a new database or updates an existing database. - * @param resourceGroupName The name of the resource group that contains the resource. You can - * obtain this value from the Azure Resource Manager API or the portal. + * @param resourceGroupName The name of the resource group. The name is case insensitive. * @param serverName The name of the server. * @param databaseName The name of the database. * @param parameters The required parameters for creating or updating a database. @@ -44,8 +43,7 @@ export class Databases { /** * Deletes a database. - * @param resourceGroupName The name of the resource group that contains the resource. You can - * obtain this value from the Azure Resource Manager API or the portal. + * @param resourceGroupName The name of the resource group. The name is case insensitive. * @param serverName The name of the server. * @param databaseName The name of the database. * @param [options] The optional parameters @@ -58,8 +56,7 @@ export class Databases { /** * Gets information about a database. - * @param resourceGroupName The name of the resource group that contains the resource. You can - * obtain this value from the Azure Resource Manager API or the portal. + * @param resourceGroupName The name of the resource group. The name is case insensitive. * @param serverName The name of the server. * @param databaseName The name of the database. * @param [options] The optional parameters @@ -67,16 +64,14 @@ export class Databases { */ get(resourceGroupName: string, serverName: string, databaseName: string, options?: msRest.RequestOptionsBase): Promise; /** - * @param resourceGroupName The name of the resource group that contains the resource. You can - * obtain this value from the Azure Resource Manager API or the portal. + * @param resourceGroupName The name of the resource group. The name is case insensitive. * @param serverName The name of the server. * @param databaseName The name of the database. * @param callback The callback */ get(resourceGroupName: string, serverName: string, databaseName: string, callback: msRest.ServiceCallback): void; /** - * @param resourceGroupName The name of the resource group that contains the resource. You can - * obtain this value from the Azure Resource Manager API or the portal. + * @param resourceGroupName The name of the resource group. The name is case insensitive. * @param serverName The name of the server. * @param databaseName The name of the database. * @param options The optional parameters @@ -97,23 +92,20 @@ export class Databases { /** * List all the databases in a given server. - * @param resourceGroupName The name of the resource group that contains the resource. You can - * obtain this value from the Azure Resource Manager API or the portal. + * @param resourceGroupName The name of the resource group. The name is case insensitive. * @param serverName The name of the server. * @param [options] The optional parameters * @returns Promise */ listByServer(resourceGroupName: string, serverName: string, options?: msRest.RequestOptionsBase): Promise; /** - * @param resourceGroupName The name of the resource group that contains the resource. You can - * obtain this value from the Azure Resource Manager API or the portal. + * @param resourceGroupName The name of the resource group. The name is case insensitive. * @param serverName The name of the server. * @param callback The callback */ listByServer(resourceGroupName: string, serverName: string, callback: msRest.ServiceCallback): void; /** - * @param resourceGroupName The name of the resource group that contains the resource. You can - * obtain this value from the Azure Resource Manager API or the portal. + * @param resourceGroupName The name of the resource group. The name is case insensitive. * @param serverName The name of the server. * @param options The optional parameters * @param callback The callback @@ -132,8 +124,7 @@ export class Databases { /** * Creates a new database or updates an existing database. - * @param resourceGroupName The name of the resource group that contains the resource. You can - * obtain this value from the Azure Resource Manager API or the portal. + * @param resourceGroupName The name of the resource group. The name is case insensitive. * @param serverName The name of the server. * @param databaseName The name of the database. * @param parameters The required parameters for creating or updating a database. @@ -155,8 +146,7 @@ export class Databases { /** * Deletes a database. - * @param resourceGroupName The name of the resource group that contains the resource. You can - * obtain this value from the Azure Resource Manager API or the portal. + * @param resourceGroupName The name of the resource group. The name is case insensitive. * @param serverName The name of the server. * @param databaseName The name of the database. * @param [options] The optional parameters diff --git a/sdk/mariadb/arm-mariadb/src/operations/firewallRules.ts b/sdk/mariadb/arm-mariadb/src/operations/firewallRules.ts index 796a8285006c..ba178778c816 100644 --- a/sdk/mariadb/arm-mariadb/src/operations/firewallRules.ts +++ b/sdk/mariadb/arm-mariadb/src/operations/firewallRules.ts @@ -29,8 +29,7 @@ export class FirewallRules { /** * Creates a new firewall rule or updates an existing firewall rule. - * @param resourceGroupName The name of the resource group that contains the resource. You can - * obtain this value from the Azure Resource Manager API or the portal. + * @param resourceGroupName The name of the resource group. The name is case insensitive. * @param serverName The name of the server. * @param firewallRuleName The name of the server firewall rule. * @param parameters The required parameters for creating or updating a firewall rule. @@ -44,8 +43,7 @@ export class FirewallRules { /** * Deletes a server firewall rule. - * @param resourceGroupName The name of the resource group that contains the resource. You can - * obtain this value from the Azure Resource Manager API or the portal. + * @param resourceGroupName The name of the resource group. The name is case insensitive. * @param serverName The name of the server. * @param firewallRuleName The name of the server firewall rule. * @param [options] The optional parameters @@ -58,8 +56,7 @@ export class FirewallRules { /** * Gets information about a server firewall rule. - * @param resourceGroupName The name of the resource group that contains the resource. You can - * obtain this value from the Azure Resource Manager API or the portal. + * @param resourceGroupName The name of the resource group. The name is case insensitive. * @param serverName The name of the server. * @param firewallRuleName The name of the server firewall rule. * @param [options] The optional parameters @@ -67,16 +64,14 @@ export class FirewallRules { */ get(resourceGroupName: string, serverName: string, firewallRuleName: string, options?: msRest.RequestOptionsBase): Promise; /** - * @param resourceGroupName The name of the resource group that contains the resource. You can - * obtain this value from the Azure Resource Manager API or the portal. + * @param resourceGroupName The name of the resource group. The name is case insensitive. * @param serverName The name of the server. * @param firewallRuleName The name of the server firewall rule. * @param callback The callback */ get(resourceGroupName: string, serverName: string, firewallRuleName: string, callback: msRest.ServiceCallback): void; /** - * @param resourceGroupName The name of the resource group that contains the resource. You can - * obtain this value from the Azure Resource Manager API or the portal. + * @param resourceGroupName The name of the resource group. The name is case insensitive. * @param serverName The name of the server. * @param firewallRuleName The name of the server firewall rule. * @param options The optional parameters @@ -97,23 +92,20 @@ export class FirewallRules { /** * List all the firewall rules in a given server. - * @param resourceGroupName The name of the resource group that contains the resource. You can - * obtain this value from the Azure Resource Manager API or the portal. + * @param resourceGroupName The name of the resource group. The name is case insensitive. * @param serverName The name of the server. * @param [options] The optional parameters * @returns Promise */ listByServer(resourceGroupName: string, serverName: string, options?: msRest.RequestOptionsBase): Promise; /** - * @param resourceGroupName The name of the resource group that contains the resource. You can - * obtain this value from the Azure Resource Manager API or the portal. + * @param resourceGroupName The name of the resource group. The name is case insensitive. * @param serverName The name of the server. * @param callback The callback */ listByServer(resourceGroupName: string, serverName: string, callback: msRest.ServiceCallback): void; /** - * @param resourceGroupName The name of the resource group that contains the resource. You can - * obtain this value from the Azure Resource Manager API or the portal. + * @param resourceGroupName The name of the resource group. The name is case insensitive. * @param serverName The name of the server. * @param options The optional parameters * @param callback The callback @@ -132,8 +124,7 @@ export class FirewallRules { /** * Creates a new firewall rule or updates an existing firewall rule. - * @param resourceGroupName The name of the resource group that contains the resource. You can - * obtain this value from the Azure Resource Manager API or the portal. + * @param resourceGroupName The name of the resource group. The name is case insensitive. * @param serverName The name of the server. * @param firewallRuleName The name of the server firewall rule. * @param parameters The required parameters for creating or updating a firewall rule. @@ -155,8 +146,7 @@ export class FirewallRules { /** * Deletes a server firewall rule. - * @param resourceGroupName The name of the resource group that contains the resource. You can - * obtain this value from the Azure Resource Manager API or the portal. + * @param resourceGroupName The name of the resource group. The name is case insensitive. * @param serverName The name of the server. * @param firewallRuleName The name of the server firewall rule. * @param [options] The optional parameters diff --git a/sdk/mariadb/arm-mariadb/src/operations/index.ts b/sdk/mariadb/arm-mariadb/src/operations/index.ts index bb02d2d2c5e9..6f7e043d4215 100644 --- a/sdk/mariadb/arm-mariadb/src/operations/index.ts +++ b/sdk/mariadb/arm-mariadb/src/operations/index.ts @@ -17,5 +17,14 @@ export * from "./configurations"; export * from "./logFiles"; export * from "./locationBasedPerformanceTier"; export * from "./checkNameAvailability"; -export * from "./serverSecurityAlertPolicies"; export * from "./operations"; +export * from "./queryTexts"; +export * from "./topQueryStatistics"; +export * from "./waitStatistics"; +export * from "./advisors"; +export * from "./recommendedActions"; +export * from "./locationBasedRecommendedActionSessionsOperationStatus"; +export * from "./locationBasedRecommendedActionSessionsResult"; +export * from "./privateEndpointConnections"; +export * from "./privateLinkResources"; +export * from "./serverSecurityAlertPolicies"; diff --git a/sdk/mariadb/arm-mariadb/src/operations/locationBasedRecommendedActionSessionsOperationStatus.ts b/sdk/mariadb/arm-mariadb/src/operations/locationBasedRecommendedActionSessionsOperationStatus.ts new file mode 100644 index 000000000000..66f6b2a5e748 --- /dev/null +++ b/sdk/mariadb/arm-mariadb/src/operations/locationBasedRecommendedActionSessionsOperationStatus.ts @@ -0,0 +1,87 @@ +/* + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + * Changes may cause incorrect behavior and will be lost if the code is + * regenerated. + */ + +import * as msRest from "@azure/ms-rest-js"; +import * as Models from "../models"; +import * as Mappers from "../models/locationBasedRecommendedActionSessionsOperationStatusMappers"; +import * as Parameters from "../models/parameters"; +import { MariaDBManagementClientContext } from "../mariaDBManagementClientContext"; + +/** Class representing a LocationBasedRecommendedActionSessionsOperationStatus. */ +export class LocationBasedRecommendedActionSessionsOperationStatus { + private readonly client: MariaDBManagementClientContext; + + /** + * Create a LocationBasedRecommendedActionSessionsOperationStatus. + * @param {MariaDBManagementClientContext} client Reference to the service client. + */ + constructor(client: MariaDBManagementClientContext) { + this.client = client; + } + + /** + * Recommendation action session operation status. + * @param locationName The name of the location. + * @param operationId The operation identifier. + * @param [options] The optional parameters + * @returns Promise + */ + get(locationName: string, operationId: string, options?: msRest.RequestOptionsBase): Promise; + /** + * @param locationName The name of the location. + * @param operationId The operation identifier. + * @param callback The callback + */ + get(locationName: string, operationId: string, callback: msRest.ServiceCallback): void; + /** + * @param locationName The name of the location. + * @param operationId The operation identifier. + * @param options The optional parameters + * @param callback The callback + */ + get(locationName: string, operationId: string, options: msRest.RequestOptionsBase, callback: msRest.ServiceCallback): void; + get(locationName: string, operationId: string, options?: msRest.RequestOptionsBase | msRest.ServiceCallback, callback?: msRest.ServiceCallback): Promise { + return this.client.sendOperationRequest( + { + locationName, + operationId, + options + }, + getOperationSpec, + callback) as Promise; + } +} + +// Operation Specifications +const serializer = new msRest.Serializer(Mappers); +const getOperationSpec: msRest.OperationSpec = { + httpMethod: "GET", + path: "subscriptions/{subscriptionId}/providers/Microsoft.DBforMariaDB/locations/{locationName}/recommendedActionSessionsAzureAsyncOperation/{operationId}", + urlParameters: [ + Parameters.subscriptionId, + Parameters.locationName, + Parameters.operationId + ], + queryParameters: [ + Parameters.apiVersion + ], + headerParameters: [ + Parameters.acceptLanguage + ], + responses: { + 200: { + bodyMapper: Mappers.RecommendedActionSessionsOperationStatus + }, + default: { + bodyMapper: Mappers.CloudError + } + }, + serializer +}; diff --git a/sdk/mariadb/arm-mariadb/src/operations/locationBasedRecommendedActionSessionsResult.ts b/sdk/mariadb/arm-mariadb/src/operations/locationBasedRecommendedActionSessionsResult.ts new file mode 100644 index 000000000000..ffe6272b36cc --- /dev/null +++ b/sdk/mariadb/arm-mariadb/src/operations/locationBasedRecommendedActionSessionsResult.ts @@ -0,0 +1,142 @@ +/* + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + * Changes may cause incorrect behavior and will be lost if the code is + * regenerated. + */ + +import * as msRest from "@azure/ms-rest-js"; +import * as Models from "../models"; +import * as Mappers from "../models/locationBasedRecommendedActionSessionsResultMappers"; +import * as Parameters from "../models/parameters"; +import { MariaDBManagementClientContext } from "../mariaDBManagementClientContext"; + +/** Class representing a LocationBasedRecommendedActionSessionsResult. */ +export class LocationBasedRecommendedActionSessionsResult { + private readonly client: MariaDBManagementClientContext; + + /** + * Create a LocationBasedRecommendedActionSessionsResult. + * @param {MariaDBManagementClientContext} client Reference to the service client. + */ + constructor(client: MariaDBManagementClientContext) { + this.client = client; + } + + /** + * Recommendation action session operation result. + * @param locationName The name of the location. + * @param operationId The operation identifier. + * @param [options] The optional parameters + * @returns Promise + */ + list(locationName: string, operationId: string, options?: msRest.RequestOptionsBase): Promise; + /** + * @param locationName The name of the location. + * @param operationId The operation identifier. + * @param callback The callback + */ + list(locationName: string, operationId: string, callback: msRest.ServiceCallback): void; + /** + * @param locationName The name of the location. + * @param operationId The operation identifier. + * @param options The optional parameters + * @param callback The callback + */ + list(locationName: string, operationId: string, options: msRest.RequestOptionsBase, callback: msRest.ServiceCallback): void; + list(locationName: string, operationId: string, options?: msRest.RequestOptionsBase | msRest.ServiceCallback, callback?: msRest.ServiceCallback): Promise { + return this.client.sendOperationRequest( + { + locationName, + operationId, + options + }, + listOperationSpec, + callback) as Promise; + } + + /** + * Recommendation action session operation result. + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @param [options] The optional parameters + * @returns Promise + */ + listNext(nextPageLink: string, options?: msRest.RequestOptionsBase): Promise; + /** + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @param callback The callback + */ + listNext(nextPageLink: string, callback: msRest.ServiceCallback): void; + /** + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @param options The optional parameters + * @param callback The callback + */ + listNext(nextPageLink: string, options: msRest.RequestOptionsBase, callback: msRest.ServiceCallback): void; + listNext(nextPageLink: string, options?: msRest.RequestOptionsBase | msRest.ServiceCallback, callback?: msRest.ServiceCallback): Promise { + return this.client.sendOperationRequest( + { + nextPageLink, + options + }, + listNextOperationSpec, + callback) as Promise; + } +} + +// Operation Specifications +const serializer = new msRest.Serializer(Mappers); +const listOperationSpec: msRest.OperationSpec = { + httpMethod: "GET", + path: "subscriptions/{subscriptionId}/providers/Microsoft.DBforMariaDB/locations/{locationName}/recommendedActionSessionsOperationResults/{operationId}", + urlParameters: [ + Parameters.subscriptionId, + Parameters.locationName, + Parameters.operationId + ], + queryParameters: [ + Parameters.apiVersion + ], + headerParameters: [ + Parameters.acceptLanguage + ], + responses: { + 200: { + bodyMapper: Mappers.RecommendationActionsResultList + }, + 201: { + bodyMapper: Mappers.RecommendationActionsResultList + }, + default: { + bodyMapper: Mappers.CloudError + } + }, + serializer +}; + +const listNextOperationSpec: msRest.OperationSpec = { + httpMethod: "GET", + baseUrl: "https://management.azure.com", + path: "{nextLink}", + urlParameters: [ + Parameters.nextPageLink + ], + headerParameters: [ + Parameters.acceptLanguage + ], + responses: { + 200: { + bodyMapper: Mappers.RecommendationActionsResultList + }, + 201: { + bodyMapper: Mappers.RecommendationActionsResultList + }, + default: { + bodyMapper: Mappers.CloudError + } + }, + serializer +}; diff --git a/sdk/mariadb/arm-mariadb/src/operations/logFiles.ts b/sdk/mariadb/arm-mariadb/src/operations/logFiles.ts index 30687cbb0c89..fbc8ca4ef30b 100644 --- a/sdk/mariadb/arm-mariadb/src/operations/logFiles.ts +++ b/sdk/mariadb/arm-mariadb/src/operations/logFiles.ts @@ -28,23 +28,20 @@ export class LogFiles { /** * List all the log files in a given server. - * @param resourceGroupName The name of the resource group that contains the resource. You can - * obtain this value from the Azure Resource Manager API or the portal. + * @param resourceGroupName The name of the resource group. The name is case insensitive. * @param serverName The name of the server. * @param [options] The optional parameters * @returns Promise */ listByServer(resourceGroupName: string, serverName: string, options?: msRest.RequestOptionsBase): Promise; /** - * @param resourceGroupName The name of the resource group that contains the resource. You can - * obtain this value from the Azure Resource Manager API or the portal. + * @param resourceGroupName The name of the resource group. The name is case insensitive. * @param serverName The name of the server. * @param callback The callback */ listByServer(resourceGroupName: string, serverName: string, callback: msRest.ServiceCallback): void; /** - * @param resourceGroupName The name of the resource group that contains the resource. You can - * obtain this value from the Azure Resource Manager API or the portal. + * @param resourceGroupName The name of the resource group. The name is case insensitive. * @param serverName The name of the server. * @param options The optional parameters * @param callback The callback diff --git a/sdk/mariadb/arm-mariadb/src/operations/privateEndpointConnections.ts b/sdk/mariadb/arm-mariadb/src/operations/privateEndpointConnections.ts new file mode 100644 index 000000000000..e19e5848595f --- /dev/null +++ b/sdk/mariadb/arm-mariadb/src/operations/privateEndpointConnections.ts @@ -0,0 +1,399 @@ +/* + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + * Changes may cause incorrect behavior and will be lost if the code is + * regenerated. + */ + +import * as msRest from "@azure/ms-rest-js"; +import * as msRestAzure from "@azure/ms-rest-azure-js"; +import * as Models from "../models"; +import * as Mappers from "../models/privateEndpointConnectionsMappers"; +import * as Parameters from "../models/parameters"; +import { MariaDBManagementClientContext } from "../mariaDBManagementClientContext"; + +/** Class representing a PrivateEndpointConnections. */ +export class PrivateEndpointConnections { + private readonly client: MariaDBManagementClientContext; + + /** + * Create a PrivateEndpointConnections. + * @param {MariaDBManagementClientContext} client Reference to the service client. + */ + constructor(client: MariaDBManagementClientContext) { + this.client = client; + } + + /** + * Gets a private endpoint connection. + * @param resourceGroupName The name of the resource group. The name is case insensitive. + * @param serverName The name of the server. + * @param privateEndpointConnectionName The name of the private endpoint connection. + * @param [options] The optional parameters + * @returns Promise + */ + get(resourceGroupName: string, serverName: string, privateEndpointConnectionName: string, options?: msRest.RequestOptionsBase): Promise; + /** + * @param resourceGroupName The name of the resource group. The name is case insensitive. + * @param serverName The name of the server. + * @param privateEndpointConnectionName The name of the private endpoint connection. + * @param callback The callback + */ + get(resourceGroupName: string, serverName: string, privateEndpointConnectionName: string, callback: msRest.ServiceCallback): void; + /** + * @param resourceGroupName The name of the resource group. The name is case insensitive. + * @param serverName The name of the server. + * @param privateEndpointConnectionName The name of the private endpoint connection. + * @param options The optional parameters + * @param callback The callback + */ + get(resourceGroupName: string, serverName: string, privateEndpointConnectionName: string, options: msRest.RequestOptionsBase, callback: msRest.ServiceCallback): void; + get(resourceGroupName: string, serverName: string, privateEndpointConnectionName: string, options?: msRest.RequestOptionsBase | msRest.ServiceCallback, callback?: msRest.ServiceCallback): Promise { + return this.client.sendOperationRequest( + { + resourceGroupName, + serverName, + privateEndpointConnectionName, + options + }, + getOperationSpec, + callback) as Promise; + } + + /** + * Approve or reject a private endpoint connection with a given name. + * @param resourceGroupName The name of the resource group. The name is case insensitive. + * @param serverName The name of the server. + * @param privateEndpointConnectionName + * @param parameters + * @param [options] The optional parameters + * @returns Promise + */ + createOrUpdate(resourceGroupName: string, serverName: string, privateEndpointConnectionName: string, parameters: Models.PrivateEndpointConnection, options?: msRest.RequestOptionsBase): Promise { + return this.beginCreateOrUpdate(resourceGroupName,serverName,privateEndpointConnectionName,parameters,options) + .then(lroPoller => lroPoller.pollUntilFinished()) as Promise; + } + + /** + * Deletes a private endpoint connection with a given name. + * @param resourceGroupName The name of the resource group. The name is case insensitive. + * @param serverName The name of the server. + * @param privateEndpointConnectionName + * @param [options] The optional parameters + * @returns Promise + */ + deleteMethod(resourceGroupName: string, serverName: string, privateEndpointConnectionName: string, options?: msRest.RequestOptionsBase): Promise { + return this.beginDeleteMethod(resourceGroupName,serverName,privateEndpointConnectionName,options) + .then(lroPoller => lroPoller.pollUntilFinished()); + } + + /** + * Updates private endpoint connection with the specified tags. + * @summary Updates tags on private endpoint connection. + * @param resourceGroupName The name of the resource group. The name is case insensitive. + * @param serverName The name of the server. + * @param privateEndpointConnectionName + * @param parameters Parameters supplied to the Update private endpoint connection Tags operation. + * @param [options] The optional parameters + * @returns Promise + */ + updateTags(resourceGroupName: string, serverName: string, privateEndpointConnectionName: string, parameters: Models.TagsObject, options?: msRest.RequestOptionsBase): Promise { + return this.beginUpdateTags(resourceGroupName,serverName,privateEndpointConnectionName,parameters,options) + .then(lroPoller => lroPoller.pollUntilFinished()) as Promise; + } + + /** + * Gets all private endpoint connections on a server. + * @param resourceGroupName The name of the resource group. The name is case insensitive. + * @param serverName The name of the server. + * @param [options] The optional parameters + * @returns Promise + */ + listByServer(resourceGroupName: string, serverName: string, options?: msRest.RequestOptionsBase): Promise; + /** + * @param resourceGroupName The name of the resource group. The name is case insensitive. + * @param serverName The name of the server. + * @param callback The callback + */ + listByServer(resourceGroupName: string, serverName: string, callback: msRest.ServiceCallback): void; + /** + * @param resourceGroupName The name of the resource group. The name is case insensitive. + * @param serverName The name of the server. + * @param options The optional parameters + * @param callback The callback + */ + listByServer(resourceGroupName: string, serverName: string, options: msRest.RequestOptionsBase, callback: msRest.ServiceCallback): void; + listByServer(resourceGroupName: string, serverName: string, options?: msRest.RequestOptionsBase | msRest.ServiceCallback, callback?: msRest.ServiceCallback): Promise { + return this.client.sendOperationRequest( + { + resourceGroupName, + serverName, + options + }, + listByServerOperationSpec, + callback) as Promise; + } + + /** + * Approve or reject a private endpoint connection with a given name. + * @param resourceGroupName The name of the resource group. The name is case insensitive. + * @param serverName The name of the server. + * @param privateEndpointConnectionName + * @param parameters + * @param [options] The optional parameters + * @returns Promise + */ + beginCreateOrUpdate(resourceGroupName: string, serverName: string, privateEndpointConnectionName: string, parameters: Models.PrivateEndpointConnection, options?: msRest.RequestOptionsBase): Promise { + return this.client.sendLRORequest( + { + resourceGroupName, + serverName, + privateEndpointConnectionName, + parameters, + options + }, + beginCreateOrUpdateOperationSpec, + options); + } + + /** + * Deletes a private endpoint connection with a given name. + * @param resourceGroupName The name of the resource group. The name is case insensitive. + * @param serverName The name of the server. + * @param privateEndpointConnectionName + * @param [options] The optional parameters + * @returns Promise + */ + beginDeleteMethod(resourceGroupName: string, serverName: string, privateEndpointConnectionName: string, options?: msRest.RequestOptionsBase): Promise { + return this.client.sendLRORequest( + { + resourceGroupName, + serverName, + privateEndpointConnectionName, + options + }, + beginDeleteMethodOperationSpec, + options); + } + + /** + * Updates private endpoint connection with the specified tags. + * @summary Updates tags on private endpoint connection. + * @param resourceGroupName The name of the resource group. The name is case insensitive. + * @param serverName The name of the server. + * @param privateEndpointConnectionName + * @param parameters Parameters supplied to the Update private endpoint connection Tags operation. + * @param [options] The optional parameters + * @returns Promise + */ + beginUpdateTags(resourceGroupName: string, serverName: string, privateEndpointConnectionName: string, parameters: Models.TagsObject, options?: msRest.RequestOptionsBase): Promise { + return this.client.sendLRORequest( + { + resourceGroupName, + serverName, + privateEndpointConnectionName, + parameters, + options + }, + beginUpdateTagsOperationSpec, + options); + } + + /** + * Gets all private endpoint connections on a server. + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @param [options] The optional parameters + * @returns Promise + */ + listByServerNext(nextPageLink: string, options?: msRest.RequestOptionsBase): Promise; + /** + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @param callback The callback + */ + listByServerNext(nextPageLink: string, callback: msRest.ServiceCallback): void; + /** + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @param options The optional parameters + * @param callback The callback + */ + listByServerNext(nextPageLink: string, options: msRest.RequestOptionsBase, callback: msRest.ServiceCallback): void; + listByServerNext(nextPageLink: string, options?: msRest.RequestOptionsBase | msRest.ServiceCallback, callback?: msRest.ServiceCallback): Promise { + return this.client.sendOperationRequest( + { + nextPageLink, + options + }, + listByServerNextOperationSpec, + callback) as Promise; + } +} + +// Operation Specifications +const serializer = new msRest.Serializer(Mappers); +const getOperationSpec: msRest.OperationSpec = { + httpMethod: "GET", + path: "subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.DBforMariaDB/servers/{serverName}/privateEndpointConnections/{privateEndpointConnectionName}", + urlParameters: [ + Parameters.resourceGroupName, + Parameters.serverName, + Parameters.privateEndpointConnectionName, + Parameters.subscriptionId + ], + queryParameters: [ + Parameters.apiVersion + ], + headerParameters: [ + Parameters.acceptLanguage + ], + responses: { + 200: { + bodyMapper: Mappers.PrivateEndpointConnection + }, + default: { + bodyMapper: Mappers.CloudError + } + }, + serializer +}; + +const listByServerOperationSpec: msRest.OperationSpec = { + httpMethod: "GET", + path: "subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.DBforMariaDB/servers/{serverName}/privateEndpointConnections", + urlParameters: [ + Parameters.resourceGroupName, + Parameters.serverName, + Parameters.subscriptionId + ], + queryParameters: [ + Parameters.apiVersion + ], + headerParameters: [ + Parameters.acceptLanguage + ], + responses: { + 200: { + bodyMapper: Mappers.PrivateEndpointConnectionListResult + }, + default: { + bodyMapper: Mappers.CloudError + } + }, + serializer +}; + +const beginCreateOrUpdateOperationSpec: msRest.OperationSpec = { + httpMethod: "PUT", + path: "subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.DBforMariaDB/servers/{serverName}/privateEndpointConnections/{privateEndpointConnectionName}", + urlParameters: [ + Parameters.resourceGroupName, + Parameters.serverName, + Parameters.privateEndpointConnectionName, + Parameters.subscriptionId + ], + queryParameters: [ + Parameters.apiVersion + ], + headerParameters: [ + Parameters.acceptLanguage + ], + requestBody: { + parameterPath: "parameters", + mapper: { + ...Mappers.PrivateEndpointConnection, + required: true + } + }, + responses: { + 200: { + bodyMapper: Mappers.PrivateEndpointConnection + }, + 202: {}, + default: { + bodyMapper: Mappers.CloudError + } + }, + serializer +}; + +const beginDeleteMethodOperationSpec: msRest.OperationSpec = { + httpMethod: "DELETE", + path: "subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.DBforMariaDB/servers/{serverName}/privateEndpointConnections/{privateEndpointConnectionName}", + urlParameters: [ + Parameters.resourceGroupName, + Parameters.serverName, + Parameters.privateEndpointConnectionName, + Parameters.subscriptionId + ], + queryParameters: [ + Parameters.apiVersion + ], + headerParameters: [ + Parameters.acceptLanguage + ], + responses: { + 200: {}, + 202: {}, + 204: {}, + default: { + bodyMapper: Mappers.CloudError + } + }, + serializer +}; + +const beginUpdateTagsOperationSpec: msRest.OperationSpec = { + httpMethod: "PATCH", + path: "subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.DBforMariaDB/servers/{serverName}/privateEndpointConnections/{privateEndpointConnectionName}", + urlParameters: [ + Parameters.subscriptionId, + Parameters.resourceGroupName, + Parameters.serverName, + Parameters.privateEndpointConnectionName + ], + queryParameters: [ + Parameters.apiVersion + ], + headerParameters: [ + Parameters.acceptLanguage + ], + requestBody: { + parameterPath: "parameters", + mapper: { + ...Mappers.TagsObject, + required: true + } + }, + responses: { + 200: { + bodyMapper: Mappers.PrivateEndpointConnection + }, + default: { + bodyMapper: Mappers.CloudError + } + }, + serializer +}; + +const listByServerNextOperationSpec: msRest.OperationSpec = { + httpMethod: "GET", + baseUrl: "https://management.azure.com", + path: "{nextLink}", + urlParameters: [ + Parameters.nextPageLink + ], + headerParameters: [ + Parameters.acceptLanguage + ], + responses: { + 200: { + bodyMapper: Mappers.PrivateEndpointConnectionListResult + }, + default: { + bodyMapper: Mappers.CloudError + } + }, + serializer +}; diff --git a/sdk/mariadb/arm-mariadb/src/operations/privateLinkResources.ts b/sdk/mariadb/arm-mariadb/src/operations/privateLinkResources.ts new file mode 100644 index 000000000000..5dc922280e40 --- /dev/null +++ b/sdk/mariadb/arm-mariadb/src/operations/privateLinkResources.ts @@ -0,0 +1,198 @@ +/* + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + * Changes may cause incorrect behavior and will be lost if the code is + * regenerated. + */ + +import * as msRest from "@azure/ms-rest-js"; +import * as Models from "../models"; +import * as Mappers from "../models/privateLinkResourcesMappers"; +import * as Parameters from "../models/parameters"; +import { MariaDBManagementClientContext } from "../mariaDBManagementClientContext"; + +/** Class representing a PrivateLinkResources. */ +export class PrivateLinkResources { + private readonly client: MariaDBManagementClientContext; + + /** + * Create a PrivateLinkResources. + * @param {MariaDBManagementClientContext} client Reference to the service client. + */ + constructor(client: MariaDBManagementClientContext) { + this.client = client; + } + + /** + * Gets the private link resources for MariaDB server. + * @param resourceGroupName The name of the resource group. The name is case insensitive. + * @param serverName The name of the server. + * @param [options] The optional parameters + * @returns Promise + */ + listByServer(resourceGroupName: string, serverName: string, options?: msRest.RequestOptionsBase): Promise; + /** + * @param resourceGroupName The name of the resource group. The name is case insensitive. + * @param serverName The name of the server. + * @param callback The callback + */ + listByServer(resourceGroupName: string, serverName: string, callback: msRest.ServiceCallback): void; + /** + * @param resourceGroupName The name of the resource group. The name is case insensitive. + * @param serverName The name of the server. + * @param options The optional parameters + * @param callback The callback + */ + listByServer(resourceGroupName: string, serverName: string, options: msRest.RequestOptionsBase, callback: msRest.ServiceCallback): void; + listByServer(resourceGroupName: string, serverName: string, options?: msRest.RequestOptionsBase | msRest.ServiceCallback, callback?: msRest.ServiceCallback): Promise { + return this.client.sendOperationRequest( + { + resourceGroupName, + serverName, + options + }, + listByServerOperationSpec, + callback) as Promise; + } + + /** + * Gets a private link resource for MariaDB server. + * @param resourceGroupName The name of the resource group. The name is case insensitive. + * @param serverName The name of the server. + * @param groupName The name of the private link resource. + * @param [options] The optional parameters + * @returns Promise + */ + get(resourceGroupName: string, serverName: string, groupName: string, options?: msRest.RequestOptionsBase): Promise; + /** + * @param resourceGroupName The name of the resource group. The name is case insensitive. + * @param serverName The name of the server. + * @param groupName The name of the private link resource. + * @param callback The callback + */ + get(resourceGroupName: string, serverName: string, groupName: string, callback: msRest.ServiceCallback): void; + /** + * @param resourceGroupName The name of the resource group. The name is case insensitive. + * @param serverName The name of the server. + * @param groupName The name of the private link resource. + * @param options The optional parameters + * @param callback The callback + */ + get(resourceGroupName: string, serverName: string, groupName: string, options: msRest.RequestOptionsBase, callback: msRest.ServiceCallback): void; + get(resourceGroupName: string, serverName: string, groupName: string, options?: msRest.RequestOptionsBase | msRest.ServiceCallback, callback?: msRest.ServiceCallback): Promise { + return this.client.sendOperationRequest( + { + resourceGroupName, + serverName, + groupName, + options + }, + getOperationSpec, + callback) as Promise; + } + + /** + * Gets the private link resources for MariaDB server. + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @param [options] The optional parameters + * @returns Promise + */ + listByServerNext(nextPageLink: string, options?: msRest.RequestOptionsBase): Promise; + /** + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @param callback The callback + */ + listByServerNext(nextPageLink: string, callback: msRest.ServiceCallback): void; + /** + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @param options The optional parameters + * @param callback The callback + */ + listByServerNext(nextPageLink: string, options: msRest.RequestOptionsBase, callback: msRest.ServiceCallback): void; + listByServerNext(nextPageLink: string, options?: msRest.RequestOptionsBase | msRest.ServiceCallback, callback?: msRest.ServiceCallback): Promise { + return this.client.sendOperationRequest( + { + nextPageLink, + options + }, + listByServerNextOperationSpec, + callback) as Promise; + } +} + +// Operation Specifications +const serializer = new msRest.Serializer(Mappers); +const listByServerOperationSpec: msRest.OperationSpec = { + httpMethod: "GET", + path: "subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.DBforMariaDB/servers/{serverName}/privateLinkResources", + urlParameters: [ + Parameters.resourceGroupName, + Parameters.serverName, + Parameters.subscriptionId + ], + queryParameters: [ + Parameters.apiVersion + ], + headerParameters: [ + Parameters.acceptLanguage + ], + responses: { + 200: { + bodyMapper: Mappers.PrivateLinkResourceListResult + }, + default: { + bodyMapper: Mappers.CloudError + } + }, + serializer +}; + +const getOperationSpec: msRest.OperationSpec = { + httpMethod: "GET", + path: "subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.DBforMariaDB/servers/{serverName}/privateLinkResources/{groupName}", + urlParameters: [ + Parameters.resourceGroupName, + Parameters.serverName, + Parameters.groupName, + Parameters.subscriptionId + ], + queryParameters: [ + Parameters.apiVersion + ], + headerParameters: [ + Parameters.acceptLanguage + ], + responses: { + 200: { + bodyMapper: Mappers.PrivateLinkResource + }, + default: { + bodyMapper: Mappers.CloudError + } + }, + serializer +}; + +const listByServerNextOperationSpec: msRest.OperationSpec = { + httpMethod: "GET", + baseUrl: "https://management.azure.com", + path: "{nextLink}", + urlParameters: [ + Parameters.nextPageLink + ], + headerParameters: [ + Parameters.acceptLanguage + ], + responses: { + 200: { + bodyMapper: Mappers.PrivateLinkResourceListResult + }, + default: { + bodyMapper: Mappers.CloudError + } + }, + serializer +}; diff --git a/sdk/mariadb/arm-mariadb/src/operations/queryTexts.ts b/sdk/mariadb/arm-mariadb/src/operations/queryTexts.ts new file mode 100644 index 000000000000..37f0d778143f --- /dev/null +++ b/sdk/mariadb/arm-mariadb/src/operations/queryTexts.ts @@ -0,0 +1,203 @@ +/* + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + * Changes may cause incorrect behavior and will be lost if the code is + * regenerated. + */ + +import * as msRest from "@azure/ms-rest-js"; +import * as Models from "../models"; +import * as Mappers from "../models/queryTextsMappers"; +import * as Parameters from "../models/parameters"; +import { MariaDBManagementClientContext } from "../mariaDBManagementClientContext"; + +/** Class representing a QueryTexts. */ +export class QueryTexts { + private readonly client: MariaDBManagementClientContext; + + /** + * Create a QueryTexts. + * @param {MariaDBManagementClientContext} client Reference to the service client. + */ + constructor(client: MariaDBManagementClientContext) { + this.client = client; + } + + /** + * Retrieve the Query-Store query texts for the queryId. + * @param resourceGroupName The name of the resource group. The name is case insensitive. + * @param serverName The name of the server. + * @param queryId The Query-Store query identifier. + * @param [options] The optional parameters + * @returns Promise + */ + get(resourceGroupName: string, serverName: string, queryId: string, options?: msRest.RequestOptionsBase): Promise; + /** + * @param resourceGroupName The name of the resource group. The name is case insensitive. + * @param serverName The name of the server. + * @param queryId The Query-Store query identifier. + * @param callback The callback + */ + get(resourceGroupName: string, serverName: string, queryId: string, callback: msRest.ServiceCallback): void; + /** + * @param resourceGroupName The name of the resource group. The name is case insensitive. + * @param serverName The name of the server. + * @param queryId The Query-Store query identifier. + * @param options The optional parameters + * @param callback The callback + */ + get(resourceGroupName: string, serverName: string, queryId: string, options: msRest.RequestOptionsBase, callback: msRest.ServiceCallback): void; + get(resourceGroupName: string, serverName: string, queryId: string, options?: msRest.RequestOptionsBase | msRest.ServiceCallback, callback?: msRest.ServiceCallback): Promise { + return this.client.sendOperationRequest( + { + resourceGroupName, + serverName, + queryId, + options + }, + getOperationSpec, + callback) as Promise; + } + + /** + * Retrieve the Query-Store query texts for specified queryIds. + * @param resourceGroupName The name of the resource group. The name is case insensitive. + * @param serverName The name of the server. + * @param queryIds The query identifiers + * @param [options] The optional parameters + * @returns Promise + */ + listByServer(resourceGroupName: string, serverName: string, queryIds: string[], options?: msRest.RequestOptionsBase): Promise; + /** + * @param resourceGroupName The name of the resource group. The name is case insensitive. + * @param serverName The name of the server. + * @param queryIds The query identifiers + * @param callback The callback + */ + listByServer(resourceGroupName: string, serverName: string, queryIds: string[], callback: msRest.ServiceCallback): void; + /** + * @param resourceGroupName The name of the resource group. The name is case insensitive. + * @param serverName The name of the server. + * @param queryIds The query identifiers + * @param options The optional parameters + * @param callback The callback + */ + listByServer(resourceGroupName: string, serverName: string, queryIds: string[], options: msRest.RequestOptionsBase, callback: msRest.ServiceCallback): void; + listByServer(resourceGroupName: string, serverName: string, queryIds: string[], options?: msRest.RequestOptionsBase | msRest.ServiceCallback, callback?: msRest.ServiceCallback): Promise { + return this.client.sendOperationRequest( + { + resourceGroupName, + serverName, + queryIds, + options + }, + listByServerOperationSpec, + callback) as Promise; + } + + /** + * Retrieve the Query-Store query texts for specified queryIds. + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @param [options] The optional parameters + * @returns Promise + */ + listByServerNext(nextPageLink: string, options?: msRest.RequestOptionsBase): Promise; + /** + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @param callback The callback + */ + listByServerNext(nextPageLink: string, callback: msRest.ServiceCallback): void; + /** + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @param options The optional parameters + * @param callback The callback + */ + listByServerNext(nextPageLink: string, options: msRest.RequestOptionsBase, callback: msRest.ServiceCallback): void; + listByServerNext(nextPageLink: string, options?: msRest.RequestOptionsBase | msRest.ServiceCallback, callback?: msRest.ServiceCallback): Promise { + return this.client.sendOperationRequest( + { + nextPageLink, + options + }, + listByServerNextOperationSpec, + callback) as Promise; + } +} + +// Operation Specifications +const serializer = new msRest.Serializer(Mappers); +const getOperationSpec: msRest.OperationSpec = { + httpMethod: "GET", + path: "subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.DBforMariaDB/servers/{serverName}/queryTexts/{queryId}", + urlParameters: [ + Parameters.subscriptionId, + Parameters.resourceGroupName, + Parameters.serverName, + Parameters.queryId + ], + queryParameters: [ + Parameters.apiVersion + ], + headerParameters: [ + Parameters.acceptLanguage + ], + responses: { + 200: { + bodyMapper: Mappers.QueryText + }, + default: { + bodyMapper: Mappers.CloudError + } + }, + serializer +}; + +const listByServerOperationSpec: msRest.OperationSpec = { + httpMethod: "GET", + path: "subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.DBforMariaDB/servers/{serverName}/queryTexts", + urlParameters: [ + Parameters.subscriptionId, + Parameters.resourceGroupName, + Parameters.serverName + ], + queryParameters: [ + Parameters.apiVersion, + Parameters.queryIds + ], + headerParameters: [ + Parameters.acceptLanguage + ], + responses: { + 200: { + bodyMapper: Mappers.QueryTextsResultList + }, + default: { + bodyMapper: Mappers.CloudError + } + }, + serializer +}; + +const listByServerNextOperationSpec: msRest.OperationSpec = { + httpMethod: "GET", + baseUrl: "https://management.azure.com", + path: "{nextLink}", + urlParameters: [ + Parameters.nextPageLink + ], + headerParameters: [ + Parameters.acceptLanguage + ], + responses: { + 200: { + bodyMapper: Mappers.QueryTextsResultList + }, + default: { + bodyMapper: Mappers.CloudError + } + }, + serializer +}; diff --git a/sdk/mariadb/arm-mariadb/src/operations/recommendedActions.ts b/sdk/mariadb/arm-mariadb/src/operations/recommendedActions.ts new file mode 100644 index 000000000000..e5dc0d640dd7 --- /dev/null +++ b/sdk/mariadb/arm-mariadb/src/operations/recommendedActions.ts @@ -0,0 +1,209 @@ +/* + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + * Changes may cause incorrect behavior and will be lost if the code is + * regenerated. + */ + +import * as msRest from "@azure/ms-rest-js"; +import * as Models from "../models"; +import * as Mappers from "../models/recommendedActionsMappers"; +import * as Parameters from "../models/parameters"; +import { MariaDBManagementClientContext } from "../mariaDBManagementClientContext"; + +/** Class representing a RecommendedActions. */ +export class RecommendedActions { + private readonly client: MariaDBManagementClientContext; + + /** + * Create a RecommendedActions. + * @param {MariaDBManagementClientContext} client Reference to the service client. + */ + constructor(client: MariaDBManagementClientContext) { + this.client = client; + } + + /** + * Retrieve recommended actions from the advisor. + * @param resourceGroupName The name of the resource group. The name is case insensitive. + * @param serverName The name of the server. + * @param advisorName The advisor name for recommendation action. + * @param recommendedActionName The recommended action name. + * @param [options] The optional parameters + * @returns Promise + */ + get(resourceGroupName: string, serverName: string, advisorName: string, recommendedActionName: string, options?: msRest.RequestOptionsBase): Promise; + /** + * @param resourceGroupName The name of the resource group. The name is case insensitive. + * @param serverName The name of the server. + * @param advisorName The advisor name for recommendation action. + * @param recommendedActionName The recommended action name. + * @param callback The callback + */ + get(resourceGroupName: string, serverName: string, advisorName: string, recommendedActionName: string, callback: msRest.ServiceCallback): void; + /** + * @param resourceGroupName The name of the resource group. The name is case insensitive. + * @param serverName The name of the server. + * @param advisorName The advisor name for recommendation action. + * @param recommendedActionName The recommended action name. + * @param options The optional parameters + * @param callback The callback + */ + get(resourceGroupName: string, serverName: string, advisorName: string, recommendedActionName: string, options: msRest.RequestOptionsBase, callback: msRest.ServiceCallback): void; + get(resourceGroupName: string, serverName: string, advisorName: string, recommendedActionName: string, options?: msRest.RequestOptionsBase | msRest.ServiceCallback, callback?: msRest.ServiceCallback): Promise { + return this.client.sendOperationRequest( + { + resourceGroupName, + serverName, + advisorName, + recommendedActionName, + options + }, + getOperationSpec, + callback) as Promise; + } + + /** + * Retrieve recommended actions from the advisor. + * @param resourceGroupName The name of the resource group. The name is case insensitive. + * @param serverName The name of the server. + * @param advisorName The advisor name for recommendation action. + * @param [options] The optional parameters + * @returns Promise + */ + listByServer(resourceGroupName: string, serverName: string, advisorName: string, options?: Models.RecommendedActionsListByServerOptionalParams): Promise; + /** + * @param resourceGroupName The name of the resource group. The name is case insensitive. + * @param serverName The name of the server. + * @param advisorName The advisor name for recommendation action. + * @param callback The callback + */ + listByServer(resourceGroupName: string, serverName: string, advisorName: string, callback: msRest.ServiceCallback): void; + /** + * @param resourceGroupName The name of the resource group. The name is case insensitive. + * @param serverName The name of the server. + * @param advisorName The advisor name for recommendation action. + * @param options The optional parameters + * @param callback The callback + */ + listByServer(resourceGroupName: string, serverName: string, advisorName: string, options: Models.RecommendedActionsListByServerOptionalParams, callback: msRest.ServiceCallback): void; + listByServer(resourceGroupName: string, serverName: string, advisorName: string, options?: Models.RecommendedActionsListByServerOptionalParams | msRest.ServiceCallback, callback?: msRest.ServiceCallback): Promise { + return this.client.sendOperationRequest( + { + resourceGroupName, + serverName, + advisorName, + options + }, + listByServerOperationSpec, + callback) as Promise; + } + + /** + * Retrieve recommended actions from the advisor. + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @param [options] The optional parameters + * @returns Promise + */ + listByServerNext(nextPageLink: string, options?: msRest.RequestOptionsBase): Promise; + /** + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @param callback The callback + */ + listByServerNext(nextPageLink: string, callback: msRest.ServiceCallback): void; + /** + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @param options The optional parameters + * @param callback The callback + */ + listByServerNext(nextPageLink: string, options: msRest.RequestOptionsBase, callback: msRest.ServiceCallback): void; + listByServerNext(nextPageLink: string, options?: msRest.RequestOptionsBase | msRest.ServiceCallback, callback?: msRest.ServiceCallback): Promise { + return this.client.sendOperationRequest( + { + nextPageLink, + options + }, + listByServerNextOperationSpec, + callback) as Promise; + } +} + +// Operation Specifications +const serializer = new msRest.Serializer(Mappers); +const getOperationSpec: msRest.OperationSpec = { + httpMethod: "GET", + path: "subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.DBforMariaDB/servers/{serverName}/advisors/{advisorName}/recommendedActions/{recommendedActionName}", + urlParameters: [ + Parameters.subscriptionId, + Parameters.resourceGroupName, + Parameters.serverName, + Parameters.advisorName, + Parameters.recommendedActionName + ], + queryParameters: [ + Parameters.apiVersion + ], + headerParameters: [ + Parameters.acceptLanguage + ], + responses: { + 200: { + bodyMapper: Mappers.RecommendationAction + }, + default: { + bodyMapper: Mappers.CloudError + } + }, + serializer +}; + +const listByServerOperationSpec: msRest.OperationSpec = { + httpMethod: "GET", + path: "subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.DBforMariaDB/servers/{serverName}/advisors/{advisorName}/recommendedActions", + urlParameters: [ + Parameters.subscriptionId, + Parameters.resourceGroupName, + Parameters.serverName, + Parameters.advisorName + ], + queryParameters: [ + Parameters.apiVersion, + Parameters.sessionId + ], + headerParameters: [ + Parameters.acceptLanguage + ], + responses: { + 200: { + bodyMapper: Mappers.RecommendationActionsResultList + }, + default: { + bodyMapper: Mappers.CloudError + } + }, + serializer +}; + +const listByServerNextOperationSpec: msRest.OperationSpec = { + httpMethod: "GET", + baseUrl: "https://management.azure.com", + path: "{nextLink}", + urlParameters: [ + Parameters.nextPageLink + ], + headerParameters: [ + Parameters.acceptLanguage + ], + responses: { + 200: { + bodyMapper: Mappers.RecommendationActionsResultList + }, + default: { + bodyMapper: Mappers.CloudError + } + }, + serializer +}; diff --git a/sdk/mariadb/arm-mariadb/src/operations/replicas.ts b/sdk/mariadb/arm-mariadb/src/operations/replicas.ts index 0359016a2178..6ffd0670c465 100644 --- a/sdk/mariadb/arm-mariadb/src/operations/replicas.ts +++ b/sdk/mariadb/arm-mariadb/src/operations/replicas.ts @@ -28,23 +28,20 @@ export class Replicas { /** * List all the replicas for a given server. - * @param resourceGroupName The name of the resource group that contains the resource. You can - * obtain this value from the Azure Resource Manager API or the portal. + * @param resourceGroupName The name of the resource group. The name is case insensitive. * @param serverName The name of the server. * @param [options] The optional parameters * @returns Promise */ listByServer(resourceGroupName: string, serverName: string, options?: msRest.RequestOptionsBase): Promise; /** - * @param resourceGroupName The name of the resource group that contains the resource. You can - * obtain this value from the Azure Resource Manager API or the portal. + * @param resourceGroupName The name of the resource group. The name is case insensitive. * @param serverName The name of the server. * @param callback The callback */ listByServer(resourceGroupName: string, serverName: string, callback: msRest.ServiceCallback): void; /** - * @param resourceGroupName The name of the resource group that contains the resource. You can - * obtain this value from the Azure Resource Manager API or the portal. + * @param resourceGroupName The name of the resource group. The name is case insensitive. * @param serverName The name of the server. * @param options The optional parameters * @param callback The callback diff --git a/sdk/mariadb/arm-mariadb/src/operations/serverSecurityAlertPolicies.ts b/sdk/mariadb/arm-mariadb/src/operations/serverSecurityAlertPolicies.ts index b6b4ce11d763..71affe526027 100644 --- a/sdk/mariadb/arm-mariadb/src/operations/serverSecurityAlertPolicies.ts +++ b/sdk/mariadb/arm-mariadb/src/operations/serverSecurityAlertPolicies.ts @@ -29,23 +29,20 @@ export class ServerSecurityAlertPolicies { /** * Get a server's security alert policy. - * @param resourceGroupName The name of the resource group that contains the resource. You can - * obtain this value from the Azure Resource Manager API or the portal. + * @param resourceGroupName The name of the resource group. The name is case insensitive. * @param serverName The name of the server. * @param [options] The optional parameters * @returns Promise */ get(resourceGroupName: string, serverName: string, options?: msRest.RequestOptionsBase): Promise; /** - * @param resourceGroupName The name of the resource group that contains the resource. You can - * obtain this value from the Azure Resource Manager API or the portal. + * @param resourceGroupName The name of the resource group. The name is case insensitive. * @param serverName The name of the server. * @param callback The callback */ get(resourceGroupName: string, serverName: string, callback: msRest.ServiceCallback): void; /** - * @param resourceGroupName The name of the resource group that contains the resource. You can - * obtain this value from the Azure Resource Manager API or the portal. + * @param resourceGroupName The name of the resource group. The name is case insensitive. * @param serverName The name of the server. * @param options The optional parameters * @param callback The callback @@ -64,8 +61,7 @@ export class ServerSecurityAlertPolicies { /** * Creates or updates a threat detection policy. - * @param resourceGroupName The name of the resource group that contains the resource. You can - * obtain this value from the Azure Resource Manager API or the portal. + * @param resourceGroupName The name of the resource group. The name is case insensitive. * @param serverName The name of the server. * @param parameters The server security alert policy. * @param [options] The optional parameters @@ -78,8 +74,7 @@ export class ServerSecurityAlertPolicies { /** * Creates or updates a threat detection policy. - * @param resourceGroupName The name of the resource group that contains the resource. You can - * obtain this value from the Azure Resource Manager API or the portal. + * @param resourceGroupName The name of the resource group. The name is case insensitive. * @param serverName The name of the server. * @param parameters The server security alert policy. * @param [options] The optional parameters diff --git a/sdk/mariadb/arm-mariadb/src/operations/servers.ts b/sdk/mariadb/arm-mariadb/src/operations/servers.ts index 65eb20b35d53..edbf17a29fc9 100644 --- a/sdk/mariadb/arm-mariadb/src/operations/servers.ts +++ b/sdk/mariadb/arm-mariadb/src/operations/servers.ts @@ -30,8 +30,7 @@ export class Servers { /** * Creates a new server or updates an existing server. The update action will overwrite the * existing server. - * @param resourceGroupName The name of the resource group that contains the resource. You can - * obtain this value from the Azure Resource Manager API or the portal. + * @param resourceGroupName The name of the resource group. The name is case insensitive. * @param serverName The name of the server. * @param parameters The required parameters for creating or updating a server. * @param [options] The optional parameters @@ -45,8 +44,7 @@ export class Servers { /** * Updates an existing server. The request body can contain one to many of the properties present * in the normal server definition. - * @param resourceGroupName The name of the resource group that contains the resource. You can - * obtain this value from the Azure Resource Manager API or the portal. + * @param resourceGroupName The name of the resource group. The name is case insensitive. * @param serverName The name of the server. * @param parameters The required parameters for updating a server. * @param [options] The optional parameters @@ -59,8 +57,7 @@ export class Servers { /** * Deletes a server. - * @param resourceGroupName The name of the resource group that contains the resource. You can - * obtain this value from the Azure Resource Manager API or the portal. + * @param resourceGroupName The name of the resource group. The name is case insensitive. * @param serverName The name of the server. * @param [options] The optional parameters * @returns Promise @@ -72,23 +69,20 @@ export class Servers { /** * Gets information about a server. - * @param resourceGroupName The name of the resource group that contains the resource. You can - * obtain this value from the Azure Resource Manager API or the portal. + * @param resourceGroupName The name of the resource group. The name is case insensitive. * @param serverName The name of the server. * @param [options] The optional parameters * @returns Promise */ get(resourceGroupName: string, serverName: string, options?: msRest.RequestOptionsBase): Promise; /** - * @param resourceGroupName The name of the resource group that contains the resource. You can - * obtain this value from the Azure Resource Manager API or the portal. + * @param resourceGroupName The name of the resource group. The name is case insensitive. * @param serverName The name of the server. * @param callback The callback */ get(resourceGroupName: string, serverName: string, callback: msRest.ServiceCallback): void; /** - * @param resourceGroupName The name of the resource group that contains the resource. You can - * obtain this value from the Azure Resource Manager API or the portal. + * @param resourceGroupName The name of the resource group. The name is case insensitive. * @param serverName The name of the server. * @param options The optional parameters * @param callback The callback @@ -107,21 +101,18 @@ export class Servers { /** * List all the servers in a given resource group. - * @param resourceGroupName The name of the resource group that contains the resource. You can - * obtain this value from the Azure Resource Manager API or the portal. + * @param resourceGroupName The name of the resource group. The name is case insensitive. * @param [options] The optional parameters * @returns Promise */ listByResourceGroup(resourceGroupName: string, options?: msRest.RequestOptionsBase): Promise; /** - * @param resourceGroupName The name of the resource group that contains the resource. You can - * obtain this value from the Azure Resource Manager API or the portal. + * @param resourceGroupName The name of the resource group. The name is case insensitive. * @param callback The callback */ listByResourceGroup(resourceGroupName: string, callback: msRest.ServiceCallback): void; /** - * @param resourceGroupName The name of the resource group that contains the resource. You can - * obtain this value from the Azure Resource Manager API or the portal. + * @param resourceGroupName The name of the resource group. The name is case insensitive. * @param options The optional parameters * @param callback The callback */ @@ -162,8 +153,7 @@ export class Servers { /** * Restarts a server. - * @param resourceGroupName The name of the resource group that contains the resource. You can - * obtain this value from the Azure Resource Manager API or the portal. + * @param resourceGroupName The name of the resource group. The name is case insensitive. * @param serverName The name of the server. * @param [options] The optional parameters * @returns Promise @@ -176,8 +166,7 @@ export class Servers { /** * Creates a new server or updates an existing server. The update action will overwrite the * existing server. - * @param resourceGroupName The name of the resource group that contains the resource. You can - * obtain this value from the Azure Resource Manager API or the portal. + * @param resourceGroupName The name of the resource group. The name is case insensitive. * @param serverName The name of the server. * @param parameters The required parameters for creating or updating a server. * @param [options] The optional parameters @@ -198,8 +187,7 @@ export class Servers { /** * Updates an existing server. The request body can contain one to many of the properties present * in the normal server definition. - * @param resourceGroupName The name of the resource group that contains the resource. You can - * obtain this value from the Azure Resource Manager API or the portal. + * @param resourceGroupName The name of the resource group. The name is case insensitive. * @param serverName The name of the server. * @param parameters The required parameters for updating a server. * @param [options] The optional parameters @@ -219,8 +207,7 @@ export class Servers { /** * Deletes a server. - * @param resourceGroupName The name of the resource group that contains the resource. You can - * obtain this value from the Azure Resource Manager API or the portal. + * @param resourceGroupName The name of the resource group. The name is case insensitive. * @param serverName The name of the server. * @param [options] The optional parameters * @returns Promise @@ -238,8 +225,7 @@ export class Servers { /** * Restarts a server. - * @param resourceGroupName The name of the resource group that contains the resource. You can - * obtain this value from the Azure Resource Manager API or the portal. + * @param resourceGroupName The name of the resource group. The name is case insensitive. * @param serverName The name of the server. * @param [options] The optional parameters * @returns Promise diff --git a/sdk/mariadb/arm-mariadb/src/operations/topQueryStatistics.ts b/sdk/mariadb/arm-mariadb/src/operations/topQueryStatistics.ts new file mode 100644 index 000000000000..905d24f3cb07 --- /dev/null +++ b/sdk/mariadb/arm-mariadb/src/operations/topQueryStatistics.ts @@ -0,0 +1,209 @@ +/* + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + * Changes may cause incorrect behavior and will be lost if the code is + * regenerated. + */ + +import * as msRest from "@azure/ms-rest-js"; +import * as Models from "../models"; +import * as Mappers from "../models/topQueryStatisticsMappers"; +import * as Parameters from "../models/parameters"; +import { MariaDBManagementClientContext } from "../mariaDBManagementClientContext"; + +/** Class representing a TopQueryStatistics. */ +export class TopQueryStatistics { + private readonly client: MariaDBManagementClientContext; + + /** + * Create a TopQueryStatistics. + * @param {MariaDBManagementClientContext} client Reference to the service client. + */ + constructor(client: MariaDBManagementClientContext) { + this.client = client; + } + + /** + * Retrieve the query statistic for specified identifier. + * @param resourceGroupName The name of the resource group. The name is case insensitive. + * @param serverName The name of the server. + * @param queryStatisticId The Query Statistic identifier. + * @param [options] The optional parameters + * @returns Promise + */ + get(resourceGroupName: string, serverName: string, queryStatisticId: string, options?: msRest.RequestOptionsBase): Promise; + /** + * @param resourceGroupName The name of the resource group. The name is case insensitive. + * @param serverName The name of the server. + * @param queryStatisticId The Query Statistic identifier. + * @param callback The callback + */ + get(resourceGroupName: string, serverName: string, queryStatisticId: string, callback: msRest.ServiceCallback): void; + /** + * @param resourceGroupName The name of the resource group. The name is case insensitive. + * @param serverName The name of the server. + * @param queryStatisticId The Query Statistic identifier. + * @param options The optional parameters + * @param callback The callback + */ + get(resourceGroupName: string, serverName: string, queryStatisticId: string, options: msRest.RequestOptionsBase, callback: msRest.ServiceCallback): void; + get(resourceGroupName: string, serverName: string, queryStatisticId: string, options?: msRest.RequestOptionsBase | msRest.ServiceCallback, callback?: msRest.ServiceCallback): Promise { + return this.client.sendOperationRequest( + { + resourceGroupName, + serverName, + queryStatisticId, + options + }, + getOperationSpec, + callback) as Promise; + } + + /** + * Retrieve the Query-Store top queries for specified metric and aggregation. + * @param resourceGroupName The name of the resource group. The name is case insensitive. + * @param serverName The name of the server. + * @param parameters The required parameters for retrieving top query statistics. + * @param [options] The optional parameters + * @returns Promise + */ + listByServer(resourceGroupName: string, serverName: string, parameters: Models.TopQueryStatisticsInput, options?: msRest.RequestOptionsBase): Promise; + /** + * @param resourceGroupName The name of the resource group. The name is case insensitive. + * @param serverName The name of the server. + * @param parameters The required parameters for retrieving top query statistics. + * @param callback The callback + */ + listByServer(resourceGroupName: string, serverName: string, parameters: Models.TopQueryStatisticsInput, callback: msRest.ServiceCallback): void; + /** + * @param resourceGroupName The name of the resource group. The name is case insensitive. + * @param serverName The name of the server. + * @param parameters The required parameters for retrieving top query statistics. + * @param options The optional parameters + * @param callback The callback + */ + listByServer(resourceGroupName: string, serverName: string, parameters: Models.TopQueryStatisticsInput, options: msRest.RequestOptionsBase, callback: msRest.ServiceCallback): void; + listByServer(resourceGroupName: string, serverName: string, parameters: Models.TopQueryStatisticsInput, options?: msRest.RequestOptionsBase | msRest.ServiceCallback, callback?: msRest.ServiceCallback): Promise { + return this.client.sendOperationRequest( + { + resourceGroupName, + serverName, + parameters, + options + }, + listByServerOperationSpec, + callback) as Promise; + } + + /** + * Retrieve the Query-Store top queries for specified metric and aggregation. + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @param [options] The optional parameters + * @returns Promise + */ + listByServerNext(nextPageLink: string, options?: msRest.RequestOptionsBase): Promise; + /** + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @param callback The callback + */ + listByServerNext(nextPageLink: string, callback: msRest.ServiceCallback): void; + /** + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @param options The optional parameters + * @param callback The callback + */ + listByServerNext(nextPageLink: string, options: msRest.RequestOptionsBase, callback: msRest.ServiceCallback): void; + listByServerNext(nextPageLink: string, options?: msRest.RequestOptionsBase | msRest.ServiceCallback, callback?: msRest.ServiceCallback): Promise { + return this.client.sendOperationRequest( + { + nextPageLink, + options + }, + listByServerNextOperationSpec, + callback) as Promise; + } +} + +// Operation Specifications +const serializer = new msRest.Serializer(Mappers); +const getOperationSpec: msRest.OperationSpec = { + httpMethod: "GET", + path: "subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.DBforMariaDB/servers/{serverName}/topQueryStatistics/{queryStatisticId}", + urlParameters: [ + Parameters.subscriptionId, + Parameters.resourceGroupName, + Parameters.serverName, + Parameters.queryStatisticId + ], + queryParameters: [ + Parameters.apiVersion + ], + headerParameters: [ + Parameters.acceptLanguage + ], + responses: { + 200: { + bodyMapper: Mappers.QueryStatistic + }, + default: { + bodyMapper: Mappers.CloudError + } + }, + serializer +}; + +const listByServerOperationSpec: msRest.OperationSpec = { + httpMethod: "GET", + path: "subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.DBforMariaDB/servers/{serverName}/topQueryStatistics", + urlParameters: [ + Parameters.subscriptionId, + Parameters.resourceGroupName, + Parameters.serverName + ], + queryParameters: [ + Parameters.apiVersion + ], + headerParameters: [ + Parameters.acceptLanguage + ], + requestBody: { + parameterPath: "parameters", + mapper: { + ...Mappers.TopQueryStatisticsInput, + required: true + } + }, + responses: { + 200: { + bodyMapper: Mappers.TopQueryStatisticsResultList + }, + default: { + bodyMapper: Mappers.CloudError + } + }, + serializer +}; + +const listByServerNextOperationSpec: msRest.OperationSpec = { + httpMethod: "GET", + baseUrl: "https://management.azure.com", + path: "{nextLink}", + urlParameters: [ + Parameters.nextPageLink + ], + headerParameters: [ + Parameters.acceptLanguage + ], + responses: { + 200: { + bodyMapper: Mappers.TopQueryStatisticsResultList + }, + default: { + bodyMapper: Mappers.CloudError + } + }, + serializer +}; diff --git a/sdk/mariadb/arm-mariadb/src/operations/virtualNetworkRules.ts b/sdk/mariadb/arm-mariadb/src/operations/virtualNetworkRules.ts index 4b7d5b9332d1..f7a121a539d7 100644 --- a/sdk/mariadb/arm-mariadb/src/operations/virtualNetworkRules.ts +++ b/sdk/mariadb/arm-mariadb/src/operations/virtualNetworkRules.ts @@ -29,8 +29,7 @@ export class VirtualNetworkRules { /** * Gets a virtual network rule. - * @param resourceGroupName The name of the resource group that contains the resource. You can - * obtain this value from the Azure Resource Manager API or the portal. + * @param resourceGroupName The name of the resource group. The name is case insensitive. * @param serverName The name of the server. * @param virtualNetworkRuleName The name of the virtual network rule. * @param [options] The optional parameters @@ -38,16 +37,14 @@ export class VirtualNetworkRules { */ get(resourceGroupName: string, serverName: string, virtualNetworkRuleName: string, options?: msRest.RequestOptionsBase): Promise; /** - * @param resourceGroupName The name of the resource group that contains the resource. You can - * obtain this value from the Azure Resource Manager API or the portal. + * @param resourceGroupName The name of the resource group. The name is case insensitive. * @param serverName The name of the server. * @param virtualNetworkRuleName The name of the virtual network rule. * @param callback The callback */ get(resourceGroupName: string, serverName: string, virtualNetworkRuleName: string, callback: msRest.ServiceCallback): void; /** - * @param resourceGroupName The name of the resource group that contains the resource. You can - * obtain this value from the Azure Resource Manager API or the portal. + * @param resourceGroupName The name of the resource group. The name is case insensitive. * @param serverName The name of the server. * @param virtualNetworkRuleName The name of the virtual network rule. * @param options The optional parameters @@ -68,8 +65,7 @@ export class VirtualNetworkRules { /** * Creates or updates an existing virtual network rule. - * @param resourceGroupName The name of the resource group that contains the resource. You can - * obtain this value from the Azure Resource Manager API or the portal. + * @param resourceGroupName The name of the resource group. The name is case insensitive. * @param serverName The name of the server. * @param virtualNetworkRuleName The name of the virtual network rule. * @param parameters The requested virtual Network Rule Resource state. @@ -83,8 +79,7 @@ export class VirtualNetworkRules { /** * Deletes the virtual network rule with the given name. - * @param resourceGroupName The name of the resource group that contains the resource. You can - * obtain this value from the Azure Resource Manager API or the portal. + * @param resourceGroupName The name of the resource group. The name is case insensitive. * @param serverName The name of the server. * @param virtualNetworkRuleName The name of the virtual network rule. * @param [options] The optional parameters @@ -97,23 +92,20 @@ export class VirtualNetworkRules { /** * Gets a list of virtual network rules in a server. - * @param resourceGroupName The name of the resource group that contains the resource. You can - * obtain this value from the Azure Resource Manager API or the portal. + * @param resourceGroupName The name of the resource group. The name is case insensitive. * @param serverName The name of the server. * @param [options] The optional parameters * @returns Promise */ listByServer(resourceGroupName: string, serverName: string, options?: msRest.RequestOptionsBase): Promise; /** - * @param resourceGroupName The name of the resource group that contains the resource. You can - * obtain this value from the Azure Resource Manager API or the portal. + * @param resourceGroupName The name of the resource group. The name is case insensitive. * @param serverName The name of the server. * @param callback The callback */ listByServer(resourceGroupName: string, serverName: string, callback: msRest.ServiceCallback): void; /** - * @param resourceGroupName The name of the resource group that contains the resource. You can - * obtain this value from the Azure Resource Manager API or the portal. + * @param resourceGroupName The name of the resource group. The name is case insensitive. * @param serverName The name of the server. * @param options The optional parameters * @param callback The callback @@ -132,8 +124,7 @@ export class VirtualNetworkRules { /** * Creates or updates an existing virtual network rule. - * @param resourceGroupName The name of the resource group that contains the resource. You can - * obtain this value from the Azure Resource Manager API or the portal. + * @param resourceGroupName The name of the resource group. The name is case insensitive. * @param serverName The name of the server. * @param virtualNetworkRuleName The name of the virtual network rule. * @param parameters The requested virtual Network Rule Resource state. @@ -155,8 +146,7 @@ export class VirtualNetworkRules { /** * Deletes the virtual network rule with the given name. - * @param resourceGroupName The name of the resource group that contains the resource. You can - * obtain this value from the Azure Resource Manager API or the portal. + * @param resourceGroupName The name of the resource group. The name is case insensitive. * @param serverName The name of the server. * @param virtualNetworkRuleName The name of the virtual network rule. * @param [options] The optional parameters diff --git a/sdk/mariadb/arm-mariadb/src/operations/waitStatistics.ts b/sdk/mariadb/arm-mariadb/src/operations/waitStatistics.ts new file mode 100644 index 000000000000..c0c30f4ae616 --- /dev/null +++ b/sdk/mariadb/arm-mariadb/src/operations/waitStatistics.ts @@ -0,0 +1,209 @@ +/* + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for + * license information. + * + * Code generated by Microsoft (R) AutoRest Code Generator. + * Changes may cause incorrect behavior and will be lost if the code is + * regenerated. + */ + +import * as msRest from "@azure/ms-rest-js"; +import * as Models from "../models"; +import * as Mappers from "../models/waitStatisticsMappers"; +import * as Parameters from "../models/parameters"; +import { MariaDBManagementClientContext } from "../mariaDBManagementClientContext"; + +/** Class representing a WaitStatistics. */ +export class WaitStatistics { + private readonly client: MariaDBManagementClientContext; + + /** + * Create a WaitStatistics. + * @param {MariaDBManagementClientContext} client Reference to the service client. + */ + constructor(client: MariaDBManagementClientContext) { + this.client = client; + } + + /** + * Retrieve wait statistics for specified identifier. + * @param resourceGroupName The name of the resource group. The name is case insensitive. + * @param serverName The name of the server. + * @param waitStatisticsId The Wait Statistic identifier. + * @param [options] The optional parameters + * @returns Promise + */ + get(resourceGroupName: string, serverName: string, waitStatisticsId: string, options?: msRest.RequestOptionsBase): Promise; + /** + * @param resourceGroupName The name of the resource group. The name is case insensitive. + * @param serverName The name of the server. + * @param waitStatisticsId The Wait Statistic identifier. + * @param callback The callback + */ + get(resourceGroupName: string, serverName: string, waitStatisticsId: string, callback: msRest.ServiceCallback): void; + /** + * @param resourceGroupName The name of the resource group. The name is case insensitive. + * @param serverName The name of the server. + * @param waitStatisticsId The Wait Statistic identifier. + * @param options The optional parameters + * @param callback The callback + */ + get(resourceGroupName: string, serverName: string, waitStatisticsId: string, options: msRest.RequestOptionsBase, callback: msRest.ServiceCallback): void; + get(resourceGroupName: string, serverName: string, waitStatisticsId: string, options?: msRest.RequestOptionsBase | msRest.ServiceCallback, callback?: msRest.ServiceCallback): Promise { + return this.client.sendOperationRequest( + { + resourceGroupName, + serverName, + waitStatisticsId, + options + }, + getOperationSpec, + callback) as Promise; + } + + /** + * Retrieve wait statistics for specified aggregation window. + * @param resourceGroupName The name of the resource group. The name is case insensitive. + * @param serverName The name of the server. + * @param parameters The required parameters for retrieving wait statistics. + * @param [options] The optional parameters + * @returns Promise + */ + listByServer(resourceGroupName: string, serverName: string, parameters: Models.WaitStatisticsInput, options?: msRest.RequestOptionsBase): Promise; + /** + * @param resourceGroupName The name of the resource group. The name is case insensitive. + * @param serverName The name of the server. + * @param parameters The required parameters for retrieving wait statistics. + * @param callback The callback + */ + listByServer(resourceGroupName: string, serverName: string, parameters: Models.WaitStatisticsInput, callback: msRest.ServiceCallback): void; + /** + * @param resourceGroupName The name of the resource group. The name is case insensitive. + * @param serverName The name of the server. + * @param parameters The required parameters for retrieving wait statistics. + * @param options The optional parameters + * @param callback The callback + */ + listByServer(resourceGroupName: string, serverName: string, parameters: Models.WaitStatisticsInput, options: msRest.RequestOptionsBase, callback: msRest.ServiceCallback): void; + listByServer(resourceGroupName: string, serverName: string, parameters: Models.WaitStatisticsInput, options?: msRest.RequestOptionsBase | msRest.ServiceCallback, callback?: msRest.ServiceCallback): Promise { + return this.client.sendOperationRequest( + { + resourceGroupName, + serverName, + parameters, + options + }, + listByServerOperationSpec, + callback) as Promise; + } + + /** + * Retrieve wait statistics for specified aggregation window. + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @param [options] The optional parameters + * @returns Promise + */ + listByServerNext(nextPageLink: string, options?: msRest.RequestOptionsBase): Promise; + /** + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @param callback The callback + */ + listByServerNext(nextPageLink: string, callback: msRest.ServiceCallback): void; + /** + * @param nextPageLink The NextLink from the previous successful call to List operation. + * @param options The optional parameters + * @param callback The callback + */ + listByServerNext(nextPageLink: string, options: msRest.RequestOptionsBase, callback: msRest.ServiceCallback): void; + listByServerNext(nextPageLink: string, options?: msRest.RequestOptionsBase | msRest.ServiceCallback, callback?: msRest.ServiceCallback): Promise { + return this.client.sendOperationRequest( + { + nextPageLink, + options + }, + listByServerNextOperationSpec, + callback) as Promise; + } +} + +// Operation Specifications +const serializer = new msRest.Serializer(Mappers); +const getOperationSpec: msRest.OperationSpec = { + httpMethod: "GET", + path: "subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.DBforMariaDB/servers/{serverName}/waitStatistics/{waitStatisticsId}", + urlParameters: [ + Parameters.subscriptionId, + Parameters.resourceGroupName, + Parameters.serverName, + Parameters.waitStatisticsId + ], + queryParameters: [ + Parameters.apiVersion + ], + headerParameters: [ + Parameters.acceptLanguage + ], + responses: { + 200: { + bodyMapper: Mappers.WaitStatistic + }, + default: { + bodyMapper: Mappers.CloudError + } + }, + serializer +}; + +const listByServerOperationSpec: msRest.OperationSpec = { + httpMethod: "GET", + path: "subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.DBforMariaDB/servers/{serverName}/waitStatistics", + urlParameters: [ + Parameters.subscriptionId, + Parameters.resourceGroupName, + Parameters.serverName + ], + queryParameters: [ + Parameters.apiVersion + ], + headerParameters: [ + Parameters.acceptLanguage + ], + requestBody: { + parameterPath: "parameters", + mapper: { + ...Mappers.WaitStatisticsInput, + required: true + } + }, + responses: { + 200: { + bodyMapper: Mappers.WaitStatisticsResultList + }, + default: { + bodyMapper: Mappers.CloudError + } + }, + serializer +}; + +const listByServerNextOperationSpec: msRest.OperationSpec = { + httpMethod: "GET", + baseUrl: "https://management.azure.com", + path: "{nextLink}", + urlParameters: [ + Parameters.nextPageLink + ], + headerParameters: [ + Parameters.acceptLanguage + ], + responses: { + 200: { + bodyMapper: Mappers.WaitStatisticsResultList + }, + default: { + bodyMapper: Mappers.CloudError + } + }, + serializer +}; diff --git a/sdk/mariadb/arm-mariadb/tsconfig.json b/sdk/mariadb/arm-mariadb/tsconfig.json index 87bbf5b5fa49..422b584abd5e 100644 --- a/sdk/mariadb/arm-mariadb/tsconfig.json +++ b/sdk/mariadb/arm-mariadb/tsconfig.json @@ -9,7 +9,7 @@ "esModuleInterop": true, "allowSyntheticDefaultImports": true, "forceConsistentCasingInFileNames": true, - "lib": ["es6"], + "lib": ["es6", "dom"], "declaration": true, "outDir": "./esm", "importHelpers": true diff --git a/sdk/netapp/arm-netapp/package.json b/sdk/netapp/arm-netapp/package.json index 08cd0b459a1a..6f087b7164ab 100644 --- a/sdk/netapp/arm-netapp/package.json +++ b/sdk/netapp/arm-netapp/package.json @@ -2,7 +2,7 @@ "name": "@azure/arm-netapp", "author": "Microsoft Corporation", "description": "AzureNetAppFilesManagementClient Library with typescript type definitions for node.js and browser.", - "version": "9.0.0", + "version": "10.0.0", "dependencies": { "@azure/ms-rest-azure-js": "^2.0.1", "@azure/ms-rest-js": "^2.0.4", diff --git a/sdk/netapp/arm-netapp/src/azureNetAppFilesManagementClientContext.ts b/sdk/netapp/arm-netapp/src/azureNetAppFilesManagementClientContext.ts index 7e5c6a4a8de2..142635725ac4 100644 --- a/sdk/netapp/arm-netapp/src/azureNetAppFilesManagementClientContext.ts +++ b/sdk/netapp/arm-netapp/src/azureNetAppFilesManagementClientContext.ts @@ -13,7 +13,7 @@ import * as msRest from "@azure/ms-rest-js"; import * as msRestAzure from "@azure/ms-rest-azure-js"; const packageName = "@azure/arm-netapp"; -const packageVersion = "9.0.0"; +const packageVersion = "10.0.0"; export class AzureNetAppFilesManagementClientContext extends msRestAzure.AzureServiceClient { credentials: msRest.ServiceClientCredentials; @@ -38,7 +38,7 @@ export class AzureNetAppFilesManagementClientContext extends msRestAzure.AzureSe if (!options) { options = {}; } - if(!options.userAgent) { + if (!options.userAgent) { const defaultUserAgent = msRestAzure.getDefaultUserAgentValue(); options.userAgent = `${packageName}/${packageVersion} ${defaultUserAgent}`; } @@ -53,10 +53,10 @@ export class AzureNetAppFilesManagementClientContext extends msRestAzure.AzureSe this.credentials = credentials; this.subscriptionId = subscriptionId; - if(options.acceptLanguage !== null && options.acceptLanguage !== undefined) { + if (options.acceptLanguage !== null && options.acceptLanguage !== undefined) { this.acceptLanguage = options.acceptLanguage; } - if(options.longRunningOperationRetryTimeout !== null && options.longRunningOperationRetryTimeout !== undefined) { + if (options.longRunningOperationRetryTimeout !== null && options.longRunningOperationRetryTimeout !== undefined) { this.longRunningOperationRetryTimeout = options.longRunningOperationRetryTimeout; } } diff --git a/sdk/netapp/arm-netapp/src/models/accountsMappers.ts b/sdk/netapp/arm-netapp/src/models/accountsMappers.ts index 996b978b7718..587c55d2eedb 100644 --- a/sdk/netapp/arm-netapp/src/models/accountsMappers.ts +++ b/sdk/netapp/arm-netapp/src/models/accountsMappers.ts @@ -13,7 +13,7 @@ export { CapacityPoolPatch, CloudError, ExportPolicyRule, - MountTarget, + MountTargetProperties, NetAppAccount, NetAppAccountList, NetAppAccountPatch, diff --git a/sdk/netapp/arm-netapp/src/models/index.ts b/sdk/netapp/arm-netapp/src/models/index.ts index c73843ade621..4dff80d9ae66 100644 --- a/sdk/netapp/arm-netapp/src/models/index.ts +++ b/sdk/netapp/arm-netapp/src/models/index.ts @@ -420,32 +420,9 @@ export interface VolumePropertiesExportPolicy { } /** - * Mount Target + * Mount target properties */ -export interface MountTarget { - /** - * Resource location - */ - location: string; - /** - * Resource Id - * **NOTE: This property will not be serialized. It can only be populated by the server.** - */ - readonly id?: string; - /** - * Resource name - * **NOTE: This property will not be serialized. It can only be populated by the server.** - */ - readonly name?: string; - /** - * Resource type - * **NOTE: This property will not be serialized. It can only be populated by the server.** - */ - readonly type?: string; - /** - * Resource tags - */ - tags?: { [propertyName: string]: string }; +export interface MountTargetProperties { /** * mountTargetId. UUID v4 used to identify the MountTarget * **NOTE: This property will not be serialized. It can only be populated by the server.** @@ -602,7 +579,7 @@ export interface Volume extends BaseResource { /** * mountTargets. List of mount targets */ - mountTargets?: MountTarget[]; + mountTargets?: MountTargetProperties[]; /** * What type of volume is this */ @@ -699,6 +676,73 @@ export interface VolumePatch extends BaseResource { exportPolicy?: VolumePatchPropertiesExportPolicy; } +/** + * Mount Target + */ +export interface MountTarget { + /** + * Resource location + */ + location: string; + /** + * Resource Id + * **NOTE: This property will not be serialized. It can only be populated by the server.** + */ + readonly id?: string; + /** + * Resource name + * **NOTE: This property will not be serialized. It can only be populated by the server.** + */ + readonly name?: string; + /** + * Resource type + * **NOTE: This property will not be serialized. It can only be populated by the server.** + */ + readonly type?: string; + /** + * Resource tags + */ + tags?: { [propertyName: string]: string }; + /** + * mountTargetId. UUID v4 used to identify the MountTarget + * **NOTE: This property will not be serialized. It can only be populated by the server.** + */ + readonly mountTargetId?: string; + /** + * fileSystemId. UUID v4 used to identify the MountTarget + */ + fileSystemId: string; + /** + * ipAddress. The mount target's IPv4 address + * **NOTE: This property will not be serialized. It can only be populated by the server.** + */ + readonly ipAddress?: string; + /** + * subnet. The subnet + */ + subnet?: string; + /** + * startIp. The start of IPv4 address range to use when creating a new mount target + */ + startIp?: string; + /** + * endIp. The end of IPv4 address range to use when creating a new mount target + */ + endIp?: string; + /** + * gateway. The gateway of the IPv4 address range to use when creating a new mount target + */ + gateway?: string; + /** + * netmask. The netmask of the IPv4 address range to use when creating a new mount target + */ + netmask?: string; + /** + * smbServerFQDN. The SMB server's Fully Qualified Domain Name, FQDN + */ + smbServerFqdn?: string; +} + /** * Snapshot of a Volume */ diff --git a/sdk/netapp/arm-netapp/src/models/mappers.ts b/sdk/netapp/arm-netapp/src/models/mappers.ts index 8136b93ee618..34bd742b40db 100644 --- a/sdk/netapp/arm-netapp/src/models/mappers.ts +++ b/sdk/netapp/arm-netapp/src/models/mappers.ts @@ -681,54 +681,15 @@ export const VolumePropertiesExportPolicy: msRest.CompositeMapper = { } }; -export const MountTarget: msRest.CompositeMapper = { - serializedName: "mountTarget", +export const MountTargetProperties: msRest.CompositeMapper = { + serializedName: "mountTargetProperties", type: { name: "Composite", - className: "MountTarget", + className: "MountTargetProperties", modelProperties: { - location: { - required: true, - serializedName: "location", - type: { - name: "String" - } - }, - id: { - readOnly: true, - serializedName: "id", - type: { - name: "String" - } - }, - name: { - readOnly: true, - serializedName: "name", - type: { - name: "String" - } - }, - type: { - readOnly: true, - serializedName: "type", - type: { - name: "String" - } - }, - tags: { - serializedName: "tags", - type: { - name: "Dictionary", - value: { - type: { - name: "String" - } - } - } - }, mountTargetId: { readOnly: true, - serializedName: "properties.mountTargetId", + serializedName: "mountTargetId", constraints: { MaxLength: 36, MinLength: 36, @@ -740,7 +701,7 @@ export const MountTarget: msRest.CompositeMapper = { }, fileSystemId: { required: true, - serializedName: "properties.fileSystemId", + serializedName: "fileSystemId", constraints: { MaxLength: 36, MinLength: 36, @@ -752,43 +713,43 @@ export const MountTarget: msRest.CompositeMapper = { }, ipAddress: { readOnly: true, - serializedName: "properties.ipAddress", + serializedName: "ipAddress", type: { name: "String" } }, subnet: { - serializedName: "properties.subnet", + serializedName: "subnet", type: { name: "String" } }, startIp: { - serializedName: "properties.startIp", + serializedName: "startIp", type: { name: "String" } }, endIp: { - serializedName: "properties.endIp", + serializedName: "endIp", type: { name: "String" } }, gateway: { - serializedName: "properties.gateway", + serializedName: "gateway", type: { name: "String" } }, netmask: { - serializedName: "properties.netmask", + serializedName: "netmask", type: { name: "String" } }, smbServerFqdn: { - serializedName: "properties.smbServerFqdn", + serializedName: "smbServerFqdn", type: { name: "String" } @@ -1006,7 +967,7 @@ export const Volume: msRest.CompositeMapper = { element: { type: { name: "Composite", - className: "MountTarget" + className: "MountTargetProperties" } } } @@ -1169,6 +1130,122 @@ export const VolumePatch: msRest.CompositeMapper = { } }; +export const MountTarget: msRest.CompositeMapper = { + serializedName: "mountTarget", + type: { + name: "Composite", + className: "MountTarget", + modelProperties: { + location: { + required: true, + serializedName: "location", + type: { + name: "String" + } + }, + id: { + readOnly: true, + serializedName: "id", + type: { + name: "String" + } + }, + name: { + readOnly: true, + serializedName: "name", + type: { + name: "String" + } + }, + type: { + readOnly: true, + serializedName: "type", + type: { + name: "String" + } + }, + tags: { + serializedName: "tags", + type: { + name: "Dictionary", + value: { + type: { + name: "String" + } + } + } + }, + mountTargetId: { + readOnly: true, + serializedName: "properties.mountTargetId", + constraints: { + MaxLength: 36, + MinLength: 36, + Pattern: /^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$/ + }, + type: { + name: "String" + } + }, + fileSystemId: { + required: true, + serializedName: "properties.fileSystemId", + constraints: { + MaxLength: 36, + MinLength: 36, + Pattern: /^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$/ + }, + type: { + name: "String" + } + }, + ipAddress: { + readOnly: true, + serializedName: "properties.ipAddress", + type: { + name: "String" + } + }, + subnet: { + serializedName: "properties.subnet", + type: { + name: "String" + } + }, + startIp: { + serializedName: "properties.startIp", + type: { + name: "String" + } + }, + endIp: { + serializedName: "properties.endIp", + type: { + name: "String" + } + }, + gateway: { + serializedName: "properties.gateway", + type: { + name: "String" + } + }, + netmask: { + serializedName: "properties.netmask", + type: { + name: "String" + } + }, + smbServerFqdn: { + serializedName: "properties.smbServerFqdn", + type: { + name: "String" + } + } + } + } +}; + export const Snapshot: msRest.CompositeMapper = { serializedName: "snapshot", type: { diff --git a/sdk/netapp/arm-netapp/src/models/poolsMappers.ts b/sdk/netapp/arm-netapp/src/models/poolsMappers.ts index a2ce76177536..e50bdf260d22 100644 --- a/sdk/netapp/arm-netapp/src/models/poolsMappers.ts +++ b/sdk/netapp/arm-netapp/src/models/poolsMappers.ts @@ -14,7 +14,7 @@ export { CapacityPoolPatch, CloudError, ExportPolicyRule, - MountTarget, + MountTargetProperties, NetAppAccount, NetAppAccountPatch, ReplicationObject, diff --git a/sdk/netapp/arm-netapp/src/models/snapshotsMappers.ts b/sdk/netapp/arm-netapp/src/models/snapshotsMappers.ts index 80554b0453b2..db83bb018f12 100644 --- a/sdk/netapp/arm-netapp/src/models/snapshotsMappers.ts +++ b/sdk/netapp/arm-netapp/src/models/snapshotsMappers.ts @@ -13,7 +13,7 @@ export { CapacityPoolPatch, CloudError, ExportPolicyRule, - MountTarget, + MountTargetProperties, NetAppAccount, NetAppAccountPatch, ReplicationObject, diff --git a/sdk/netapp/arm-netapp/src/models/volumesMappers.ts b/sdk/netapp/arm-netapp/src/models/volumesMappers.ts index 44dfbc8331f8..e3ca24d90b89 100644 --- a/sdk/netapp/arm-netapp/src/models/volumesMappers.ts +++ b/sdk/netapp/arm-netapp/src/models/volumesMappers.ts @@ -14,7 +14,7 @@ export { CapacityPoolPatch, CloudError, ExportPolicyRule, - MountTarget, + MountTargetProperties, NetAppAccount, NetAppAccountPatch, ReplicationObject, diff --git a/sdk/search/search-documents/package.json b/sdk/search/search-documents/package.json index fdbec1905f12..4d262e6136e2 100644 --- a/sdk/search/search-documents/package.json +++ b/sdk/search/search-documents/package.json @@ -10,14 +10,12 @@ "audit": "node ../../../common/scripts/rush-audit.js && rimraf node_modules package-lock.json && npm i --package-lock-only 2>&1 && npm audit", "build:browser": "tsc -p . && cross-env ONLY_BROWSER=true rollup -c 2>&1", "build:node": "tsc -p . && cross-env ONLY_NODE=true rollup -c 2>&1", - "build:samples": "node ../../../common/scripts/prep-samples.js && cd samples && tsc -p .", + "build:samples": "dev-tool samples prep && cd dist-samples && tsc -p .", "build:test": "tsc -p . && rollup -c rollup.test.config.js 2>&1", "build": "tsc -p . && rollup -c 2>&1 && api-extractor run --local", "check-format": "prettier --list-different --config ../../.prettierrc.json --ignore-path ../../.prettierignore \"src/**/*.ts\" \"test/**/*.ts\" \"*.{js,json}\"", "clean": "rimraf dist dist-esm test-dist temp types *.tgz *.log", - "execute:js-samples": "node ../../../common/scripts/run-samples.js samples/javascript/", - "execute:ts-samples": "node ../../../common/scripts/run-samples.js samples/typescript/dist/samples/typescript/src/", - "execute:samples": "npm run build:samples && npm run execute:js-samples && npm run execute:ts-samples", + "execute:samples": "npm run build:samples && dev-tool samples run dist-samples/javascript dist-samples/typescript/dist/dist-samples/typescript/src/", "extract-api": "tsc -p . && api-extractor run --local", "format": "prettier --write --config ../../.prettierrc.json --ignore-path ../../.prettierignore \"src/**/*.ts\" \"test/**/*.ts\" \"*.{js,json}\"", "integration-test:browser": "karma start --single-run", @@ -85,6 +83,7 @@ "tslib": "^2.0.0" }, "devDependencies": { + "@azure/dev-tool": "^1.0.0", "@azure/eslint-plugin-azure-sdk": "^3.0.0", "@azure/test-utils-recorder": "^1.0.0", "@microsoft/api-extractor": "7.7.11", diff --git a/sdk/search/search-documents/test/node/searchIndexClient.spec.ts b/sdk/search/search-documents/test/node/searchIndexClient.spec.ts index bd912f448546..1876433f719a 100644 --- a/sdk/search/search-documents/test/node/searchIndexClient.spec.ts +++ b/sdk/search/search-documents/test/node/searchIndexClient.spec.ts @@ -34,7 +34,7 @@ describe("SearchClient", function() { afterEach(async function() { if (recorder) { - recorder.stop(); + await recorder.stop(); } if (!isPlaybackMode()) { await indexClient.deleteIndex(TEST_INDEX_NAME); diff --git a/sdk/servicebus/service-bus/package.json b/sdk/servicebus/service-bus/package.json index f985355461d5..dec10f3dc537 100644 --- a/sdk/servicebus/service-bus/package.json +++ b/sdk/servicebus/service-bus/package.json @@ -48,7 +48,7 @@ "audit": "node ../../../common/scripts/rush-audit.js && rimraf node_modules package-lock.json && npm i --package-lock-only 2>&1 && npm audit", "build:browser": "tsc -p . && cross-env ONLY_BROWSER=true rollup -c 2>&1", "build:node": "tsc -p . && cross-env ONLY_NODE=true rollup -c 2>&1", - "build:samples": "node ../../../common/scripts/prep-samples.js && cd samples && tsc -p .", + "build:samples": "dev-tool samples prep && cd dist-samples && tsc -p .", "build:test:browser": "tsc -p . && cross-env ONLY_BROWSER=true rollup -c rollup.test.config.js 2>&1", "build:test:node": "tsc -p . && cross-env ONLY_NODE=true rollup -c rollup.test.config.js 2>&1", "build:test": "npm run build:test:node && npm run build:test:browser", @@ -102,6 +102,7 @@ "rhea-promise": "^1.0.0" }, "devDependencies": { + "@azure/dev-tool": "^1.0.0", "@azure/eslint-plugin-azure-sdk": "^3.0.0", "@azure/identity": "^1.1.0-preview", "@microsoft/api-extractor": "7.7.11", diff --git a/sdk/servicebus/service-bus/samples-v1/javascript/receiveMessagesStreaming.js b/sdk/servicebus/service-bus/samples-v1/javascript/receiveMessagesStreaming.js index 842623c110b0..de53757968f1 100644 --- a/sdk/servicebus/service-bus/samples-v1/javascript/receiveMessagesStreaming.js +++ b/sdk/servicebus/service-bus/samples-v1/javascript/receiveMessagesStreaming.js @@ -1,17 +1,18 @@ /* -Copyright (c) Microsoft Corporation. All rights reserved. -Licensed under the MIT Licence. + Copyright (c) Microsoft Corporation. All rights reserved. + Licensed under the MIT Licence. -This sample demonstrates how the receive() function can be used to receive Service Bus messages -in a stream. + This sample demonstrates how the registerMessageHandler() function can be used to receive Service Bus messages + in a stream. -Setup: Please run "sendMessages.ts" sample before running this to populate the queue/topic + Setup: Please run "sendMessages.ts" sample before running this to populate the queue/topic */ -const { delay, ServiceBusClient, ReceiveMode } = require("@azure/service-bus"); +const { ServiceBusClient, ReceiveMode } = require("@azure/service-bus"); // Load the .env file if it exists -require("dotenv").config(); +const dotenv = require("dotenv"); +dotenv.config(); // Define connection string and related Service Bus entity names here const connectionString = process.env.SERVICE_BUS_CONNECTION_STRING || ""; @@ -23,31 +24,47 @@ async function main() { // If receiving from a Subscription, use `createSubscriptionClient` instead of `createQueueClient` const queueClient = sbClient.createQueueClient(queueName); - // To receive messages from sessions, use getSessionReceiver instead of getReceiver or look at + // To receive messages from sessions, use createSessionReceiver instead of createReceiver or look at // the sample in sessions.ts file - const receiver = queueClient.createReceiver(ReceiveMode.peekLock); - - const onMessageHandler = async (brokeredMessage) => { - console.log(`Received message: ${brokeredMessage.body}`); - await brokeredMessage.complete(); - }; - const onErrorHandler = (err) => { - console.log("Error occurred: ", err); - }; - - try { - receiver.registerMessageHandler(onMessageHandler, onErrorHandler, { - autoComplete: false + + // controls whether we continue to recover from fatal Receiver failures. + let enableReceiverRecovery = true; + + do { + const receiver = queueClient.createReceiver(ReceiveMode.peekLock); + + const receiverPromise = new Promise((resolve, _reject) => { + const onMessageHandler = async (brokeredMessage) => { + console.log(`Received message: ${brokeredMessage.body}`); + await brokeredMessage.complete(); + }; + + const onErrorHandler = (err) => { + if (err.retryable === true) { + console.log("Receiver will be recreated. A recoverable error occurred:", err); + resolve(); + } else { + console.log("Error occurred: ", err); + } + }; + + receiver.registerMessageHandler(onMessageHandler, onErrorHandler, { autoComplete: false }); }); - // Waiting long enough before closing the receiver to receive messages - await delay(5000); + // This will only resolve if our receiver has failed in a way that is not recoverable. + await receiverPromise; + + // the Service Bus package is intended to be resilient in the face of transitive issues, like network + // interruptions. If there are continual restarts this might indicate a more serious issue, like a network + // outage. + console.log(`Closing previous receiver and recreating - a fatal error has occurred.`); + // we can close the old receiver and just let the loop start again. await receiver.close(); - await queueClient.close(); - } finally { - await sbClient.close(); - } + } while (enableReceiverRecovery); + + await queueClient.close(); + await sbClient.close(); } main().catch((err) => { diff --git a/sdk/servicebus/service-bus/samples-v1/typescript/src/receiveMessagesStreaming.ts b/sdk/servicebus/service-bus/samples-v1/typescript/src/receiveMessagesStreaming.ts index 878c5d1a5c01..05b9d3ee4160 100644 --- a/sdk/servicebus/service-bus/samples-v1/typescript/src/receiveMessagesStreaming.ts +++ b/sdk/servicebus/service-bus/samples-v1/typescript/src/receiveMessagesStreaming.ts @@ -2,13 +2,19 @@ Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT Licence. - This sample demonstrates how the receive() function can be used to receive Service Bus messages + This sample demonstrates how the registerMessageHandler() function can be used to receive Service Bus messages in a stream. Setup: Please run "sendMessages.ts" sample before running this to populate the queue/topic */ -import { OnMessage, OnError, delay, ServiceBusClient, ReceiveMode } from "@azure/service-bus"; +import { + OnMessage, + OnError, + ServiceBusClient, + ReceiveMode, + MessagingError +} from "@azure/service-bus"; // Load the .env file if it exists import * as dotenv from "dotenv"; @@ -24,29 +30,47 @@ export async function main() { // If receiving from a Subscription, use `createSubscriptionClient` instead of `createQueueClient` const queueClient = sbClient.createQueueClient(queueName); - // To receive messages from sessions, use getSessionReceiver instead of getReceiver or look at + // To receive messages from sessions, use createSessionReceiver instead of createReceiver or look at // the sample in sessions.ts file - const receiver = queueClient.createReceiver(ReceiveMode.peekLock); - const onMessageHandler: OnMessage = async (brokeredMessage) => { - console.log(`Received message: ${brokeredMessage.body}`); - await brokeredMessage.complete(); - }; - const onErrorHandler: OnError = (err) => { - console.log("Error occurred: ", err); - }; + // controls whether we continue to recover from fatal Receiver failures. + let enableReceiverRecovery = true; - try { - receiver.registerMessageHandler(onMessageHandler, onErrorHandler, { autoComplete: false }); + do { + const receiver = queueClient.createReceiver(ReceiveMode.peekLock); - // Waiting long enough before closing the receiver to receive messages - await delay(5000); + const receiverPromise = new Promise((resolve, _reject) => { + const onMessageHandler: OnMessage = async (brokeredMessage) => { + console.log(`Received message: ${brokeredMessage.body}`); + await brokeredMessage.complete(); + }; + const onErrorHandler: OnError = (err) => { + if ((err as MessagingError).retryable === true) { + console.log("Receiver will be recreated. A recoverable error occurred:", err); + resolve(); + } else { + console.log("Error occurred: ", err); + } + }; + + receiver.registerMessageHandler(onMessageHandler, onErrorHandler, { autoComplete: false }); + }); + + // This will only resolve if our receiver has failed in a way that is not recoverable. + await receiverPromise; + + // the Service Bus package is intended to be resilient in the face of transitive issues, like network + // interruptions. If there are continual restarts this might indicate a more serious issue, like a network + // outage. + console.log(`Closing previous receiver and recreating - a fatal error has occurred.`); + + // we can close the old receiver and just let the loop start again. await receiver.close(); - await queueClient.close(); - } finally { - await sbClient.close(); - } + } while (enableReceiverRecovery); + + await queueClient.close(); + await sbClient.close(); } main().catch((err) => { diff --git a/sdk/servicebus/service-bus/samples/javascript/README.md b/sdk/servicebus/service-bus/samples/javascript/README.md index 6cdb39a656f0..62677dd2113f 100644 --- a/sdk/servicebus/service-bus/samples/javascript/README.md +++ b/sdk/servicebus/service-bus/samples/javascript/README.md @@ -1,6 +1,6 @@ # Azure Service Bus client library samples for JavaScript -**NOTE**: Samples for @azure/service-bus v1.1.x are still available [here](https://github.com/Azure/azure-sdk-for-js/tree/%40azure/service-bus_1.1.5/sdk/servicebus/service-bus/samples) +**NOTE**: Samples for @azure/service-bus v1.1.x are still available [here](https://github.com/Azure/azure-sdk-for-js/blob/master/sdk/servicebus/service-bus/samples-v1) These sample programs show how to use the JavaScript client libraries for Azure Service Bus in some common scenarios. diff --git a/sdk/servicebus/service-bus/samples/javascript/advanced/deferral.js b/sdk/servicebus/service-bus/samples/javascript/advanced/deferral.js index 41a08215c001..0975621b54be 100644 --- a/sdk/servicebus/service-bus/samples/javascript/advanced/deferral.js +++ b/sdk/servicebus/service-bus/samples/javascript/advanced/deferral.js @@ -3,7 +3,7 @@ Licensed under the MIT Licence. **NOTE**: If you are using version 1.1.x or lower, then please use the link below: - https://github.com/Azure/azure-sdk-for-js/tree/%40azure/service-bus_1.1.5/sdk/servicebus/service-bus/samples + https://github.com/Azure/azure-sdk-for-js/blob/master/sdk/servicebus/service-bus/samples-v1 This sample demonstrates how the defer() function can be used to defer a message for later processing. diff --git a/sdk/servicebus/service-bus/samples/javascript/advanced/managementClient.js b/sdk/servicebus/service-bus/samples/javascript/advanced/managementClient.js index 8b1aaa771e05..e1d35a7e538a 100644 --- a/sdk/servicebus/service-bus/samples/javascript/advanced/managementClient.js +++ b/sdk/servicebus/service-bus/samples/javascript/advanced/managementClient.js @@ -4,7 +4,7 @@ **NOTE**: This sample uses the preview of the next version of the @azure/service-bus package. For samples using the current stable version of the package, please use the link below: - https://github.com/Azure/azure-sdk-for-js/tree/%40azure/service-bus_1.1.5/sdk/servicebus/service-bus/samples + https://github.com/Azure/azure-sdk-for-js/blob/master/sdk/servicebus/service-bus/samples-v1 This sample demonstrates how the ServiceBusManagementClient can be used to manage the resources of a service bus namespace. diff --git a/sdk/servicebus/service-bus/samples/javascript/advanced/movingMessagesToDLQ.js b/sdk/servicebus/service-bus/samples/javascript/advanced/movingMessagesToDLQ.js index cba6eff47262..2807adb37958 100644 --- a/sdk/servicebus/service-bus/samples/javascript/advanced/movingMessagesToDLQ.js +++ b/sdk/servicebus/service-bus/samples/javascript/advanced/movingMessagesToDLQ.js @@ -3,7 +3,7 @@ Licensed under the MIT Licence. **NOTE**: If you are using version 1.1.x or lower, then please use the link below: - https://github.com/Azure/azure-sdk-for-js/tree/%40azure/service-bus_1.1.5/sdk/servicebus/service-bus/samples + https://github.com/Azure/azure-sdk-for-js/blob/master/sdk/servicebus/service-bus/samples-v1 This sample demonstrates scenarios as to how a Service Bus message can be explicitly moved to the DLQ. For other implicit ways when Service Bus messages get moved to DLQ, refer to - diff --git a/sdk/servicebus/service-bus/samples/javascript/advanced/processMessageFromDLQ.js b/sdk/servicebus/service-bus/samples/javascript/advanced/processMessageFromDLQ.js index b4854765d5be..862135d4f8d5 100644 --- a/sdk/servicebus/service-bus/samples/javascript/advanced/processMessageFromDLQ.js +++ b/sdk/servicebus/service-bus/samples/javascript/advanced/processMessageFromDLQ.js @@ -3,7 +3,7 @@ Licensed under the MIT Licence. **NOTE**: If you are using version 1.1.x or lower, then please use the link below: - https://github.com/Azure/azure-sdk-for-js/tree/%40azure/service-bus_1.1.5/sdk/servicebus/service-bus/samples + https://github.com/Azure/azure-sdk-for-js/blob/master/sdk/servicebus/service-bus/samples-v1 This sample demonstrates retrieving a message from a dead letter queue, editing it and sending it back to the main queue. diff --git a/sdk/servicebus/service-bus/samples/javascript/advanced/sessionState.js b/sdk/servicebus/service-bus/samples/javascript/advanced/sessionState.js index 4312236fced7..8c8fe76be54e 100644 --- a/sdk/servicebus/service-bus/samples/javascript/advanced/sessionState.js +++ b/sdk/servicebus/service-bus/samples/javascript/advanced/sessionState.js @@ -3,7 +3,7 @@ Licensed under the MIT Licence. **NOTE**: If you are using version 1.1.x or lower, then please use the link below: - https://github.com/Azure/azure-sdk-for-js/tree/%40azure/service-bus_1.1.5/sdk/servicebus/service-bus/samples + https://github.com/Azure/azure-sdk-for-js/blob/master/sdk/servicebus/service-bus/samples-v1 This sample demonstrates usage of SessionState. @@ -124,7 +124,9 @@ async function processMessageFromSession(sessionId) { } console.log( - `Received message: Customer '${sessionReceiver.sessionId}': '${messages[0].body.event_name} ${messages[0].body.event_details}'` + `Received message: Customer '${sessionReceiver.sessionId}': '${messages[0].body.event_name} ${ + messages[0].body.event_details + }'` ); await messages[0].complete(); } else { diff --git a/sdk/servicebus/service-bus/samples/javascript/browseMessages.js b/sdk/servicebus/service-bus/samples/javascript/browseMessages.js index 48139b519c92..5376f61e54e9 100644 --- a/sdk/servicebus/service-bus/samples/javascript/browseMessages.js +++ b/sdk/servicebus/service-bus/samples/javascript/browseMessages.js @@ -3,7 +3,7 @@ Licensed under the MIT Licence. **NOTE**: If you are using version 1.1.x or lower, then please use the link below: - https://github.com/Azure/azure-sdk-for-js/tree/%40azure/service-bus_1.1.5/sdk/servicebus/service-bus/samples + https://github.com/Azure/azure-sdk-for-js/blob/master/sdk/servicebus/service-bus/samples-v1 This sample demonstrates how the peekMessages() function can be used to browse a Service Bus message. diff --git a/sdk/servicebus/service-bus/samples/javascript/receiveMessagesLoop.js b/sdk/servicebus/service-bus/samples/javascript/receiveMessagesLoop.js index e6b2b53ebf93..bc2247cd2625 100644 --- a/sdk/servicebus/service-bus/samples/javascript/receiveMessagesLoop.js +++ b/sdk/servicebus/service-bus/samples/javascript/receiveMessagesLoop.js @@ -3,7 +3,7 @@ Licensed under the MIT Licence. **NOTE**: If you are using version 1.1.x or lower, then please use the link below: - https://github.com/Azure/azure-sdk-for-js/tree/%40azure/service-bus_1.1.5/sdk/servicebus/service-bus/samples + https://github.com/Azure/azure-sdk-for-js/blob/master/sdk/servicebus/service-bus/samples-v1 This sample demonstrates how the receiveMessages() function can be used to receive Service Bus messages in a loop. diff --git a/sdk/servicebus/service-bus/samples/javascript/receiveMessagesStreaming.js b/sdk/servicebus/service-bus/samples/javascript/receiveMessagesStreaming.js index febe38825d87..8e194227ce4a 100644 --- a/sdk/servicebus/service-bus/samples/javascript/receiveMessagesStreaming.js +++ b/sdk/servicebus/service-bus/samples/javascript/receiveMessagesStreaming.js @@ -3,7 +3,7 @@ Licensed under the MIT Licence. **NOTE**: If you are using version 1.1.x or lower, then please use the link below: - https://github.com/Azure/azure-sdk-for-js/tree/%40azure/service-bus_1.1.5/sdk/servicebus/service-bus/samples + https://github.com/Azure/azure-sdk-for-js/blob/master/sdk/servicebus/service-bus/samples-v1 This sample demonstrates how the receive() function can be used to receive Service Bus messages in a stream. diff --git a/sdk/servicebus/service-bus/samples/javascript/scheduledMessages.js b/sdk/servicebus/service-bus/samples/javascript/scheduledMessages.js index f95ac1908cf8..984ed635bb3d 100644 --- a/sdk/servicebus/service-bus/samples/javascript/scheduledMessages.js +++ b/sdk/servicebus/service-bus/samples/javascript/scheduledMessages.js @@ -3,7 +3,7 @@ Licensed under the MIT Licence. **NOTE**: If you are using version 1.1.x or lower, then please use the link below: - https://github.com/Azure/azure-sdk-for-js/tree/%40azure/service-bus_1.1.5/sdk/servicebus/service-bus/samples + https://github.com/Azure/azure-sdk-for-js/blob/master/sdk/servicebus/service-bus/samples-v1 This sample demonstrates how the scheduleMessage() function can be used to schedule messages to appear on a Service Bus Queue/Subscription at a later time. diff --git a/sdk/servicebus/service-bus/samples/javascript/sendMessages.js b/sdk/servicebus/service-bus/samples/javascript/sendMessages.js index 8f60978298da..5d7d4a4a6497 100644 --- a/sdk/servicebus/service-bus/samples/javascript/sendMessages.js +++ b/sdk/servicebus/service-bus/samples/javascript/sendMessages.js @@ -3,7 +3,7 @@ Licensed under the MIT Licence. **NOTE**: If you are using version 1.1.x or lower, then please use the link below: - https://github.com/Azure/azure-sdk-for-js/tree/%40azure/service-bus_1.1.5/sdk/servicebus/service-bus/samples + https://github.com/Azure/azure-sdk-for-js/blob/master/sdk/servicebus/service-bus/samples-v1 This sample demonstrates how the sendMessages() method can be used to send messages to Service Bus Queue/Topic. diff --git a/sdk/servicebus/service-bus/samples/javascript/session.js b/sdk/servicebus/service-bus/samples/javascript/session.js index 9334c9506a12..159a483f9e74 100644 --- a/sdk/servicebus/service-bus/samples/javascript/session.js +++ b/sdk/servicebus/service-bus/samples/javascript/session.js @@ -3,7 +3,7 @@ Licensed under the MIT Licence. **NOTE**: If you are using version 1.1.x or lower, then please use the link below: - https://github.com/Azure/azure-sdk-for-js/tree/%40azure/service-bus_1.1.5/sdk/servicebus/service-bus/samples + https://github.com/Azure/azure-sdk-for-js/blob/master/sdk/servicebus/service-bus/samples-v1 This sample demonstrates how to send/receive messages to/from session enabled queues/subscriptions in Service Bus. diff --git a/sdk/servicebus/service-bus/samples/javascript/useProxy.js b/sdk/servicebus/service-bus/samples/javascript/useProxy.js index 7a97b807313c..dfbb4ea1177c 100644 --- a/sdk/servicebus/service-bus/samples/javascript/useProxy.js +++ b/sdk/servicebus/service-bus/samples/javascript/useProxy.js @@ -3,7 +3,7 @@ Licensed under the MIT Licence. **NOTE**: If you are using version 1.1.x or lower, then please use the link below: - https://github.com/Azure/azure-sdk-for-js/tree/%40azure/service-bus_1.1.5/sdk/servicebus/service-bus/samples + https://github.com/Azure/azure-sdk-for-js/blob/master/sdk/servicebus/service-bus/samples-v1 This sample demonstrates how to create a ServiceBusClient meant to be used in an environment where outgoing network requests have to go through a proxy server diff --git a/sdk/servicebus/service-bus/samples/javascript/usingAadAuth.js b/sdk/servicebus/service-bus/samples/javascript/usingAadAuth.js index 5cbb1187c90f..f8d834640b7a 100644 --- a/sdk/servicebus/service-bus/samples/javascript/usingAadAuth.js +++ b/sdk/servicebus/service-bus/samples/javascript/usingAadAuth.js @@ -3,7 +3,7 @@ Licensed under the MIT Licence. **NOTE**: If you are using version 1.1.x or lower, then please use the link below: - https://github.com/Azure/azure-sdk-for-js/tree/%40azure/service-bus_1.1.5/sdk/servicebus/service-bus/samples + https://github.com/Azure/azure-sdk-for-js/blob/master/sdk/servicebus/service-bus/samples-v1 This sample demonstrates how to create a namespace using AAD token credentials obtained from using Service Principal Secrets. diff --git a/sdk/servicebus/service-bus/samples/typescript/README.md b/sdk/servicebus/service-bus/samples/typescript/README.md index d6882a711996..ca7b1be318f7 100644 --- a/sdk/servicebus/service-bus/samples/typescript/README.md +++ b/sdk/servicebus/service-bus/samples/typescript/README.md @@ -1,6 +1,6 @@ # Azure Service Bus client library samples for TypeScript -**NOTE**: Samples for @azure/service-bus v1.1.x are still available [here](https://github.com/Azure/azure-sdk-for-js/tree/%40azure/service-bus_1.1.5/sdk/servicebus/service-bus/samples) +**NOTE**: Samples for @azure/service-bus v1.1.x are still available [here](https://github.com/Azure/azure-sdk-for-js/blob/master/sdk/servicebus/service-bus/samples-v1) These sample programs show how to use the TypeScript client libraries for Azure Service Bus in some common scenarios. diff --git a/sdk/servicebus/service-bus/samples/typescript/src/advanced/deferral.ts b/sdk/servicebus/service-bus/samples/typescript/src/advanced/deferral.ts index 46d18722354d..ed662d5114df 100644 --- a/sdk/servicebus/service-bus/samples/typescript/src/advanced/deferral.ts +++ b/sdk/servicebus/service-bus/samples/typescript/src/advanced/deferral.ts @@ -4,7 +4,7 @@ **NOTE**: This sample uses the preview of the next version of the @azure/service-bus package. For samples using the current stable version of the package, please use the link below: - https://github.com/Azure/azure-sdk-for-js/tree/%40azure/service-bus_1.1.5/sdk/servicebus/service-bus/samples + https://github.com/Azure/azure-sdk-for-js/blob/master/sdk/servicebus/service-bus/samples-v1 This sample demonstrates how the defer() function can be used to defer a message for later processing. diff --git a/sdk/servicebus/service-bus/samples/typescript/src/advanced/managementClient.ts b/sdk/servicebus/service-bus/samples/typescript/src/advanced/managementClient.ts index cbfd52247a75..7bccfb3c0a07 100644 --- a/sdk/servicebus/service-bus/samples/typescript/src/advanced/managementClient.ts +++ b/sdk/servicebus/service-bus/samples/typescript/src/advanced/managementClient.ts @@ -4,7 +4,7 @@ **NOTE**: This sample uses the preview of the next version of the @azure/service-bus package. For samples using the current stable version of the package, please use the link below: - https://github.com/Azure/azure-sdk-for-js/tree/%40azure/service-bus_1.1.5/sdk/servicebus/service-bus/samples + https://github.com/Azure/azure-sdk-for-js/blob/master/sdk/servicebus/service-bus/samples-v1 This sample demonstrates how the ServiceBusManagementClient can be used to manage the resources of a service bus namespace. diff --git a/sdk/servicebus/service-bus/samples/typescript/src/advanced/movingMessagesToDLQ.ts b/sdk/servicebus/service-bus/samples/typescript/src/advanced/movingMessagesToDLQ.ts index 4ddac58b8430..4951ff6f7a27 100644 --- a/sdk/servicebus/service-bus/samples/typescript/src/advanced/movingMessagesToDLQ.ts +++ b/sdk/servicebus/service-bus/samples/typescript/src/advanced/movingMessagesToDLQ.ts @@ -4,7 +4,7 @@ **NOTE**: This sample uses the preview of the next version of the @azure/service-bus package. For samples using the current stable version of the package, please use the link below: - https://github.com/Azure/azure-sdk-for-js/tree/%40azure/service-bus_1.1.5/sdk/servicebus/service-bus/samples + https://github.com/Azure/azure-sdk-for-js/blob/master/sdk/servicebus/service-bus/samples-v1 This sample demonstrates scenarios as to how a Service Bus message can be explicitly moved to the DLQ. For other implicit ways when Service Bus messages get moved to DLQ, refer to - diff --git a/sdk/servicebus/service-bus/samples/typescript/src/advanced/processMessageFromDLQ.ts b/sdk/servicebus/service-bus/samples/typescript/src/advanced/processMessageFromDLQ.ts index 3d6417e2c64b..5fb5351d3098 100644 --- a/sdk/servicebus/service-bus/samples/typescript/src/advanced/processMessageFromDLQ.ts +++ b/sdk/servicebus/service-bus/samples/typescript/src/advanced/processMessageFromDLQ.ts @@ -4,7 +4,7 @@ **NOTE**: This sample uses the preview of the next version of the @azure/service-bus package. For samples using the current stable version of the package, please use the link below: - https://github.com/Azure/azure-sdk-for-js/tree/%40azure/service-bus_1.1.5/sdk/servicebus/service-bus/samples + https://github.com/Azure/azure-sdk-for-js/blob/master/sdk/servicebus/service-bus/samples-v1 This sample demonstrates retrieving a message from a dead letter queue, editing it and sending it back to the main queue. diff --git a/sdk/servicebus/service-bus/samples/typescript/src/advanced/sessionState.ts b/sdk/servicebus/service-bus/samples/typescript/src/advanced/sessionState.ts index d229b5281129..ffb1518a36cb 100644 --- a/sdk/servicebus/service-bus/samples/typescript/src/advanced/sessionState.ts +++ b/sdk/servicebus/service-bus/samples/typescript/src/advanced/sessionState.ts @@ -4,7 +4,7 @@ **NOTE**: This sample uses the preview of the next version of the @azure/service-bus package. For samples using the current stable version of the package, please use the link below: - https://github.com/Azure/azure-sdk-for-js/tree/%40azure/service-bus_1.1.5/sdk/servicebus/service-bus/samples + https://github.com/Azure/azure-sdk-for-js/blob/master/sdk/servicebus/service-bus/samples-v1 This sample demonstrates usage of SessionState. @@ -142,7 +142,9 @@ async function processMessageFromSession(sessionId: string) { } console.log( - `Received message: Customer '${sessionReceiver.sessionId}': '${messages[0].body.event_name} ${messages[0].body.event_details}'` + `Received message: Customer '${sessionReceiver.sessionId}': '${messages[0].body.event_name} ${ + messages[0].body.event_details + }'` ); await messages[0].complete(); } else { diff --git a/sdk/servicebus/service-bus/samples/typescript/src/browseMessages.ts b/sdk/servicebus/service-bus/samples/typescript/src/browseMessages.ts index 3bcffd0c6f18..f3ff43ced3a0 100644 --- a/sdk/servicebus/service-bus/samples/typescript/src/browseMessages.ts +++ b/sdk/servicebus/service-bus/samples/typescript/src/browseMessages.ts @@ -4,7 +4,7 @@ **NOTE**: This sample uses the preview of the next version of the @azure/service-bus package. For samples using the current stable version of the package, please use the link below: - https://github.com/Azure/azure-sdk-for-js/tree/%40azure/service-bus_1.1.5/sdk/servicebus/service-bus/samples + https://github.com/Azure/azure-sdk-for-js/blob/master/sdk/servicebus/service-bus/samples-v1 This sample demonstrates how the peekMessages() function can be used to browse a Service Bus message. diff --git a/sdk/servicebus/service-bus/samples/typescript/src/receiveMessagesLoop.ts b/sdk/servicebus/service-bus/samples/typescript/src/receiveMessagesLoop.ts index 4d2714caeb84..bc84250502eb 100644 --- a/sdk/servicebus/service-bus/samples/typescript/src/receiveMessagesLoop.ts +++ b/sdk/servicebus/service-bus/samples/typescript/src/receiveMessagesLoop.ts @@ -4,7 +4,7 @@ **NOTE**: This sample uses the preview of the next version of the @azure/service-bus package. For samples using the current stable version of the package, please use the link below: - https://github.com/Azure/azure-sdk-for-js/tree/%40azure/service-bus_1.1.5/sdk/servicebus/service-bus/samples + https://github.com/Azure/azure-sdk-for-js/blob/master/sdk/servicebus/service-bus/samples-v1 This sample demonstrates how the receiveMessages() function can be used to receive Service Bus messages in a loop. diff --git a/sdk/servicebus/service-bus/samples/typescript/src/receiveMessagesStreaming.ts b/sdk/servicebus/service-bus/samples/typescript/src/receiveMessagesStreaming.ts index e27e4372c23e..e60f7b8bf586 100644 --- a/sdk/servicebus/service-bus/samples/typescript/src/receiveMessagesStreaming.ts +++ b/sdk/servicebus/service-bus/samples/typescript/src/receiveMessagesStreaming.ts @@ -4,7 +4,7 @@ **NOTE**: This sample uses the preview of the next version of the @azure/service-bus package. For samples using the current stable version of the package, please use the link below: - https://github.com/Azure/azure-sdk-for-js/tree/%40azure/service-bus_1.1.5/sdk/servicebus/service-bus/samples + https://github.com/Azure/azure-sdk-for-js/blob/master/sdk/servicebus/service-bus/samples-v1 This sample demonstrates how the receive() function can be used to receive Service Bus messages in a stream. diff --git a/sdk/servicebus/service-bus/samples/typescript/src/scheduledMessages.ts b/sdk/servicebus/service-bus/samples/typescript/src/scheduledMessages.ts index 3ca3248deb8c..649c2d01e553 100644 --- a/sdk/servicebus/service-bus/samples/typescript/src/scheduledMessages.ts +++ b/sdk/servicebus/service-bus/samples/typescript/src/scheduledMessages.ts @@ -4,7 +4,7 @@ **NOTE**: This sample uses the preview of the next version of the @azure/service-bus package. For samples using the current stable version of the package, please use the link below: - https://github.com/Azure/azure-sdk-for-js/tree/%40azure/service-bus_1.1.5/sdk/servicebus/service-bus/samples + https://github.com/Azure/azure-sdk-for-js/blob/master/sdk/servicebus/service-bus/samples-v1 This sample demonstrates how the scheduleMessages() function can be used to schedule messages to appear on a Service Bus Queue/Subscription at a later time. diff --git a/sdk/servicebus/service-bus/samples/typescript/src/sendMessages.ts b/sdk/servicebus/service-bus/samples/typescript/src/sendMessages.ts index e87348dabc98..842acb8a130a 100644 --- a/sdk/servicebus/service-bus/samples/typescript/src/sendMessages.ts +++ b/sdk/servicebus/service-bus/samples/typescript/src/sendMessages.ts @@ -4,7 +4,7 @@ **NOTE**: This sample uses the preview of the next version of the @azure/service-bus package. For samples using the current stable version of the package, please use the link below: - https://github.com/Azure/azure-sdk-for-js/tree/%40azure/service-bus_1.1.5/sdk/servicebus/service-bus/samples + https://github.com/Azure/azure-sdk-for-js/blob/master/sdk/servicebus/service-bus/samples-v1 This sample demonstrates how the sendMessages() method can be used to send messages to Service Bus Queue/Topic. diff --git a/sdk/servicebus/service-bus/samples/typescript/src/session.ts b/sdk/servicebus/service-bus/samples/typescript/src/session.ts index ae7514acc3ce..8297c39099f1 100644 --- a/sdk/servicebus/service-bus/samples/typescript/src/session.ts +++ b/sdk/servicebus/service-bus/samples/typescript/src/session.ts @@ -4,7 +4,7 @@ **NOTE**: This sample uses the preview of the next version of the @azure/service-bus package. For samples using the current stable version of the package, please use the link below: - https://github.com/Azure/azure-sdk-for-js/tree/%40azure/service-bus_1.1.5/sdk/servicebus/service-bus/samples + https://github.com/Azure/azure-sdk-for-js/blob/master/sdk/servicebus/service-bus/samples-v1 This sample demonstrates how to send/receive messages to/from session enabled queues/subscriptions in Service Bus. diff --git a/sdk/servicebus/service-bus/samples/typescript/src/useProxy.ts b/sdk/servicebus/service-bus/samples/typescript/src/useProxy.ts index 7feb1bd1fe1c..f5f98730fa37 100644 --- a/sdk/servicebus/service-bus/samples/typescript/src/useProxy.ts +++ b/sdk/servicebus/service-bus/samples/typescript/src/useProxy.ts @@ -4,7 +4,7 @@ **NOTE**: This sample uses the preview of the next version of the @azure/service-bus package. For samples using the current stable version of the package, please use the link below: - https://github.com/Azure/azure-sdk-for-js/tree/%40azure/service-bus_1.1.5/sdk/servicebus/service-bus/samples + https://github.com/Azure/azure-sdk-for-js/blob/master/sdk/servicebus/service-bus/samples-v1 This sample demonstrates how to create a ServiceBusClient meant to be used in an environment where outgoing network requests have to go through a proxy server diff --git a/sdk/servicebus/service-bus/samples/typescript/src/usingAadAuth.ts b/sdk/servicebus/service-bus/samples/typescript/src/usingAadAuth.ts index bd5d62762087..ecf1d96b3d9c 100644 --- a/sdk/servicebus/service-bus/samples/typescript/src/usingAadAuth.ts +++ b/sdk/servicebus/service-bus/samples/typescript/src/usingAadAuth.ts @@ -4,7 +4,7 @@ **NOTE**: This sample uses the preview of the next version of the @azure/service-bus package. For samples using the current stable version of the package, please use the link below: - https://github.com/Azure/azure-sdk-for-js/tree/%40azure/service-bus_1.1.5/sdk/servicebus/service-bus/samples + https://github.com/Azure/azure-sdk-for-js/blob/master/sdk/servicebus/service-bus/samples-v1 This sample demonstrates how to create a namespace using AAD token credentials obtained from using Service Principal Secrets. diff --git a/sdk/servicebus/service-bus/src/receivers/receiver.ts b/sdk/servicebus/service-bus/src/receivers/receiver.ts index 976e38950e61..9265aaa6c856 100644 --- a/sdk/servicebus/service-bus/src/receivers/receiver.ts +++ b/sdk/servicebus/service-bus/src/receivers/receiver.ts @@ -173,10 +173,7 @@ export class ReceiverImpl> { + context.isSessionEnabled = true; + if (sessionOptions.sessionId != undefined) { + sessionOptions.sessionId = String(sessionOptions.sessionId); + } + const messageSession = await MessageSession.create(context, { + sessionId: sessionOptions.sessionId, + autoRenewLockDurationInMs: sessionOptions.autoRenewLockDurationInMs, + receiveMode: convertToInternalReceiveMode(receiveMode) + }); const sessionReceiver = new SessionReceiverImpl( + messageSession, context, receiveMode, - sessionOptions, retryOptions ); - - await sessionReceiver._createMessageSessionIfDoesntExist(); return sessionReceiver; } private _throwIfReceiverOrConnectionClosed(): void { throwErrorIfConnectionClosed(this._context.namespace); if (this.isClosed) { - const errorMessage = getReceiverClosedErrorMsg( - this._context.entityPath, - this._context.isClosed, - this.sessionId! - ); - const error = new Error(errorMessage); - log.error(`[${this._context.namespace.connectionId}] %O`, error); - throw error; - } - } - - private async _createMessageSessionIfDoesntExist(): Promise { - // TODO - pass timeout for MessageSession creation - if (this._messageSession) { - return; - } - this._context.isSessionEnabled = true; - this._messageSession = await MessageSession.create(this._context, { - sessionId: this._sessionOptions.sessionId, - autoRenewLockDurationInMs: this._sessionOptions.autoRenewLockDurationInMs, - receiveMode: convertToInternalReceiveMode(this.receiveMode) - }); - // By this point, we should have a valid sessionId on the messageSession - // If not, the receiver cannot be used, so throw error. - if (this._messageSession.sessionId == null) { - const error = new Error("Something went wrong. Cannot lock a session."); - log.error(`[${this._context.namespace.connectionId}] %O`, error); - throw error; + if (this._isClosed) { + const errorMessage = getReceiverClosedErrorMsg(this._context.entityPath, this.sessionId); + const error = new Error(errorMessage); + log.error(`[${this._context.namespace.connectionId}] %O`, error); + throw error; + } + const amqpError: AmqpError = { + condition: ErrorNameConditionMapper.SessionLockLostError, + description: `The session lock has expired on the session with id ${this.sessionId}` + }; + throw translate(amqpError); } - this.sessionId = this._messageSession.sessionId; - return; } private _throwIfAlreadyReceiving(): void { @@ -197,13 +177,15 @@ export class SessionReceiverImpl { this._throwIfReceiverOrConnectionClosed(); - const renewSessionLockOperationPromise = async () => { - await this._createMessageSessionIfDoesntExist(); this._messageSession!.sessionLockedUntilUtc = await this._context.managementClient!.renewSessionLock( this.sessionId, { @@ -270,7 +250,6 @@ export class SessionReceiverImpl { - await this._createMessageSessionIfDoesntExist(); await this._context.managementClient!.setSessionState(this.sessionId!, state, { ...options, requestName: "setState", @@ -300,7 +279,6 @@ export class SessionReceiverImpl { - await this._createMessageSessionIfDoesntExist(); return this._context.managementClient!.getSessionState(this.sessionId, { ...options, requestName: "getState", @@ -379,7 +357,6 @@ export class SessionReceiverImpl { - await this._createMessageSessionIfDoesntExist(); const deferredMessages = await this._context.managementClient!.receiveDeferredMessages( deferredSequenceNumbers, convertToInternalReceiveMode(this.receiveMode), @@ -414,8 +391,6 @@ export class SessionReceiverImpl { - await this._createMessageSessionIfDoesntExist(); - const receivedMessages = await this._messageSession!.receiveMessages( maxMessageCount, options?.maxWaitTimeInMs ?? Constants.defaultOperationTimeoutInMs @@ -498,21 +473,11 @@ export class SessionReceiverImpl { - if (!this._messageSession) { - return; - } - if (!this._isClosed) { - this._messageSession.receive(onMessage, onError, options); - } else { - await this._messageSession.close(); - } - return; - }) - .catch((err) => { - onError(err); - }); + try { + this._messageSession.receive(onMessage, onError, options); + } catch (err) { + onError(err); + } } getMessageIterator(options?: GetMessageIteratorOptions): AsyncIterableIterator { @@ -521,10 +486,7 @@ export class SessionReceiverImpl { try { - if (this._messageSession) { - await this._messageSession.close(); - this._messageSession = undefined; - } + await this._messageSession.close(); } catch (err) { log.error( "[%s] An error occurred while closing the SessionReceiver for session %s in %s: %O", diff --git a/sdk/servicebus/service-bus/src/session/messageSession.ts b/sdk/servicebus/service-bus/src/session/messageSession.ts index baa8d3506154..c21764f10953 100644 --- a/sdk/servicebus/service-bus/src/session/messageSession.ts +++ b/sdk/servicebus/service-bus/src/session/messageSession.ts @@ -11,13 +11,15 @@ import { import { AmqpError, EventContext, + isAmqpError, OnAmqpEvent, Receiver, ReceiverEvents, - ReceiverOptions, - isAmqpError + ReceiverOptions } from "rhea-promise"; -import * as log from "../log"; +import { ClientEntityContext } from "../clientEntityContext"; +import { LinkEntity } from "../core/linkEntity"; +import { DispositionStatusOptions } from "../core/managementClient"; import { OnAmqpEventAsPromise, OnError, @@ -25,12 +27,10 @@ import { PromiseLike, ReceiverHelper } from "../core/messageReceiver"; -import { LinkEntity } from "../core/linkEntity"; -import { ClientEntityContext } from "../clientEntityContext"; -import { calculateRenewAfterDuration, convertTicksToDate } from "../util/utils"; -import { throwErrorIfConnectionClosed } from "../util/errors"; +import * as log from "../log"; import { DispositionType, ReceiveMode, ServiceBusMessageImpl } from "../serviceBusMessage"; -import { DispositionStatusOptions } from "../core/managementClient"; +import { throwErrorIfConnectionClosed } from "../util/errors"; +import { calculateRenewAfterDuration, convertTicksToDate } from "../util/utils"; /** * Enum to denote who is calling the session receiver @@ -137,12 +137,16 @@ export class MessageSession extends LinkEntity { */ sessionLockedUntilUtc?: Date; /** - * @property {string} [sessionId] The sessionId for the message session. Empty string is valid sessionId + * @property {string} [providedSessionId] The sessionId provided in the MessageSessionOptions. Empty string is valid sessionId. */ - sessionId?: string; + private providedSessionId?: string; + /** + * @property {string} [sessionId] The sessionId for the message session. Empty string is valid sessionId. + */ + sessionId!: string; /** * @property {number} [maxConcurrentSessions] The maximum number of concurrent sessions that the - * client should initate. + * client should initiate. * - **Default**: `1`. */ maxConcurrentSessions?: number; @@ -183,7 +187,7 @@ export class MessageSession extends LinkEntity { */ autoRenewLock: boolean; /** - * @property {SessionCallee} callee Describes who instantied the MessageSession. Whether it was + * @property {SessionCallee} callee Describes who instantiated the MessageSession. Whether it was * called by the SessionManager or it was called standalone. * - Default: "standalone" */ @@ -284,7 +288,7 @@ export class MessageSession extends LinkEntity { this.name ); this.sessionLockedUntilUtc = await this._context.managementClient!.renewSessionLock( - this.sessionId!, + this.sessionId, { timeoutInMs: 10000 } @@ -330,7 +334,7 @@ export class MessageSession extends LinkEntity { */ private _deleteFromCache(): void { this._receiver = undefined; - delete this._context.messageSessions[this.sessionId!]; + delete this._context.messageSessions[this.sessionId]; log.error( "[%s] Deleted the receiver '%s' with sessionId '%s' from the client cache.", this._context.namespace.connectionId, @@ -371,17 +375,18 @@ export class MessageSession extends LinkEntity { this._receiver.source && this._receiver.source.filter && this._receiver.source.filter[Constants.sessionFilterName]; + let errorMessage: string = ""; // SB allows a sessionId with empty string value :) - if (this.sessionId == null && receivedSessionId == null) { - // Ideally this code path should never be reached as `createReceiver()` should fail instead + if (this.providedSessionId == null && receivedSessionId == null) { + // Ideally this code path should never be reached as `MessageSession.createReceiver()` should fail instead // TODO: https://github.com/Azure/azure-sdk-for-js/issues/9775 to figure out why this code path indeed gets hit. errorMessage = `No unlocked sessions were available`; - } else if (this.sessionId != null && receivedSessionId !== this.sessionId) { + } else if (this.providedSessionId != null && receivedSessionId !== this.providedSessionId) { // This code path is reached if the session is already locked by another receiver. // TODO: Check why the service would not throw an error or just timeout instead of giving a misleading successful receiver - errorMessage = `Failed to get a lock on the session ${this.sessionId}`; + errorMessage = `Failed to get a lock on the session ${this.providedSessionId}`; } if (errorMessage) { @@ -392,7 +397,7 @@ export class MessageSession extends LinkEntity { log.error("[%s] %O", this._context.namespace.connectionId, error); throw error; } - if (this.sessionId == null) this.sessionId = receivedSessionId; + if (this.providedSessionId == null) this.sessionId = receivedSessionId; this.sessionLockedUntilUtc = convertTicksToDate( this._receiver.properties["com.microsoft:locked-until-utc"] ); @@ -418,12 +423,12 @@ export class MessageSession extends LinkEntity { this.name, options ); - if (!this._context.messageSessions[this.sessionId!]) { - this._context.messageSessions[this.sessionId!] = this; + if (!this._context.messageSessions[this.sessionId]) { + this._context.messageSessions[this.sessionId] = this; } this._totalAutoLockRenewDuration = Date.now() + this.maxAutoRenewDurationInMs; - await this._ensureTokenRenewal(); - await this._ensureSessionLockRenewal(); + this._ensureTokenRenewal(); + this._ensureSessionLockRenewal(); } else { log.error( "[%s] The receiver '%s' for sessionId '%s' is open -> %s and is connecting " + @@ -439,7 +444,7 @@ export class MessageSession extends LinkEntity { this.isConnecting = false; const errObj = translate(err); log.error( - "[%s] An error occured while creating the receiver '%s': %O", + "[%s] An error occurred while creating the receiver '%s': %O", this._context.namespace.connectionId, this.name, errObj @@ -490,7 +495,8 @@ export class MessageSession extends LinkEntity { this._receiverHelper = new ReceiverHelper(() => this._receiver); if (!options) options = { sessionId: undefined }; this.autoComplete = false; - this.sessionId = options.sessionId; + this.providedSessionId = options.sessionId; + if (this.providedSessionId != undefined) this.sessionId = this.providedSessionId; this.receiveMode = options.receiveMode || ReceiveMode.peekLock; this.callee = options.callee || SessionCallee.standalone; this.maxAutoRenewDurationInMs = diff --git a/sdk/servicebus/service-bus/src/util/errors.ts b/sdk/servicebus/service-bus/src/util/errors.ts index 09d3e5f46483..41ee2524403c 100644 --- a/sdk/servicebus/service-bus/src/util/errors.ts +++ b/sdk/servicebus/service-bus/src/util/errors.ts @@ -27,7 +27,7 @@ export function throwErrorIfConnectionClosed(context: ConnectionContext): void { export function getSenderClosedErrorMsg(entityPath: string): string { return ( `The sender for "${entityPath}" has been closed and can no longer be used. ` + - `Please create a new sender using the "getSender" method on the ServiceBusClient.` + `Please create a new sender using the "createSender" method on the ServiceBusClient.` ); } @@ -35,29 +35,18 @@ export function getSenderClosedErrorMsg(entityPath: string): string { * @internal * Gets the error message when a receiver is used when its already closed * @param entityPath Value of the `entityPath` property on the client which denotes its name - * @param isClientClosed Denotes if the close() was called on the client that created the sender * @param sessionId If using session receiver, then the id of the session */ -export function getReceiverClosedErrorMsg( - entityPath: string, - isClientClosed: boolean, - sessionId?: string -): string { - if (isClientClosed) { - return ( - `The client for "${entityPath}" has been closed. The receiver created by it can no longer be used. ` + - `Please create a new client using an instance of ServiceBusClient.` - ); - } +export function getReceiverClosedErrorMsg(entityPath: string, sessionId?: string): string { if (sessionId == undefined) { return ( `The receiver for "${entityPath}" has been closed and can no longer be used. ` + - `Please create a new receiver using the "getReceiver" method on the ServiceBusClient.` + `Please create a new receiver using the "createReceiver" method on the ServiceBusClient.` ); } return ( `The receiver for session "${sessionId}" in "${entityPath}" has been closed and can no ` + - `longer be used. Please create a new receiver using the "getSessionReceiver" method on the ServiceBusClient.` + `longer be used. Please create a new receiver using the "createSessionReceiver" method on the ServiceBusClient.` ); } diff --git a/sdk/servicebus/service-bus/test/backupMessageSettlement.spec.ts b/sdk/servicebus/service-bus/test/backupMessageSettlement.spec.ts index 343559e030fd..ef81a2d95eda 100644 --- a/sdk/servicebus/service-bus/test/backupMessageSettlement.spec.ts +++ b/sdk/servicebus/service-bus/test/backupMessageSettlement.spec.ts @@ -11,14 +11,19 @@ import { EntityName, ServiceBusClientForTests, createServiceBusClientForTests, - testPeekMsgsLength + testPeekMsgsLength, + getRandomTestClientTypeWithSessions, + getRandomTestClientTypeWithNoSessions } from "./utils/testutils2"; import { DispositionType, ReceivedMessageWithLock } from "../src/serviceBusMessage"; const should = chai.should(); chai.use(chaiAsPromised); -describe("Backup message settlement - Through ManagementLink", () => { +const noSessionTestClientType = getRandomTestClientTypeWithNoSessions(); +const withSessionTestClientType = getRandomTestClientTypeWithSessions(); + +describe("Message settlement After Receiver is Closed - Through ManagementLink", () => { let serviceBusClient: ServiceBusClientForTests; let sender: Sender; @@ -45,503 +50,285 @@ describe("Backup message settlement - Through ManagementLink", () => { deadLetterReceiver = serviceBusClient.test.createDeadLetterReceiver(entityNames); } - function afterEachTest(): Promise { - return serviceBusClient.test.afterEach(); + afterEach(async () => { + await serviceBusClient.test.afterEach(); + }); + + async function sendReceiveMsg(testMessages: ServiceBusMessage): Promise { + await sender.sendMessages(testMessages); + const msgs = await receiver.receiveMessages(1); + + should.equal(Array.isArray(msgs), true, "`ReceivedMessages` is not an array"); + should.equal(msgs.length, 1, "Unexpected number of messages"); + should.equal(msgs[0].body, testMessages.body, "MessageBody is different than expected"); + should.equal(msgs[0].messageId, testMessages.messageId, "MessageId is different than expected"); + should.equal(msgs[0].deliveryCount, 0, "DeliveryCount is different than expected"); + + return msgs[0]; + } + + async function testComplete(): Promise { + const testMessages = entityNames.usesSessions + ? TestMessage.getSessionSample() + : TestMessage.getSample(); + const msg = await sendReceiveMsg(testMessages); + await receiver.close(); + let errorWasThrown = false; + try { + await msg.complete(); + } catch (err) { + should.equal( + err.message, + `Failed to ${DispositionType.complete} the message as the AMQP link with which the message was received is no longer alive.`, + "Unexpected error thrown" + ); + errorWasThrown = true; + } + + receiver = await serviceBusClient.test.getPeekLockReceiver(entityNames); + if (entityNames.usesSessions) { + should.equal(errorWasThrown, true, "Error was not thrown for messages with session-id"); + const msgBatch = await receiver.receiveMessages(1); + await msgBatch[0].complete(); + } else { + should.equal(errorWasThrown, false, "Error was thrown for sessions without session-id"); + } + await testPeekMsgsLength(receiver, 0); } - describe("Operations On Messages After Receiver Is Closed", function(): void { - afterEach(async () => { - await afterEachTest(); - }); + it(noSessionTestClientType + ": complete() removes message", async function(): Promise { + await beforeEachTest(noSessionTestClientType); + await testComplete(); + }); - async function sendReceiveMsg( - testMessages: ServiceBusMessage - ): Promise { - await sender.sendMessages(testMessages); - const msgs = await receiver.receiveMessages(1); + it(withSessionTestClientType + ": complete() removes message", async function(): Promise { + await beforeEachTest(withSessionTestClientType); + await testComplete(); + }); - should.equal(Array.isArray(msgs), true, "`ReceivedMessages` is not an array"); - should.equal(msgs.length, 1, "Unexpected number of messages"); - should.equal(msgs[0].body, testMessages.body, "MessageBody is different than expected"); + async function testAbandon(): Promise { + const testMessages = entityNames.usesSessions + ? TestMessage.getSessionSample() + : TestMessage.getSample(); + const msg = await sendReceiveMsg(testMessages); + await receiver.close(); + let errorWasThrown = false; + try { + await msg.abandon(); + } catch (err) { should.equal( - msgs[0].messageId, - testMessages.messageId, - "MessageId is different than expected" + err.message, + `Failed to ${DispositionType.abandon} the message as the AMQP link with which the message was received is no longer alive.`, + "Unexpected error thrown" ); - should.equal(msgs[0].deliveryCount, 0, "DeliveryCount is different than expected"); + errorWasThrown = true; + } - return msgs[0]; + if (entityNames.usesSessions) { + should.equal(errorWasThrown, true, "Error was not thrown for messages with session-id"); + } else { + should.equal(errorWasThrown, false, "Error was thrown for messages without session-id"); } + receiver = await serviceBusClient.test.getPeekLockReceiver(entityNames); + await testPeekMsgsLength(receiver, 1); - describe("Complete a message", function(): void { - async function testComplete(): Promise { - const testMessages = entityNames.usesSessions - ? TestMessage.getSessionSample() - : TestMessage.getSample(); - const msg = await sendReceiveMsg(testMessages); - await receiver.close(); - let errorWasThrown = false; - try { - await msg.complete(); - } catch (err) { - should.equal( - err.message, - `Failed to ${DispositionType.complete} the message as the AMQP link with which the message was received is no longer alive.`, - "Unexpected error thrown" - ); - errorWasThrown = true; - } - - receiver = await serviceBusClient.test.getPeekLockReceiver(entityNames); - if (entityNames.usesSessions) { - should.equal(errorWasThrown, true, "Error was not thrown for messages with session-id"); - const msgBatch = await receiver.receiveMessages(1); - await msgBatch[0].complete(); - } else { - should.equal(errorWasThrown, false, "Error was thrown for sessions without session-id"); - } - await testPeekMsgsLength(receiver, 0); - } + const messageBatch = await receiver.receiveMessages(1); - it("Partitioned Queue: complete() removes message", async function(): Promise { - await beforeEachTest(TestClientType.PartitionedQueue); - await testComplete(); - }); - - it("Partitioned Subscription: complete() removes message", async function(): Promise { - await beforeEachTest(TestClientType.PartitionedSubscription); - await testComplete(); - }); - - it("Unpartitioned Queue: complete() removes message #RunInBrowser ", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedQueue); - await testComplete(); - }); - - it("Unpartitioned Subscription: complete() removes message", async function(): Promise { - await beforeEachTest(TestClientType.UnpartitionedSubscription); - await testComplete(); - }); - - it("Partitioned Queue with Sessions: complete() throws error", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedQueueWithSessions); - await testComplete(); - }); - - it("Partitioned Subscription with Sessions: complete() throws error", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedSubscriptionWithSessions); - await testComplete(); - }); - - it("Unpartitioned Queue with Sessions: complete() throws error #RunInBrowser", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedQueueWithSessions); - await testComplete(); - }); - - it("Unpartitioned Subscription with Sessions: complete() throws error", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedSubscriptionWithSessions); - await testComplete(); - }); - }); - - describe("Abandon a message", function(): void { - async function testAbandon(): Promise { - const testMessages = entityNames.usesSessions - ? TestMessage.getSessionSample() - : TestMessage.getSample(); - const msg = await sendReceiveMsg(testMessages); - await receiver.close(); - let errorWasThrown = false; - try { - await msg.abandon(); - } catch (err) { - should.equal( - err.message, - `Failed to ${DispositionType.abandon} the message as the AMQP link with which the message was received is no longer alive.`, - "Unexpected error thrown" - ); - errorWasThrown = true; - } - - if (entityNames.usesSessions) { - should.equal(errorWasThrown, true, "Error was not thrown for messages with session-id"); - } else { - should.equal(errorWasThrown, false, "Error was thrown for sessions without session-id"); - } - receiver = await serviceBusClient.test.getPeekLockReceiver(entityNames); - await testPeekMsgsLength(receiver, 1); - - const messageBatch = await receiver.receiveMessages(1); - - await messageBatch[0].complete(); - - await testPeekMsgsLength(receiver, 0); - } + await messageBatch[0].complete(); - it("Partitioned Queue: abandon() retains message with incremented deliveryCount", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedQueue); - await testAbandon(); - }); - - it("Partitioned Subscription: abandon() retains message with incremented deliveryCount", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedSubscription); - await testAbandon(); - }); - - it("Unpartitioned Queue: abandon() retains message with incremented deliveryCount #RunInBrowser", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedQueue); - await testAbandon(); - }); - - it("Unpartitioned Subscription: abandon() retains message with incremented deliveryCount", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedSubscription); - await testAbandon(); - }); - - it("Partitioned Queue with Sessions: abandon() throws error", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedQueueWithSessions); - await testAbandon(); - }); - - it("Partitioned Subscription with Sessions: abandon() throws error", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedSubscriptionWithSessions); - await testAbandon(); - }); - - it("Unpartitioned Queue with Sessions: abandon() throws error #RunInBrowser", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedQueueWithSessions); - await testAbandon(); - }); - - it("Unpartitioned Subscription with Sessions: abandon() throws error", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedSubscriptionWithSessions); - await testAbandon(); - }); - }); - - describe("Defer a message", function(): void { - async function testDefer(): Promise { - const testMessages = entityNames.usesSessions - ? TestMessage.getSessionSample() - : TestMessage.getSample(); - const msg = await sendReceiveMsg(testMessages); - - if (!msg.sequenceNumber) { - throw "Sequence Number can not be null"; - } - const sequenceNumber = msg.sequenceNumber; - await receiver.close(); - let errorWasThrown = false; - try { - await msg.defer(); - } catch (err) { - should.equal( - err.message, - `Failed to ${DispositionType.defer} the message as the AMQP link with which the message was received is no longer alive.`, - "Unexpected error thrown" - ); - errorWasThrown = true; - } - - if (entityNames.usesSessions) { - should.equal(errorWasThrown, true, "Error was not thrown for messages with session-id"); - } else { - should.equal(errorWasThrown, false, "Error was thrown for sessions without session-id"); - } - receiver = await serviceBusClient.test.getPeekLockReceiver(entityNames); - if (!entityNames.usesSessions) { - const [deferredMsg] = await receiver.receiveDeferredMessages(sequenceNumber); - if (!deferredMsg) { - throw "No message received for sequence number"; - } - await deferredMsg.complete(); - } else { - const messageBatch = await receiver.receiveMessages(1); - await messageBatch[0].complete(); - } - await testPeekMsgsLength(receiver, 0); - } + await testPeekMsgsLength(receiver, 0); + } - it("Partitioned Queue: defer() moves message to deferred queue", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedQueue); - await testDefer(); - }); - - it("Partitioned Subscription: defer() moves message to deferred queue", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedSubscription); - await testDefer(); - }); - - it("Unpartitioned Queue: defer() moves message to deferred queue #RunInBrowser", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedQueue); - await testDefer(); - }); - - it("Unpartitioned Subscription: defer() moves message to deferred queue", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedSubscription); - await testDefer(); - }); - - it("Partitioned Queue with Sessions: defer() throws error", async function(): Promise { - await beforeEachTest(TestClientType.PartitionedQueueWithSessions); - await testDefer(); - }); - - it("Partitioned Subscription with Sessions: defer() throws error", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedSubscriptionWithSessions); - await testDefer(); - }); - - it("Unpartitioned Queue with Sessions: defer() throws error #RunInBrowser", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedQueueWithSessions); - await testDefer(); - }); - - it("Unpartitioned Subscription with Sessions: defer() throws error", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedSubscriptionWithSessions); - await testDefer(); - }); - }); - - describe("Deadletter a message", function(): void { - async function testDeadletter(useSessions?: boolean): Promise { - const testMessages = useSessions ? TestMessage.getSessionSample() : TestMessage.getSample(); - const msg = await sendReceiveMsg(testMessages); - await receiver.close(); - let errorWasThrown = false; - try { - await msg.deadLetter(); - } catch (err) { - should.equal( - err.message, - `Failed to ${DispositionType.deadletter} the message as the AMQP link with which the message was received is no longer alive.`, - "Unexpected error thrown" - ); - errorWasThrown = true; - } - - if (entityNames.usesSessions) { - should.equal(errorWasThrown, true, "Error was not thrown for messages with session-id"); - } else { - should.equal(errorWasThrown, false, "Error was thrown for sessions without session-id"); - } - - receiver = await serviceBusClient.test.getPeekLockReceiver(entityNames); - - if (!entityNames.usesSessions) { - const deadLetterMsgsBatch = await deadLetterReceiver.receiveMessages(1); - - should.equal( - Array.isArray(deadLetterMsgsBatch), - true, - "`ReceivedMessages` from Deadletter is not an array" - ); - should.equal(deadLetterMsgsBatch.length, 1, "Unexpected number of messages"); - should.equal( - deadLetterMsgsBatch[0].body, - testMessages.body, - "MessageBody is different than expected" - ); - should.equal( - deadLetterMsgsBatch[0].messageId, - testMessages.messageId, - "MessageId is different than expected" - ); - - await deadLetterMsgsBatch[0].complete(); - - await testPeekMsgsLength(deadLetterReceiver, 0); - } else { - const messageBatch = await receiver.receiveMessages(1); - await messageBatch[0].complete(); - - await testPeekMsgsLength(receiver, 0); - } - } + it( + noSessionTestClientType + ": abandon() retains message with incremented deliveryCount", + async function(): Promise { + await beforeEachTest(noSessionTestClientType); + await testAbandon(); + } + ); - it("Partitioned Queue: deadLetter() moves message to deadletter queue", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedQueue); - await testDeadletter(); - }); - - it("Partitioned Subscription: deadLetter() moves message to deadletter queue", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedSubscription); - await testDeadletter(); - }); - - it("Unpartitioned Queue: deadLetter() moves message to deadletter queue #RunInBrowser", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedQueue); - await testDeadletter(); - }); - - it("Unpartitioned Subscription: deadLetter() moves message to deadletter queue", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedSubscription); - await testDeadletter(); - }); - - it("Partitioned Queue with Sessions: deadLetter() throws error", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedQueueWithSessions); - await testDeadletter(true); - }); - - it("Partitioned Subscription with Sessions: deadLetter() throws error", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedSubscriptionWithSessions); - await testDeadletter(true); - }); - - it("Unpartitioned Queue with Sessions: deadLetter() throws error #RunInBrowser", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedQueueWithSessions); - await testDeadletter(true); - }); - - it("Unpartitioned Subscription with Sessions: deadLetter() throws error", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedSubscriptionWithSessions); - await testDeadletter(true); - }); - }); - - describe("Lock renewal for a message", function(): void { - async function testRenewLock(): Promise { - const testMessages = entityNames.usesSessions - ? TestMessage.getSessionSample() - : TestMessage.getSample(); - const msg = await sendReceiveMsg(testMessages); - await receiver.close(); - let errorWasThrown = false; - try { - const lockedUntilBeforeRenewlock = msg.lockedUntilUtc; - const lockedUntilAfterRenewlock = await msg.renewLock(); - should.equal( - lockedUntilAfterRenewlock > lockedUntilBeforeRenewlock!, - true, - "MessageLock did not get renewed!" - ); - await msg.complete(); - } catch (err) { - should.equal( - err.message, - `Invalid operation on the message, message lock doesn't exist when dealing with sessions`, - "Unexpected error thrown" - ); - errorWasThrown = true; - } - - receiver = await serviceBusClient.test.getPeekLockReceiver(entityNames); - if (entityNames.usesSessions) { - should.equal(errorWasThrown, true, "Error was not thrown for messages with session-id"); - const msgBatch = await receiver.receiveMessages(1); - await msgBatch[0].complete(); - } else { - should.equal(errorWasThrown, false, "Error was thrown for sessions without session-id"); - } - await testPeekMsgsLength(receiver, 0); + it( + withSessionTestClientType + ": abandon() retains message with incremented deliveryCount", + async function(): Promise { + await beforeEachTest(withSessionTestClientType); + await testAbandon(); + } + ); + + async function testDefer(): Promise { + const testMessages = entityNames.usesSessions + ? TestMessage.getSessionSample() + : TestMessage.getSample(); + const msg = await sendReceiveMsg(testMessages); + + if (!msg.sequenceNumber) { + throw "Sequence Number can not be null"; + } + const sequenceNumber = msg.sequenceNumber; + await receiver.close(); + let errorWasThrown = false; + try { + await msg.defer(); + } catch (err) { + should.equal( + err.message, + `Failed to ${DispositionType.defer} the message as the AMQP link with which the message was received is no longer alive.`, + "Unexpected error thrown" + ); + errorWasThrown = true; + } + + if (entityNames.usesSessions) { + should.equal(errorWasThrown, true, "Error was not thrown for messages with session-id"); + } else { + should.equal(errorWasThrown, false, "Error was thrown for sessions without session-id"); + } + receiver = await serviceBusClient.test.getPeekLockReceiver(entityNames); + if (!entityNames.usesSessions) { + const [deferredMsg] = await receiver.receiveDeferredMessages(sequenceNumber); + if (!deferredMsg) { + throw "No message received for sequence number"; } + await deferredMsg.complete(); + } else { + const messageBatch = await receiver.receiveMessages(1); + await messageBatch[0].complete(); + } + await testPeekMsgsLength(receiver, 0); + } + + it( + noSessionTestClientType + ": defer() moves message to deferred queue", + async function(): Promise { + await beforeEachTest(noSessionTestClientType); + await testDefer(); + } + ); + + it( + withSessionTestClientType + ": defer() moves message to deferred queue", + async function(): Promise { + await beforeEachTest(withSessionTestClientType); + await testDefer(); + } + ); + + async function testDeadletter(): Promise { + const testMessages = entityNames.usesSessions + ? TestMessage.getSessionSample() + : TestMessage.getSample(); + const msg = await sendReceiveMsg(testMessages); + await receiver.close(); + let errorWasThrown = false; + try { + await msg.deadLetter(); + } catch (err) { + should.equal( + err.message, + `Failed to ${DispositionType.deadletter} the message as the AMQP link with which the message was received is no longer alive.`, + "Unexpected error thrown" + ); + errorWasThrown = true; + } + + if (entityNames.usesSessions) { + should.equal(errorWasThrown, true, "Error was not thrown for messages with session-id"); + } else { + should.equal(errorWasThrown, false, "Error was thrown for sessions without session-id"); + } + + receiver = await serviceBusClient.test.getPeekLockReceiver(entityNames); + + if (!entityNames.usesSessions) { + const deadLetterMsgsBatch = await deadLetterReceiver.receiveMessages(1); + + should.equal( + Array.isArray(deadLetterMsgsBatch), + true, + "`ReceivedMessages` from Deadletter is not an array" + ); + should.equal(deadLetterMsgsBatch.length, 1, "Unexpected number of messages"); + should.equal( + deadLetterMsgsBatch[0].body, + testMessages.body, + "MessageBody is different than expected" + ); + should.equal( + deadLetterMsgsBatch[0].messageId, + testMessages.messageId, + "MessageId is different than expected" + ); + + await deadLetterMsgsBatch[0].complete(); + + await testPeekMsgsLength(deadLetterReceiver, 0); + } else { + const messageBatch = await receiver.receiveMessages(1); + await messageBatch[0].complete(); + + await testPeekMsgsLength(receiver, 0); + } + } + + it( + noSessionTestClientType + ": deadLetter() moves message to deadletter queue", + async function(): Promise { + await beforeEachTest(noSessionTestClientType); + await testDeadletter(); + } + ); + + it( + withSessionTestClientType + ": deadLetter() moves message to deadletter queue", + async function(): Promise { + await beforeEachTest(withSessionTestClientType); + await testDeadletter(); + } + ); + + async function testRenewLock(): Promise { + const testMessages = entityNames.usesSessions + ? TestMessage.getSessionSample() + : TestMessage.getSample(); + const msg = await sendReceiveMsg(testMessages); + await receiver.close(); + let errorWasThrown = false; + try { + const lockedUntilBeforeRenewlock = msg.lockedUntilUtc; + const lockedUntilAfterRenewlock = await msg.renewLock(); + should.equal( + lockedUntilAfterRenewlock > lockedUntilBeforeRenewlock!, + true, + "MessageLock did not get renewed!" + ); + await msg.complete(); + } catch (err) { + should.equal( + err.message, + `Invalid operation on the message, message lock doesn't exist when dealing with sessions`, + "Unexpected error thrown" + ); + errorWasThrown = true; + } + + receiver = await serviceBusClient.test.getPeekLockReceiver(entityNames); + if (entityNames.usesSessions) { + should.equal(errorWasThrown, true, "Error was not thrown for messages with session-id"); + const msgBatch = await receiver.receiveMessages(1); + await msgBatch[0].complete(); + } else { + should.equal(errorWasThrown, false, "Error was thrown for sessions without session-id"); + } + await testPeekMsgsLength(receiver, 0); + } + + it(noSessionTestClientType + ": Lock renewal for a message", async function(): Promise { + await beforeEachTest(noSessionTestClientType); + await testRenewLock(); + }); - it("Partitioned Queue: complete() removes message", async function(): Promise { - await beforeEachTest(TestClientType.PartitionedQueue); - await testRenewLock(); - }); - - it("Partitioned Subscription: complete() removes message", async function(): Promise { - await beforeEachTest(TestClientType.PartitionedSubscription); - await testRenewLock(); - }); - - it("Unpartitioned Queue: complete() removes message #RunInBrowser ", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedQueue); - await testRenewLock(); - }); - - it("Unpartitioned Subscription: complete() removes message", async function(): Promise { - await beforeEachTest(TestClientType.UnpartitionedSubscription); - await testRenewLock(); - }); - - it("Partitioned Queue with Sessions: complete() throws error", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedQueueWithSessions); - await testRenewLock(); - }); - - it("Partitioned Subscription with Sessions: complete() throws error", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedSubscriptionWithSessions); - await testRenewLock(); - }); - - it("Unpartitioned Queue with Sessions: complete() throws error #RunInBrowser", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedQueueWithSessions); - await testRenewLock(); - }); - - it("Unpartitioned Subscription with Sessions: complete() throws error", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedSubscriptionWithSessions); - await testRenewLock(); - }); - }); + it(withSessionTestClientType + ": Lock renewal for session", async function(): Promise { + await beforeEachTest(withSessionTestClientType); + await testRenewLock(); }); }); diff --git a/sdk/servicebus/service-bus/test/batchReceiver.spec.ts b/sdk/servicebus/service-bus/test/batchReceiver.spec.ts index 92fa54b54a01..c86a64be8ab2 100644 --- a/sdk/servicebus/service-bus/test/batchReceiver.spec.ts +++ b/sdk/servicebus/service-bus/test/batchReceiver.spec.ts @@ -12,7 +12,11 @@ import { Sender } from "../src/sender"; import { ServiceBusClientForTests, createServiceBusClientForTests, - testPeekMsgsLength + testPeekMsgsLength, + getRandomTestClientTypeWithSessions, + getRandomTestClientTypeWithNoSessions, + EntityName, + getRandomTestClientType } from "./utils/testutils2"; import { ReceivedMessage, ReceivedMessageWithLock } from "../src/serviceBusMessage"; import { AbortController } from "@azure/abort-controller"; @@ -21,15 +25,32 @@ import { ReceiverEvents } from "rhea-promise"; const should = chai.should(); chai.use(chaiAsPromised); -describe("batchReceiver", () => { - let serviceBusClient: ServiceBusClientForTests; - let errorWasThrown: boolean; +const noSessionTestClientType = getRandomTestClientTypeWithNoSessions(); +const withSessionTestClientType = getRandomTestClientTypeWithSessions(); +const anyRandomTestClientType = getRandomTestClientType(); - let sender: Sender; - let receiver: Receiver; - let deadLetterReceiver: Receiver; - const maxDeliveryCount = 10; +let serviceBusClient: ServiceBusClientForTests; +let entityNames: EntityName; +let sender: Sender; +let receiver: Receiver; +let deadLetterReceiver: Receiver; + +async function beforeEachTest(entityType: TestClientType): Promise { + entityNames = await serviceBusClient.test.createTestEntities(entityType); + receiver = await serviceBusClient.test.getPeekLockReceiver(entityNames); + + sender = serviceBusClient.test.addToCleanup( + serviceBusClient.createSender(entityNames.queue ?? entityNames.topic!) + ); + + deadLetterReceiver = serviceBusClient.test.createDeadLetterReceiver(entityNames); +} + +function afterEachTest(): Promise { + return serviceBusClient.test.afterEach(); +} +describe("Batch Receiver - default values", function(): void { before(() => { serviceBusClient = createServiceBusClientForTests(); }); @@ -38,23 +59,12 @@ describe("batchReceiver", () => { return serviceBusClient.test.after(); }); - async function beforeEachTest(entityType: TestClientType): Promise { - const entityNames = await serviceBusClient.test.createTestEntities(entityType); - receiver = await serviceBusClient.test.getPeekLockReceiver(entityNames); - - sender = serviceBusClient.test.addToCleanup( - serviceBusClient.createSender(entityNames.queue ?? entityNames.topic!) - ); - - deadLetterReceiver = serviceBusClient.test.createDeadLetterReceiver(entityNames); - } - - function afterEachTest(): Promise { - return serviceBusClient.test.afterEach(); - } + afterEach(async () => { + await afterEachTest(); + }); - it("Partitioned Queue: - maxMessageCount defaults to 1", async function(): Promise { - await beforeEachTest(TestClientType.PartitionedQueue); + it(noSessionTestClientType + ": maxMessageCount defaults to 1", async function(): Promise { + await beforeEachTest(noSessionTestClientType); const testMessage = TestMessage.getSample(); await sender.sendMessages(testMessage); @@ -78,10 +88,10 @@ describe("batchReceiver", () => { await msgs[0].complete(); }); - it("Partitioned Queue with Sessions- maxMessageCount defaults to 1", async function(): Promise< + it(withSessionTestClientType + ": maxMessageCount defaults to 1", async function(): Promise< void > { - await beforeEachTest(TestClientType.PartitionedQueueWithSessions); + await beforeEachTest(withSessionTestClientType); const testMessage = TestMessage.getSessionSample(); await sender.sendMessages(testMessage); @@ -104,938 +114,726 @@ describe("batchReceiver", () => { ); await msgs[0].complete(); }); +}); - describe("Batch Receiver - Settle message", function(): void { - afterEach(async () => { - await afterEachTest(); - }); - - async function sendReceiveMsg( - testMessages: ServiceBusMessage - ): Promise { - await sender.sendMessages(testMessages); - const msgs = await receiver.receiveMessages(1); - - should.equal(Array.isArray(msgs), true, "`ReceivedMessages` is not an array"); - should.equal(msgs.length, 1, "Unexpected number of messages"); - should.equal(msgs[0].body, testMessages.body, "MessageBody is different than expected"); - should.equal( - msgs[0].messageId, - testMessages.messageId, - "MessageId is different than expected" - ); - should.equal(msgs[0].deliveryCount, 0, "DeliveryCount is different than expected"); - - return msgs[0]; - } +describe("Batch Receiver - Settle message", function(): void { + const maxDeliveryCount = 10; - async function testComplete(useSessions?: boolean): Promise { - const testMessages = useSessions ? TestMessage.getSessionSample() : TestMessage.getSample(); - const msg = await sendReceiveMsg(testMessages); + before(() => { + serviceBusClient = createServiceBusClientForTests(); + }); - await msg.complete(); + after(() => { + return serviceBusClient.test.after(); + }); - await testPeekMsgsLength(receiver, 0); - } + afterEach(async () => { + await afterEachTest(); + }); - it("Partitioned Queue: complete() removes message", async function(): Promise { - await beforeEachTest(TestClientType.PartitionedQueue); - await testComplete(); - }); + async function sendReceiveMsg(testMessages: ServiceBusMessage): Promise { + await sender.sendMessages(testMessages); + const msgs = await receiver.receiveMessages(1); - it("Partitioned Subscription: complete() removes message", async function(): Promise { - await beforeEachTest(TestClientType.PartitionedSubscription); - await testComplete(); - }); + should.equal(Array.isArray(msgs), true, "`ReceivedMessages` is not an array"); + should.equal(msgs.length, 1, "Unexpected number of messages"); + should.equal(msgs[0].body, testMessages.body, "MessageBody is different than expected"); + should.equal(msgs[0].messageId, testMessages.messageId, "MessageId is different than expected"); + should.equal(msgs[0].deliveryCount, 0, "DeliveryCount is different than expected"); - it("Unpartitioned Queue: complete() removes message ", async function(): Promise { - await beforeEachTest(TestClientType.UnpartitionedQueue); - await testComplete(); - }); + return msgs[0]; + } - it("Unpartitioned Subscription: complete() removes message", async function(): Promise { - await beforeEachTest(TestClientType.UnpartitionedSubscription); - await testComplete(); - }); + async function testComplete(): Promise { + const testMessages = entityNames.usesSessions + ? TestMessage.getSessionSample() + : TestMessage.getSample(); + const msg = await sendReceiveMsg(testMessages); - it("Partitioned Queue with Sessions: complete() removes message", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedQueueWithSessions); - await testComplete(true); - }); + await msg.complete(); - it("Partitioned Subscription with Sessions: complete() removes message", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedSubscriptionWithSessions); - await testComplete(true); - }); + await testPeekMsgsLength(receiver, 0); + } - it("Unpartitioned Queue with Sessions: complete() removes message", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedQueueWithSessions); - await testComplete(true); - }); + it(noSessionTestClientType + ": complete() removes message", async function(): Promise { + await beforeEachTest(noSessionTestClientType); + await testComplete(); + }); - it("Unpartitioned Subscription with Sessions: complete() removes message", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedSubscriptionWithSessions); - await testComplete(true); - }); + it(withSessionTestClientType + ": complete() removes message", async function(): Promise { + await beforeEachTest(withSessionTestClientType); + await testComplete(); + }); - async function testAbandon(useSessions?: boolean): Promise { - const testMessages = useSessions ? TestMessage.getSessionSample() : TestMessage.getSample(); - const msg = await sendReceiveMsg(testMessages); - await msg.abandon(); + async function testAbandon(): Promise { + const testMessages = entityNames.usesSessions + ? TestMessage.getSessionSample() + : TestMessage.getSample(); + const msg = await sendReceiveMsg(testMessages); + await msg.abandon(); - await testPeekMsgsLength(receiver, 1); + await testPeekMsgsLength(receiver, 1); - const messageBatch = await receiver.receiveMessages(1); + const messageBatch = await receiver.receiveMessages(1); - should.equal(messageBatch.length, 1, "Unexpected number of messages"); - should.equal(messageBatch[0].deliveryCount, 1, "DeliveryCount is different than expected"); - should.equal( - messageBatch[0].messageId, - testMessages.messageId, - "MessageId is different than expected" - ); + should.equal(messageBatch.length, 1, "Unexpected number of messages"); + should.equal(messageBatch[0].deliveryCount, 1, "DeliveryCount is different than expected"); + should.equal( + messageBatch[0].messageId, + testMessages.messageId, + "MessageId is different than expected" + ); - await messageBatch[0].complete(); + await messageBatch[0].complete(); - await testPeekMsgsLength(receiver, 0); - } - - it("Partitioned Queue: abandon() retains message with incremented deliveryCount", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedQueue); - await testAbandon(); - }); - - it("Partitioned Subscription: abandon() retains message with incremented deliveryCount", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedSubscription); - await testAbandon(); - }); + await testPeekMsgsLength(receiver, 0); + } - it("Unpartitioned Queue: abandon() retains message with incremented deliveryCount", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedQueue); + it( + noSessionTestClientType + ": abandon() retains message with incremented deliveryCount", + async function(): Promise { + await beforeEachTest(noSessionTestClientType); await testAbandon(); - }); + } + ); - it("Unpartitioned Subscription: abandon() retains message with incremented deliveryCount", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedSubscription); + it( + withSessionTestClientType + ": abandon() retains message with incremented deliveryCount", + async function(): Promise { + await beforeEachTest(withSessionTestClientType); await testAbandon(); - }); - - it("Partitioned Queue with Sessions: abandon() retains message with incremented deliveryCount", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedQueueWithSessions); - await testAbandon(true); - }); - - it("Partitioned Subscription with Sessions: abandon() retains message with incremented deliveryCount", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedSubscriptionWithSessions); - await testAbandon(true); - }); - - it("Unpartitioned Queue with Sessions: abandon() retains message with incremented deliveryCount", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedQueueWithSessions); - await testAbandon(true); - }); - - it("Unpartitioned Subscription with Sessions: abandon() retains message with incremented deliveryCount", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedSubscriptionWithSessions); - await testAbandon(true); - }); - - async function testAbandonMsgsTillMaxDeliveryCount(useSessions?: boolean): Promise { - const testMessages = useSessions ? TestMessage.getSessionSample() : TestMessage.getSample(); - await sender.sendMessages(testMessages); - let abandonMsgCount = 0; - - while (abandonMsgCount < maxDeliveryCount) { - const batch = await receiver.receiveMessages(1); - - should.equal(batch.length, 1, "Unexpected number of messages"); - should.equal( - batch[0].messageId, - testMessages.messageId, - "MessageId is different than expected" - ); - should.equal( - batch[0].deliveryCount, - abandonMsgCount, - "DeliveryCount is different than expected" - ); - abandonMsgCount++; - - await batch[0].abandon(); - } + } + ); - await testPeekMsgsLength(receiver, 0); + async function testAbandonMsgsTillMaxDeliveryCount(): Promise { + const testMessages = entityNames.usesSessions + ? TestMessage.getSessionSample() + : TestMessage.getSample(); + await sender.sendMessages(testMessages); + let abandonMsgCount = 0; - const deadLetterMsgsBatch = await deadLetterReceiver.receiveMessages(1); + while (abandonMsgCount < maxDeliveryCount) { + const batch = await receiver.receiveMessages(1); + should.equal(batch.length, 1, "Unexpected number of messages"); should.equal( - Array.isArray(deadLetterMsgsBatch), - true, - "`ReceivedMessages` from Deadletter is not an array" - ); - should.equal(deadLetterMsgsBatch.length, 1, "Unexpected number of messages"); - should.equal( - deadLetterMsgsBatch[0].body, - testMessages.body, - "MessageBody is different than expected" - ); - should.equal( - deadLetterMsgsBatch[0].messageId, + batch[0].messageId, testMessages.messageId, "MessageId is different than expected" ); + should.equal( + batch[0].deliveryCount, + abandonMsgCount, + "DeliveryCount is different than expected" + ); + abandonMsgCount++; - await deadLetterMsgsBatch[0].complete(); - - await testPeekMsgsLength(deadLetterReceiver, 0); + await batch[0].abandon(); } - it("Partitioned Queue: Multiple abandons until maxDeliveryCount.", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedQueue); - await testAbandonMsgsTillMaxDeliveryCount(); - }); - - it("Partitioned Subscription: Multiple abandons until maxDeliveryCount.", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedSubscription); - await testAbandonMsgsTillMaxDeliveryCount(); - }); - - it("Unpartitioned Queue: Multiple abandons until maxDeliveryCount.", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedQueue); - await testAbandonMsgsTillMaxDeliveryCount(); - }); + await testPeekMsgsLength(receiver, 0); - it("Unpartitioned Subscription: Multiple abandons until maxDeliveryCount.", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedSubscription); - await testAbandonMsgsTillMaxDeliveryCount(); - }); + const deadLetterMsgsBatch = await deadLetterReceiver.receiveMessages(1); - it("Partitioned Queue with Sessions: Multiple abandons until maxDeliveryCount.", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedQueue); - await testAbandonMsgsTillMaxDeliveryCount(true); - }); - - it("Partitioned Subscription with Sessions: Multiple abandons until maxDeliveryCount.", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedSubscription); - await testAbandonMsgsTillMaxDeliveryCount(true); - }); - - it("Unpartitioned Queue with Sessions: Multiple abandons until maxDeliveryCount.", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedQueue); - await testAbandonMsgsTillMaxDeliveryCount(true); - }); + should.equal( + Array.isArray(deadLetterMsgsBatch), + true, + "`ReceivedMessages` from Deadletter is not an array" + ); + should.equal(deadLetterMsgsBatch.length, 1, "Unexpected number of messages"); + should.equal( + deadLetterMsgsBatch[0].body, + testMessages.body, + "MessageBody is different than expected" + ); + should.equal( + deadLetterMsgsBatch[0].messageId, + testMessages.messageId, + "MessageId is different than expected" + ); - it("Unpartitioned Subscription with Sessions: Multiple abandons until maxDeliveryCount.", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedSubscription); - await testAbandonMsgsTillMaxDeliveryCount(true); - }); + await deadLetterMsgsBatch[0].complete(); - async function testDefer(useSessions?: boolean): Promise { - const testMessages = useSessions ? TestMessage.getSessionSample() : TestMessage.getSample(); - const msg = await sendReceiveMsg(testMessages); + await testPeekMsgsLength(deadLetterReceiver, 0); + } - if (!msg.sequenceNumber) { - throw "Sequence Number can not be null"; - } - const sequenceNumber = msg.sequenceNumber; - await msg.defer(); + it( + noSessionTestClientType + ": Multiple abandons until maxDeliveryCount.", + async function(): Promise { + await beforeEachTest(noSessionTestClientType); + await testAbandonMsgsTillMaxDeliveryCount(); + } + ); - const [deferredMsg] = await receiver.receiveDeferredMessages(sequenceNumber); - if (!deferredMsg) { - throw "No message received for sequence number"; - } - should.equal(deferredMsg.body, testMessages.body, "MessageBody is different than expected"); - should.equal( - deferredMsg.messageId, - testMessages.messageId, - "MessageId is different than expected" - ); - should.equal(deferredMsg.deliveryCount, 1, "DeliveryCount is different than expected"); + it( + withSessionTestClientType + ": Multiple abandons until maxDeliveryCount.", + async function(): Promise { + await beforeEachTest(withSessionTestClientType); + await testAbandonMsgsTillMaxDeliveryCount(); + } + ); - await deferredMsg.complete(); + async function testDefer(): Promise { + const testMessages = entityNames.usesSessions + ? TestMessage.getSessionSample() + : TestMessage.getSample(); + const msg = await sendReceiveMsg(testMessages); - await testPeekMsgsLength(receiver, 0); + if (!msg.sequenceNumber) { + throw "Sequence Number can not be null"; } + const sequenceNumber = msg.sequenceNumber; + await msg.defer(); - it("Partitioned Queue: defer() moves message to deferred queue", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedQueue); - await testDefer(); - }); - - it("Partitioned Subscription: defer() moves message to deferred queue", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedSubscription); - await testDefer(); - }); + const [deferredMsg] = await receiver.receiveDeferredMessages(sequenceNumber); + if (!deferredMsg) { + throw "No message received for sequence number"; + } + should.equal(deferredMsg.body, testMessages.body, "MessageBody is different than expected"); + should.equal( + deferredMsg.messageId, + testMessages.messageId, + "MessageId is different than expected" + ); + should.equal(deferredMsg.deliveryCount, 1, "DeliveryCount is different than expected"); - it("Partitioned Queue with Sessions: defer() moves message to deferred queue", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedQueueWithSessions); - await testDefer(true); - }); + await deferredMsg.complete(); - it("Partitioned Subscription with Sessions: defer() moves message to deferred queue", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedSubscriptionWithSessions); - await testDefer(true); - }); + await testPeekMsgsLength(receiver, 0); + } - it("Unpartitioned Queue: defer() moves message to deferred queue", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedQueue); + it( + noSessionTestClientType + ": defer() moves message to deferred queue", + async function(): Promise { + await beforeEachTest(noSessionTestClientType); await testDefer(); - }); + } + ); - it("Unpartitioned Subscription: defer() moves message to deferred queue", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedSubscription); + it( + withSessionTestClientType + ": defer() moves message to deferred queue", + async function(): Promise { + await beforeEachTest(withSessionTestClientType); await testDefer(); - }); - - it("Unpartitioned Queue with Sessions: defer() moves message to deferred queue", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedQueueWithSessions); - await testDefer(true); - }); - - it("Unpartitioned Subscription with Sessions: defer() moves message to deferred queue", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedSubscriptionWithSessions); - await testDefer(true); - }); - - async function testDeadletter(useSessions?: boolean): Promise { - const testMessages = useSessions ? TestMessage.getSessionSample() : TestMessage.getSample(); - const msg = await sendReceiveMsg(testMessages); - await msg.deadLetter(); - - await testPeekMsgsLength(receiver, 0); + } + ); - const deadLetterMsgsBatch = await deadLetterReceiver.receiveMessages(1); + async function testDeadletter(): Promise { + const testMessages = entityNames.usesSessions + ? TestMessage.getSessionSample() + : TestMessage.getSample(); + const msg = await sendReceiveMsg(testMessages); + await msg.deadLetter(); - should.equal( - Array.isArray(deadLetterMsgsBatch), - true, - "`ReceivedMessages` from Deadletter is not an array" - ); - should.equal(deadLetterMsgsBatch.length, 1, "Unexpected number of messages"); - should.equal( - deadLetterMsgsBatch[0].body, - testMessages.body, - "MessageBody is different than expected" - ); - should.equal( - deadLetterMsgsBatch[0].messageId, - testMessages.messageId, - "MessageId is different than expected" - ); + await testPeekMsgsLength(receiver, 0); - await deadLetterMsgsBatch[0].complete(); + const deadLetterMsgsBatch = await deadLetterReceiver.receiveMessages(1); - await testPeekMsgsLength(deadLetterReceiver, 0); - } + should.equal( + Array.isArray(deadLetterMsgsBatch), + true, + "`ReceivedMessages` from Deadletter is not an array" + ); + should.equal(deadLetterMsgsBatch.length, 1, "Unexpected number of messages"); + should.equal( + deadLetterMsgsBatch[0].body, + testMessages.body, + "MessageBody is different than expected" + ); + should.equal( + deadLetterMsgsBatch[0].messageId, + testMessages.messageId, + "MessageId is different than expected" + ); - it("Partitioned Queue: deadLetter() moves message to deadletter queue", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedQueue); - await testDeadletter(); - }); + await deadLetterMsgsBatch[0].complete(); - it("Partitioned Subscription: deadLetter() moves message to deadletter queue", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedSubscription); - await testDeadletter(); - }); + await testPeekMsgsLength(deadLetterReceiver, 0); + } - it("Unpartitioned Queue: deadLetter() moves message to deadletter queue", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedQueue); + it( + noSessionTestClientType + ": deadLetter() moves message to deadletter queue", + async function(): Promise { + await beforeEachTest(noSessionTestClientType); await testDeadletter(); - }); + } + ); - it("Unpartitioned Subscription: deadLetter() moves message to deadletter queue", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedSubscription); + it( + withSessionTestClientType + ": deadLetter() moves message to deadletter queue", + async function(): Promise { + await beforeEachTest(withSessionTestClientType); await testDeadletter(); - }); - - it("Partitioned Queue with Sessions: deadLetter() moves message to deadletter queue", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedQueueWithSessions); - await testDeadletter(true); - }); + } + ); +}); - it("Partitioned Subscription with Sessions: deadLetter() moves message to deadletter queue", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedSubscriptionWithSessions); - await testDeadletter(true); - }); +describe("Batch Receiver - Settle deadlettered message", function(): void { + before(() => { + serviceBusClient = createServiceBusClientForTests(); + }); - it("Unpartitioned Queue with Sessions: deadLetter() moves message to deadletter queue", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedQueueWithSessions); - await testDeadletter(true); - }); + after(() => { + return serviceBusClient.test.after(); + }); - it("Unpartitioned Subscription with Sessions: deadLetter() moves message to deadletter queue", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedSubscriptionWithSessions); - await testDeadletter(true); - }); + afterEach(async () => { + await afterEachTest(); }); - describe("Batch Receiver - Settle deadlettered message", function(): void { - afterEach(async () => { - await afterEachTest(); - }); + async function deadLetterMessage( + testMessage: ServiceBusMessage + ): Promise { + await sender.sendMessages(testMessage); + const batch = await receiver.receiveMessages(1); - async function deadLetterMessage( - testMessage: ServiceBusMessage - ): Promise { - await sender.sendMessages(testMessage); - const batch = await receiver.receiveMessages(1); + should.equal(batch.length, 1, "Unexpected number of messages"); + should.equal(batch[0].body, testMessage.body, "MessageBody is different than expected"); + should.equal(batch[0].messageId, testMessage.messageId, "MessageId is different than expected"); + should.equal(batch[0].deliveryCount, 0, "DeliveryCount is different than expected"); - should.equal(batch.length, 1, "Unexpected number of messages"); - should.equal(batch[0].body, testMessage.body, "MessageBody is different than expected"); - should.equal( - batch[0].messageId, - testMessage.messageId, - "MessageId is different than expected" - ); - should.equal(batch[0].deliveryCount, 0, "DeliveryCount is different than expected"); + await batch[0].deadLetter(); - await batch[0].deadLetter(); + await testPeekMsgsLength(receiver, 0); - await testPeekMsgsLength(receiver, 0); + const deadLetterMsgsBatch = await deadLetterReceiver.receiveMessages(1); - const deadLetterMsgsBatch = await deadLetterReceiver.receiveMessages(1); + should.equal(deadLetterMsgsBatch.length, 1, "Unexpected number of messages"); + should.equal( + deadLetterMsgsBatch[0].body, + testMessage.body, + "MessageBody is different than expected" + ); + should.equal( + deadLetterMsgsBatch[0].messageId, + testMessage.messageId, + "MessageId is different than expected" + ); + should.equal( + deadLetterMsgsBatch[0].deliveryCount, + 0, + "DeliveryCount is different than expected" + ); - should.equal(deadLetterMsgsBatch.length, 1, "Unexpected number of messages"); - should.equal( - deadLetterMsgsBatch[0].body, - testMessage.body, - "MessageBody is different than expected" - ); - should.equal( - deadLetterMsgsBatch[0].messageId, - testMessage.messageId, - "MessageId is different than expected" - ); - should.equal( - deadLetterMsgsBatch[0].deliveryCount, - 0, - "DeliveryCount is different than expected" - ); + return deadLetterMsgsBatch[0]; + } - return deadLetterMsgsBatch[0]; - } + async function completeDeadLetteredMessage( + testMessage: ServiceBusMessage, + deadletterClient: Receiver, + expectedDeliverCount: number + ): Promise { + const deadLetterMsgsBatch = await deadLetterReceiver.receiveMessages(1); - async function completeDeadLetteredMessage( - testMessage: ServiceBusMessage, - deadletterClient: Receiver, - expectedDeliverCount: number - ): Promise { - const deadLetterMsgsBatch = await deadLetterReceiver.receiveMessages(1); + should.equal(deadLetterMsgsBatch.length, 1, "Unexpected number of messages"); + should.equal( + deadLetterMsgsBatch[0].body, + testMessage.body, + "MessageBody is different than expected" + ); + should.equal( + deadLetterMsgsBatch[0].messageId, + testMessage.messageId, + "MessageId is different than expected" + ); + should.equal( + deadLetterMsgsBatch[0].deliveryCount, + expectedDeliverCount, + "DeliveryCount is different than expected" + ); - should.equal(deadLetterMsgsBatch.length, 1, "Unexpected number of messages"); - should.equal( - deadLetterMsgsBatch[0].body, - testMessage.body, - "MessageBody is different than expected" - ); - should.equal( - deadLetterMsgsBatch[0].messageId, - testMessage.messageId, - "MessageId is different than expected" - ); - should.equal( - deadLetterMsgsBatch[0].deliveryCount, - expectedDeliverCount, - "DeliveryCount is different than expected" - ); + await deadLetterMsgsBatch[0].complete(); + await testPeekMsgsLength(deadletterClient, 0); + } - await deadLetterMsgsBatch[0].complete(); - await testPeekMsgsLength(deadletterClient, 0); - } + async function testDeadletter(): Promise { + const testMessage = entityNames.usesSessions + ? TestMessage.getSessionSample() + : TestMessage.getSessionSample(); + const deadLetterMsg = await deadLetterMessage(testMessage); + let errorWasThrown = false; - async function testDeadletter(testMessage: ServiceBusMessage): Promise { - const deadLetterMsg = await deadLetterMessage(testMessage); + await deadLetterMsg.deadLetter().catch((err) => { + should.equal(err.code, "InvalidOperationError", "Error code is different than expected"); + errorWasThrown = true; + }); - await deadLetterMsg.deadLetter().catch((err) => { - should.equal(err.code, "InvalidOperationError", "Error code is different than expected"); - errorWasThrown = true; - }); + should.equal(errorWasThrown, true, "Error thrown flag must be true"); - should.equal(errorWasThrown, true, "Error thrown flag must be true"); + await completeDeadLetteredMessage(testMessage, deadLetterReceiver, 0); + } - await completeDeadLetteredMessage(testMessage, deadLetterReceiver, 0); + it( + anyRandomTestClientType + ": Throws error when dead lettering a dead lettered message", + async function(): Promise { + await beforeEachTest(anyRandomTestClientType); + await testDeadletter(); } + ); - it("Partitioned Queue: Throws error when dead lettering a dead lettered message", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedQueue); - await testDeadletter(TestMessage.getSample()); - }); - - it("Partitioned Subscription: Throws error when dead lettering a dead lettered message", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedSubscription); - await testDeadletter(TestMessage.getSample()); - }); - - it("Unpartitioned Queue: Throws error when dead lettering a dead lettered message", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedQueue); - await testDeadletter(TestMessage.getSample()); - }); - - it("Unpartitioned Subscription: Throws error when dead lettering a dead lettered message", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedSubscription); - await testDeadletter(TestMessage.getSample()); - }); + async function testAbandon(): Promise { + const testMessage = entityNames.usesSessions + ? TestMessage.getSessionSample() + : TestMessage.getSessionSample(); + const deadLetterMsg = await deadLetterMessage(testMessage); - async function testAbandon(testMessage: ServiceBusMessage): Promise { - const deadLetterMsg = await deadLetterMessage(testMessage); + await deadLetterMsg.abandon(); - await deadLetterMsg.abandon(); + await completeDeadLetteredMessage(testMessage, deadLetterReceiver, 0); + } - await completeDeadLetteredMessage(testMessage, deadLetterReceiver, 0); + it( + anyRandomTestClientType + ": Abandon a message received from dead letter queue", + async function(): Promise { + await beforeEachTest(anyRandomTestClientType); + await testAbandon(); } + ); - it("Partitioned Queue: Abandon a message received from dead letter queue", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedQueue); - await testAbandon(TestMessage.getSample()); - }); - - it("Partitioned Subscription: Abandon a message received from dead letter queue", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedSubscription); - await testAbandon(TestMessage.getSample()); - }); - - it("Unpartitioned Queue: Abandon a message received from dead letter queue", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedQueue); - await testAbandon(TestMessage.getSample()); - }); + async function testDefer(): Promise { + const testMessage = entityNames.usesSessions + ? TestMessage.getSessionSample() + : TestMessage.getSessionSample(); + const deadLetterMsg = await deadLetterMessage(testMessage); - it("Unpartitioned Subscription: Abandon a message received from dead letter queue", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedSubscription); - await testAbandon(TestMessage.getSample()); - }); + if (!deadLetterMsg.sequenceNumber) { + throw "Sequence Number can not be null"; + } - async function testDefer(testMessage: ServiceBusMessage): Promise { - const deadLetterMsg = await deadLetterMessage(testMessage); + const sequenceNumber = deadLetterMsg.sequenceNumber; + await deadLetterMsg.defer(); - if (!deadLetterMsg.sequenceNumber) { - throw "Sequence Number can not be null"; - } - - const sequenceNumber = deadLetterMsg.sequenceNumber; - await deadLetterMsg.defer(); + const [deferredMsg] = await deadLetterReceiver.receiveDeferredMessages(sequenceNumber); + if (!deferredMsg) { + throw "No message received for sequence number"; + } + should.equal(deferredMsg.body, testMessage.body, "MessageBody is different than expected"); + should.equal( + deferredMsg.messageId, + testMessage.messageId, + "MessageId is different than expected" + ); - const [deferredMsg] = await deadLetterReceiver.receiveDeferredMessages(sequenceNumber); - if (!deferredMsg) { - throw "No message received for sequence number"; - } - should.equal(deferredMsg.body, testMessage.body, "MessageBody is different than expected"); - should.equal( - deferredMsg.messageId, - testMessage.messageId, - "MessageId is different than expected" - ); + await deferredMsg.complete(); - await deferredMsg.complete(); + await testPeekMsgsLength(receiver, 0); - await testPeekMsgsLength(receiver, 0); + await testPeekMsgsLength(deadLetterReceiver, 0); + } - await testPeekMsgsLength(deadLetterReceiver, 0); + // TODO: The below test for session enabled entity needs a higher timeout most of the time + // The rest of the time, it fails with "The service was unable to process the request; please retry the operation.". + // So, testing for non sessions at the moment, more investigation needed from service side. + it( + noSessionTestClientType + ": Defer a message received from dead letter queue", + async function(): Promise { + await beforeEachTest(noSessionTestClientType); + await testDefer(); } + ); +}); - it("Partitioned Queue: Defer a message received from dead letter queue", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedQueue); - await testDefer(TestMessage.getSample()); - }); - - it("Partitioned Subscription: Defer a message received from dead letter queue", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedSubscription); - await testDefer(TestMessage.getSample()); - }); +describe("Batch Receiver - Multiple Receiver Operations", function(): void { + before(() => { + serviceBusClient = createServiceBusClientForTests(); + }); - it("Unpartitioned Queue: Defer a message received from dead letter queue", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedQueue); - await testDefer(TestMessage.getSample()); - }); + after(() => { + return serviceBusClient.test.after(); + }); - it("Unpartitioned Subscription: Defer a message received from dead letter queue", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedSubscription); - await testDefer(TestMessage.getSample()); - }); + afterEach(async () => { + await afterEachTest(); }); - describe("Batch Receiver - Multiple Receiver Operations", function(): void { - afterEach(async () => { - await afterEachTest(); - }); + // We use an empty queue/topic here so that the first receiveMessages call takes time to return + async function testParallelReceiveCalls(): Promise { + const firstBatchPromise = receiver.receiveMessages(1, { maxWaitTimeInMs: 10000 }); + await delay(5000); - // We use an empty queue/topic here so that the first receiveMessages call takes time to return - async function testParallelReceiveCalls(useSessions?: boolean): Promise { - const firstBatchPromise = receiver.receiveMessages(1, { maxWaitTimeInMs: 10000 }); - await delay(5000); + let errorMessage; + const expectedErrorMessage = getAlreadyReceivingErrorMsg( + receiver.entityPath, + entityNames.usesSessions ? TestMessage.sessionId : undefined + ); - let errorMessage; - const expectedErrorMessage = getAlreadyReceivingErrorMsg( - receiver.entityPath, - useSessions ? TestMessage.sessionId : undefined - ); + try { + await receiver.receiveMessages(1); + } catch (err) { + errorMessage = err && err.message; + } + should.equal( + errorMessage, + expectedErrorMessage, + "Unexpected error message for receiveMessages" + ); - try { - await receiver.receiveMessages(1); - } catch (err) { - errorMessage = err && err.message; - } - should.equal( - errorMessage, - expectedErrorMessage, - "Unexpected error message for receiveMessages" - ); + let unexpectedError; + try { + receiver.subscribe({ + async processMessage(): Promise { + // process message here - it's basically a ServiceBusMessage minus any settlement related methods + }, + async processError(err: Error): Promise { + unexpectedError = err; + } + }); + } catch (err) { + errorMessage = err && err.message; + } + should.equal( + errorMessage, + expectedErrorMessage, + "Unexpected error message for registerMessageHandler" + ); + should.equal( + unexpectedError, + undefined, + "Unexpected error found in errorHandler for registerMessageHandler" + ); - let unexpectedError; - try { - receiver.subscribe({ - async processMessage(): Promise { - // process message here - it's basically a ServiceBusMessage minus any settlement related methods - }, - async processError(err: Error): Promise { - unexpectedError = err; - } - }); - } catch (err) { - errorMessage = err && err.message; - } - should.equal( - errorMessage, - expectedErrorMessage, - "Unexpected error message for registerMessageHandler" - ); - should.equal( - unexpectedError, - undefined, - "Unexpected error found in errorHandler for registerMessageHandler" - ); + await firstBatchPromise; + } - await firstBatchPromise; + it( + noSessionTestClientType + + ": Throws error when ReceiveBatch is called while the previous call is not done", + async function(): Promise { + await beforeEachTest(noSessionTestClientType); + await testParallelReceiveCalls(); } + ); - it("Unpartitioned Queue: Throws error when ReceiveBatch is called while the previous call is not done", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedQueue); + it( + withSessionTestClientType + + ": Throws error when ReceiveBatch is called while the previous call is not done", + async function(): Promise { + await beforeEachTest(withSessionTestClientType); await testParallelReceiveCalls(); - }); - - it("Unpartitioned Queue with Sessions: Throws error when ReceiveBatch is called while the previous call is not done", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedQueueWithSessions); - await testParallelReceiveCalls(true); - }); + } + ); + + const messages: ServiceBusMessage[] = [ + { + body: "hello1", + messageId: `test message ${Math.random()}`, + partitionKey: "dummy" // partitionKey is only for partitioned queue/subscrption, Unpartitioned queue/subscrption do not care about partitionKey. + }, + { + body: "hello2", + messageId: `test message ${Math.random()}`, + partitionKey: "dummy" // partitionKey is only for partitioned queue/subscrption, Unpartitioned queue/subscrption do not care about partitionKey. + } + ]; + const messageWithSessions: ServiceBusMessage[] = [ + { + body: "hello1", + messageId: `test message ${Math.random()}`, + sessionId: TestMessage.sessionId + }, + { + body: "hello2", + messageId: `test message ${Math.random()}`, + sessionId: TestMessage.sessionId + } + ]; + + // We test for mutilple receiveMessages specifically to ensure that batchingRecevier on a client is reused + // See https://github.com/Azure/azure-service-bus-node/issues/31 + async function testSequentialReceiveBatchCalls(): Promise { + const testMessages = entityNames.usesSessions ? messageWithSessions : messages; + const batchMessageToSend = await sender.createBatch(); + for (const message of testMessages) { + batchMessageToSend.tryAdd(message); + } + await sender.sendMessages(batchMessageToSend); + const msgs1 = await receiver.receiveMessages(1); + const msgs2 = await receiver.receiveMessages(1); - const messages: ServiceBusMessage[] = [ - { - body: "hello1", - messageId: `test message ${Math.random()}`, - partitionKey: "dummy" // partitionKey is only for partitioned queue/subscrption, Unpartitioned queue/subscrption do not care about partitionKey. - }, - { - body: "hello2", - messageId: `test message ${Math.random()}`, - partitionKey: "dummy" // partitionKey is only for partitioned queue/subscrption, Unpartitioned queue/subscrption do not care about partitionKey. - } - ]; - const messageWithSessions: ServiceBusMessage[] = [ - { - body: "hello1", - messageId: `test message ${Math.random()}`, - sessionId: TestMessage.sessionId - }, - { - body: "hello2", - messageId: `test message ${Math.random()}`, - sessionId: TestMessage.sessionId - } - ]; - - // We test for mutilple receiveMessages specifically to ensure that batchingRecevier on a client is reused - // See https://github.com/Azure/azure-service-bus-node/issues/31 - async function testSequentialReceiveBatchCalls(useSessions?: boolean): Promise { - const testMessages = useSessions ? messageWithSessions : messages; - const batchMessageToSend = await sender.createBatch(); - for (const message of testMessages) { - batchMessageToSend.tryAdd(message); - } - await sender.sendMessages(batchMessageToSend); - const msgs1 = await receiver.receiveMessages(1); - const msgs2 = await receiver.receiveMessages(1); + // Results are checked after both receiveMessages are done to ensure that the second call doesnt + // affect the result from the first one. + should.equal(Array.isArray(msgs1), true, "`ReceivedMessages` is not an array"); + should.equal(msgs1.length, 1, "Unexpected number of messages"); - // Results are checked after both receiveMessages are done to ensure that the second call doesnt - // affect the result from the first one. - should.equal(Array.isArray(msgs1), true, "`ReceivedMessages` is not an array"); - should.equal(msgs1.length, 1, "Unexpected number of messages"); + should.equal(Array.isArray(msgs2), true, "`ReceivedMessages` is not an array"); + should.equal(msgs2.length, 1, "Unexpected number of messages"); - should.equal(Array.isArray(msgs2), true, "`ReceivedMessages` is not an array"); - should.equal(msgs2.length, 1, "Unexpected number of messages"); + should.equal( + testMessages.some((x) => x.messageId === msgs1[0].messageId), + true, + "MessageId is different than expected" + ); + should.equal( + testMessages.some((x) => x.messageId === msgs2[0].messageId), + true, + "MessageId is different than expected" + ); - should.equal( - testMessages.some((x) => x.messageId === msgs1[0].messageId), - true, - "MessageId is different than expected" - ); - should.equal( - testMessages.some((x) => x.messageId === msgs2[0].messageId), - true, - "MessageId is different than expected" - ); + await msgs1[0].complete(); + await msgs2[0].complete(); + } - await msgs1[0].complete(); - await msgs2[0].complete(); + it( + noSessionTestClientType + ": Multiple sequential receiveMessages calls", + async function(): Promise { + await beforeEachTest(noSessionTestClientType); + await testSequentialReceiveBatchCalls(); } + ); - it("Unpartitioned Queue: Multiple sequential receiveMessages calls", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedQueue); + it( + withSessionTestClientType + ": Multiple sequential receiveMessages calls", + async function(): Promise { + await beforeEachTest(withSessionTestClientType); await testSequentialReceiveBatchCalls(); - }); + } + ); +}); - it("Unpartitioned Queue with Sessions: Multiple sequential receiveMessages calls", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedQueueWithSessions); - await testSequentialReceiveBatchCalls(true); - }); +describe("Batch Receiver - Others", function(): void { + before(() => { + serviceBusClient = createServiceBusClientForTests(); }); - describe("Batch Receiver - Others", function(): void { - afterEach(async () => { - await afterEachTest(); - }); - - async function testNoSettlement(useSessions?: boolean): Promise { - const testMessages = useSessions ? TestMessage.getSessionSample() : TestMessage.getSample(); - await sender.sendMessages(testMessages); + after(() => { + return serviceBusClient.test.after(); + }); - let batch = await receiver.receiveMessages(1); + afterEach(async () => { + await afterEachTest(); + }); - should.equal(batch.length, 1, "Unexpected number of messages"); - should.equal(batch[0].deliveryCount, 0, "DeliveryCount is different than expected"); - should.equal( - batch[0].messageId, - testMessages.messageId, - "MessageId is different than expected" - ); + async function testNoSettlement(): Promise { + const testMessages = entityNames.usesSessions + ? TestMessage.getSessionSample() + : TestMessage.getSample(); + await sender.sendMessages(testMessages); + + // If using sessions, we need a receiver with lock renewal disabled so that + // the message lands back in the queue/subscription to be picked up again. + if (entityNames.usesSessions) { + await receiver.close(); + receiver = await serviceBusClient.test.getSessionPeekLockReceiver(entityNames, { + sessionId: testMessages.sessionId, + autoRenewLockDurationInMs: 0 + }); + } - await testPeekMsgsLength(receiver, 1); + let batch = await receiver.receiveMessages(1); - batch = await receiver.receiveMessages(1); + should.equal(batch.length, 1, "Unexpected number of messages"); + should.equal(batch[0].deliveryCount, 0, "DeliveryCount is different than expected"); + should.equal( + batch[0].messageId, + testMessages.messageId, + "MessageId is different than expected" + ); - should.equal(batch.length, 1, "Unexpected number of messages"); - should.equal(batch[0].deliveryCount, 1, "DeliveryCount is different than expected"); - should.equal( - batch[0].messageId, - testMessages.messageId, - "MessageId is different than expected" - ); + await testPeekMsgsLength(receiver, 1); - await batch[0].complete(); + // If using sessions wait to lose the lock, then use a new receiver to get the message + // landed back in the queue/subscription. + if (entityNames.usesSessions) { + await delay(31000); + receiver = await serviceBusClient.test.getSessionPeekLockReceiver(entityNames, { + sessionId: testMessages.sessionId, + autoRenewLockDurationInMs: 0 + }); } - it("Partitioned Queue: No settlement of the message is retained with incremented deliveryCount", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedQueue); - await testNoSettlement(); - }); + batch = await receiver.receiveMessages(1); - it("Partitioned Subscription: No settlement of the message is retained with incremented deliveryCount", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedSubscription); - await testNoSettlement(); - }); + should.equal(batch.length, 1, "Unexpected number of messages"); + should.equal(batch[0].deliveryCount, 1, "DeliveryCount is different than expected"); + should.equal( + batch[0].messageId, + testMessages.messageId, + "MessageId is different than expected" + ); - it("Unpartitioned Queue: No settlement of the message is retained with incremented deliveryCount", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedQueue); - await testNoSettlement(); - }); + await batch[0].complete(); + } - it("Unpartitioned Subscription: No settlement of the message is retained with incremented deliveryCount", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedSubscription); + it( + noSessionTestClientType + + ": No settlement of the message is retained with incremented deliveryCount", + async function(): Promise { + await beforeEachTest(noSessionTestClientType); await testNoSettlement(); - }); - - async function testAskForMore(useSessions?: boolean): Promise { - const testMessages = useSessions ? TestMessage.getSessionSample() : TestMessage.getSample(); - await sender.sendMessages(testMessages); - const batch = await receiver.receiveMessages(2); - - should.equal(batch.length, 1, "Unexpected number of messages"); - should.equal(batch[0].body, testMessages.body, "MessageBody is different than expected"); - should.equal( - batch[0].messageId, - testMessages.messageId, - "MessageId is different than expected" - ); - - await batch[0].complete(); + } + ); - await testPeekMsgsLength(receiver, 0); + it( + withSessionTestClientType + + ": No settlement of the message is retained with incremented deliveryCount", + async function(): Promise { + await beforeEachTest(withSessionTestClientType); + await testNoSettlement(); } + ); - it("Partitioned Queue: Receive n messages but queue only has m messages, where m < n", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedQueue); + async function testAskForMore(): Promise { + const testMessages = entityNames.usesSessions + ? TestMessage.getSessionSample() + : TestMessage.getSample(); + await sender.sendMessages(testMessages); + const batch = await receiver.receiveMessages(2); - await testAskForMore(); - }); + should.equal(batch.length, 1, "Unexpected number of messages"); + should.equal(batch[0].body, testMessages.body, "MessageBody is different than expected"); + should.equal( + batch[0].messageId, + testMessages.messageId, + "MessageId is different than expected" + ); - it("Partitioned Subscription: Receive n messages but subscription only has m messages, where m < n", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedSubscription); + await batch[0].complete(); - await testAskForMore(); - }); + await testPeekMsgsLength(receiver, 0); + } - it("Unpartitioned Queue: Receive n messages but queue only has m messages, where m < n ", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedQueue); + it( + noSessionTestClientType + ": Receive n messages but queue only has m messages, where m < n", + async function(): Promise { + await beforeEachTest(noSessionTestClientType); await testAskForMore(); - }); + } + ); - it("Unpartitioned Subscription: Receive n messages but subscription only has m messages, where m < n", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedSubscription); + it( + withSessionTestClientType + + ": Receive n messages but subscription only has m messages, where m < n", + async function(): Promise { + await beforeEachTest(withSessionTestClientType); await testAskForMore(); - }); - - it("Partitioned Queue with Sessions: Receive n messages but queue only has m messages, where m < n", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedQueueWithSessions); - await testAskForMore(true); - }); - - it("Partitioned Subscription with Sessions: Receive n messages but subscription only has m messages, where m < n", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedSubscriptionWithSessions); - await testAskForMore(true); - }); - - it("Unpartitioned Queue with Sessions: Receive n messages but queue only has m messages, where m < n", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedQueueWithSessions); - await testAskForMore(true); - }); + } + ); - it("Unpartitioned Subscription with Sessions: Receive n messages but subscription only has m messages, where m < n", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedSubscriptionWithSessions); - await testAskForMore(true); - }); - }); + it( + noSessionTestClientType + ": Abort receiveDeferredMessages request on the receiver", + async function(): Promise { + await beforeEachTest(noSessionTestClientType); + const controller = new AbortController(); + setTimeout(() => controller.abort(), 1); + try { + await receiver.receiveDeferredMessages([Long.ZERO], { + abortSignal: controller.signal + }); + throw new Error(`Test failure`); + } catch (err) { + err.message.should.equal( + "The receiveDeferredMessages operation has been cancelled by the user." + ); + } + } + ); - describe("Cancel operations on the receiver", function(): void { - it("Abort receiveDeferredMessages request on the receiver", async function(): Promise { - await beforeEachTest(TestClientType.PartitionedQueueWithSessions); + it( + withSessionTestClientType + ": Abort receiveDeferredMessages request on the receiver", + async function(): Promise { + await beforeEachTest(withSessionTestClientType); const controller = new AbortController(); setTimeout(() => controller.abort(), 1); try { @@ -1048,21 +846,20 @@ describe("batchReceiver", () => { "The receiveDeferredMessages operation has been cancelled by the user." ); } - }); - }); + } + ); }); -describe("Batching - disconnects", function(): void { +describe(noSessionTestClientType + ": Batch Receiver - disconnects", function(): void { let serviceBusClient: ServiceBusClientForTests; let sender: Sender; let receiver: Receiver | Receiver; async function beforeEachTest( - entityType: TestClientType, receiveMode: "peekLock" | "receiveAndDelete" = "peekLock" ): Promise { serviceBusClient = createServiceBusClientForTests(); - const entityNames = await serviceBusClient.test.createTestEntities(entityType); + const entityNames = await serviceBusClient.test.createTestEntities(noSessionTestClientType); if (receiveMode == "receiveAndDelete") { receiver = await serviceBusClient.test.getReceiveAndDeleteReceiver(entityNames); } else { @@ -1083,7 +880,7 @@ describe("Batching - disconnects", function(): void { it("can receive and settle messages after a disconnect", async function(): Promise { // Create the sender and receiver. - await beforeEachTest(TestClientType.UnpartitionedQueue); + await beforeEachTest(); // Send a message so we can be sure when the receiver is open and active. await sender.sendMessages(TestMessage.getSample()); @@ -1135,7 +932,7 @@ describe("Batching - disconnects", function(): void { void > { // Create the sender and receiver. - await beforeEachTest(TestClientType.UnpartitionedQueue, "receiveAndDelete"); + await beforeEachTest("receiveAndDelete"); // The first time `receiveMessages` is called the receiver link is created. // The `receiver_drained` handler is only added after the link is created, @@ -1196,7 +993,7 @@ describe("Batching - disconnects", function(): void { it("throws an error if drain is in progress (peekLock)", async function(): Promise { // Create the sender and receiver. - await beforeEachTest(TestClientType.UnpartitionedQueue); + await beforeEachTest(); // The first time `receiveMessages` is called the receiver link is created. // The `receiver_drained` handler is only added after the link is created, @@ -1263,7 +1060,7 @@ describe("Batching - disconnects", function(): void { it("returns messages if receive in progress (receiveAndDelete)", async function(): Promise { // Create the sender and receiver. - await beforeEachTest(TestClientType.UnpartitionedQueue, "receiveAndDelete"); + await beforeEachTest("receiveAndDelete"); // The first time `receiveMessages` is called the receiver link is created. // The `receiver_drained` handler is only added after the link is created, @@ -1304,7 +1101,7 @@ describe("Batching - disconnects", function(): void { it("throws an error if receive is in progress (peekLock)", async function(): Promise { // Create the sender and receiver. - await beforeEachTest(TestClientType.UnpartitionedQueue); + await beforeEachTest(); // The first time `receiveMessages` is called the receiver link is created. // The `receiver_drained` handler is only added after the link is created, diff --git a/sdk/servicebus/service-bus/test/connectionManagement.spec.ts b/sdk/servicebus/service-bus/test/connectionManagement.spec.ts index 68de4fc3c996..158adf267dcf 100644 --- a/sdk/servicebus/service-bus/test/connectionManagement.spec.ts +++ b/sdk/servicebus/service-bus/test/connectionManagement.spec.ts @@ -112,7 +112,7 @@ describe("controlled connection initialization", () => { } catch (err) { assert.equal( err.message, - `The sender for "${senderEntityPath}" has been closed and can no longer be used. Please create a new sender using the "getSender" method on the ServiceBusClient.` + `The sender for "${senderEntityPath}" has been closed and can no longer be used. Please create a new sender using the "createSender" method on the ServiceBusClient.` ); } }); diff --git a/sdk/servicebus/service-bus/test/deferredMessage.spec.ts b/sdk/servicebus/service-bus/test/deferredMessage.spec.ts index 9b6924c13f3d..b8bfc9472a9f 100644 --- a/sdk/servicebus/service-bus/test/deferredMessage.spec.ts +++ b/sdk/servicebus/service-bus/test/deferredMessage.spec.ts @@ -7,17 +7,27 @@ import chaiAsPromised from "chai-as-promised"; chai.use(chaiAsPromised); import { ServiceBusMessage } from "../src"; import { TestClientType, TestMessage } from "./utils/testUtils"; -import { createServiceBusClientForTests, testPeekMsgsLength } from "./utils/testutils2"; +import { + createServiceBusClientForTests, + testPeekMsgsLength, + EntityName, + getRandomTestClientTypeWithSessions, + getRandomTestClientTypeWithNoSessions +} from "./utils/testutils2"; import { Receiver } from "../src/receivers/receiver"; import { Sender } from "../src/sender"; import { ReceivedMessageWithLock } from "../src/serviceBusMessage"; -describe("deferred messages", () => { +describe("Deferred Messages", () => { let serviceBusClient: ReturnType; let sender: Sender; let receiver: Receiver; let deadLetterReceiver: Receiver; + let entityNames: EntityName; + const noSessionTestClientType = getRandomTestClientTypeWithNoSessions(); + const withSessionTestClientType = getRandomTestClientTypeWithSessions(); + before(() => { serviceBusClient = createServiceBusClientForTests(); }); @@ -27,7 +37,7 @@ describe("deferred messages", () => { }); async function beforeEachTest(entityType: TestClientType): Promise { - const entityNames = await serviceBusClient.test.createTestEntities(entityType); + entityNames = await serviceBusClient.test.createTestEntities(entityType); receiver = await serviceBusClient.test.getPeekLockReceiver(entityNames); @@ -38,9 +48,9 @@ describe("deferred messages", () => { deadLetterReceiver = serviceBusClient.test.createDeadLetterReceiver(entityNames); } - async function afterEachTest(): Promise { + afterEach(async () => { await serviceBusClient.test.afterEach(); - } + }); /** * Sends, defers, receives and then returns a test message @@ -116,275 +126,129 @@ describe("deferred messages", () => { await testPeekMsgsLength(receiver, 0); } - describe("Abandon/Defer/Deadletter deferred message", function(): void { - afterEach(async () => { - await afterEachTest(); - }); - - async function testAbandon(useSessions?: boolean): Promise { - const testMessages = useSessions ? TestMessage.getSessionSample() : TestMessage.getSample(); - const deferredMsg = await deferMessage(testMessages, true); - const sequenceNumber = deferredMsg.sequenceNumber; - if (!sequenceNumber) { - throw "Sequence Number can not be null"; - } - await deferredMsg.abandon(); - await completeDeferredMessage(sequenceNumber, 2, testMessages); + async function testAbandon(): Promise { + const testMessages = entityNames.usesSessions + ? TestMessage.getSessionSample() + : TestMessage.getSample(); + const deferredMsg = await deferMessage(testMessages, true); + const sequenceNumber = deferredMsg.sequenceNumber; + if (!sequenceNumber) { + throw "Sequence Number can not be null"; } + await deferredMsg.abandon(); + await completeDeferredMessage(sequenceNumber, 2, testMessages); + } - it("Partitioned Queue: Abandoning a deferred message puts it back to the deferred queue.", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedQueue); - await testAbandon(); - }); - - it("Partitioned Subscription: Abandoning a deferred message puts it back to the deferred queue.", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedSubscription); - await testAbandon(); - }); - - it("Partitioned Queue with Sessions: Abandoning a deferred message puts it back to the deferred queue.", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedQueueWithSessions); - await testAbandon(true); - }); - - it("Partitioned Subscription with Sessions: Abandoning a deferred message puts it back to the deferred queue.", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedSubscriptionWithSessions); - await testAbandon(true); - }); - - it("Unpartitioned Queue: Abandoning a deferred message puts it back to the deferred queue.", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedQueue); + it( + noSessionTestClientType + ": Abandoning a deferred message puts it back to the deferred queue.", + async function(): Promise { + await beforeEachTest(noSessionTestClientType); await testAbandon(); - }); + } + ); - it("Unpartitioned Subscription: Abandoning a deferred message puts it back to the deferred queue.", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedSubscription); + it( + withSessionTestClientType + + ": Abandoning a deferred message puts it back to the deferred queue.", + async function(): Promise { + await beforeEachTest(withSessionTestClientType); await testAbandon(); - }); - - it("Unpartitioned Queue with Sessions:: Abandoning a deferred message puts it back to the deferred queue.", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedQueueWithSessions); - await testAbandon(true); - }); - - it("Unpartitioned Subscription with Sessions:: Abandoning a deferred message puts it back to the deferred queue.", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedSubscriptionWithSessions); - await testAbandon(true); - }); - - async function testDefer(useSessions?: boolean): Promise { - const testMessages = useSessions ? TestMessage.getSessionSample() : TestMessage.getSample(); - const deferredMsg = await deferMessage(testMessages, false); - const sequenceNumber = deferredMsg.sequenceNumber; - if (!sequenceNumber) { - throw "Sequence Number can not be null"; - } - await deferredMsg.defer(); - await completeDeferredMessage(sequenceNumber, 2, testMessages); } - - it("Partitioned Queue: Deferring a deferred message puts it back to the deferred queue.", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedQueue); - await testDefer(); - }); - - it("Partitioned Subscription: Deferring a deferred message puts it back to the deferred queue.", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedSubscription); - await testDefer(); - }); - - it("Partitioned Queue with Sessions: Deferring a deferred message puts it back to the deferred queue.", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedQueueWithSessions); - await testDefer(true); - }); - - it("Partitioned Subscription with Sessions: Deferring a deferred message puts it back to the deferred queue.", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedSubscriptionWithSessions); - await testDefer(true); - }); - - it("Unpartitioned Queue: Deferring a deferred message puts it back to the deferred queue.", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedQueue); + ); + + async function testDefer(): Promise { + const testMessages = entityNames.usesSessions + ? TestMessage.getSessionSample() + : TestMessage.getSample(); + const deferredMsg = await deferMessage(testMessages, false); + const sequenceNumber = deferredMsg.sequenceNumber; + if (!sequenceNumber) { + throw "Sequence Number can not be null"; + } + await deferredMsg.defer(); + await completeDeferredMessage(sequenceNumber, 2, testMessages); + } + it( + noSessionTestClientType + ": Deferring a deferred message puts it back to the deferred queue.", + async function(): Promise { + await beforeEachTest(noSessionTestClientType); await testDefer(); - }); + } + ); - it("Unpartitioned Subscription: Deferring a deferred message puts it back to the deferred queue.", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedSubscription); + it( + withSessionTestClientType + + ": Deferring a deferred message puts it back to the deferred queue.", + async function(): Promise { + await beforeEachTest(withSessionTestClientType); await testDefer(); - }); - - it("Unpartitioned Queue with Sessions: Deferring a deferred message puts it back to the deferred queue.", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedQueueWithSessions); - await testDefer(true); - }); - - it("Unpartitioned Subscription with Sessions: Deferring a deferred message puts it back to the deferred queue.", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedSubscriptionWithSessions); - await testDefer(true); - }); - - async function testDeadletter(useSessions?: boolean): Promise { - const testMessages = useSessions ? TestMessage.getSessionSample() : TestMessage.getSample(); - const deferredMsg = await deferMessage(testMessages, true); - - await deferredMsg.deadLetter(); - - await testPeekMsgsLength(receiver, 0); - - const deadLetterMsgs = await deadLetterReceiver.receiveMessages(1); - - should.equal(deadLetterMsgs.length, 1, "Unexpected number of messages"); - should.equal( - deadLetterMsgs[0].body, - testMessages.body, - "MessageBody is different than expected" - ); - should.equal(deadLetterMsgs[0].deliveryCount, 1, "DeliveryCount is different than expected"); - should.equal( - deadLetterMsgs[0].messageId, - testMessages.messageId, - "MessageId is different than expected" - ); - - await deadLetterMsgs[0].complete(); - - await testPeekMsgsLength(deadLetterReceiver, 0); } + ); - it("Partitioned Queue: Deadlettering a deferred message moves it to dead letter queue.", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedQueue); - await testDeadletter(); - }); + async function testDeadletter(): Promise { + const testMessages = entityNames.usesSessions + ? TestMessage.getSessionSample() + : TestMessage.getSample(); + const deferredMsg = await deferMessage(testMessages, true); - it("Partitioned Subscription: Deadlettering a deferred message moves it to dead letter queue.", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedSubscription); - await testDeadletter(); - }); - - it("Partitioned Queue with Sessions: Deadlettering a deferred message moves it to dead letter queue.", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedQueueWithSessions); - await testDeadletter(true); - }); - - it("Partitioned Subscription with Sessions: Deadlettering a deferred message moves it to dead letter queue.", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedSubscriptionWithSessions); - await testDeadletter(true); - }); - - it("Unpartitioned Queue: Deadlettering a deferred message moves it to dead letter queue.", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedQueue); - await testDeadletter(); - }); + await deferredMsg.deadLetter(); - it("Unpartitioned Subscription: Deadlettering a deferred message moves it to dead letter queue.", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedSubscription); - await testDeadletter(); - }); - - it("Unpartitioned Queue with Sessions: Deadlettering a deferred message moves it to dead letter queue.", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedQueueWithSessions); - await testDeadletter(true); - }); - - it("Unpartitioned Subscription with Sessions: Deadlettering a deferred message moves it to dead letter queue.", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedSubscriptionWithSessions); - await testDeadletter(true); - }); - }); + await testPeekMsgsLength(receiver, 0); + + const deadLetterMsgs = await deadLetterReceiver.receiveMessages(1); + + should.equal(deadLetterMsgs.length, 1, "Unexpected number of messages"); + should.equal( + deadLetterMsgs[0].body, + testMessages.body, + "MessageBody is different than expected" + ); + should.equal(deadLetterMsgs[0].deliveryCount, 1, "DeliveryCount is different than expected"); + should.equal( + deadLetterMsgs[0].messageId, + testMessages.messageId, + "MessageId is different than expected" + ); - describe("renewLock on a deferred message", function(): void { - async function testRenewlockAndDefer(): Promise { - const testMessages = TestMessage.getSample(); - const deferredMsg = await deferMessage(testMessages, false); - const sequenceNumber = deferredMsg.sequenceNumber; - if (!sequenceNumber) { - throw "Sequence Number can not be null"; - } - const lockedUntilBeforeRenewlock = deferredMsg.lockedUntilUtc; - const lockedUntilAfterRenewlock = await deferredMsg.renewLock(); - should.equal( - lockedUntilAfterRenewlock > lockedUntilBeforeRenewlock!, - true, - "MessageLock did not get renewed!" - ); - await deferredMsg.defer(); - await completeDeferredMessage(sequenceNumber, 2, testMessages); + await deadLetterMsgs[0].complete(); + + await testPeekMsgsLength(deadLetterReceiver, 0); + } + + it( + noSessionTestClientType + ": Deadlettering a deferred message moves it to dead letter queue.", + async function(): Promise { + await beforeEachTest(noSessionTestClientType); + await testDeadletter(); } + ); - it("Partitioned Queue: Deferring a deferred message puts it back to the deferred queue.", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedQueue); - await testRenewlockAndDefer(); - }); - - it("Partitioned Subscription: Deferring a deferred message puts it back to the deferred queue.", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedSubscription); - await testRenewlockAndDefer(); - }); - - it("Unpartitioned Queue: Deferring a deferred message puts it back to the deferred queue.", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedQueue); - await testRenewlockAndDefer(); - }); - - it("Unpartitioned Subscription: Deferring a deferred message puts it back to the deferred queue.", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedSubscription); - await testRenewlockAndDefer(); - }); + it( + withSessionTestClientType + ": Deadlettering a deferred message moves it to dead letter queue.", + async function(): Promise { + await beforeEachTest(withSessionTestClientType); + await testDeadletter(); + } + ); + + it(`${noSessionTestClientType}: renewLock on a deferred message`, async function(): Promise< + void + > { + await beforeEachTest(noSessionTestClientType); + const testMessages = TestMessage.getSample(); + const deferredMsg = await deferMessage(testMessages, false); + const sequenceNumber = deferredMsg.sequenceNumber; + if (!sequenceNumber) { + throw "Sequence Number can not be null"; + } + const lockedUntilBeforeRenewlock = deferredMsg.lockedUntilUtc; + const lockedUntilAfterRenewlock = await deferredMsg.renewLock(); + should.equal( + lockedUntilAfterRenewlock > lockedUntilBeforeRenewlock!, + true, + "MessageLock did not get renewed!" + ); + await deferredMsg.defer(); + await completeDeferredMessage(sequenceNumber, 2, testMessages); }); }); diff --git a/sdk/servicebus/service-bus/test/invalidParameters.spec.ts b/sdk/servicebus/service-bus/test/invalidParameters.spec.ts index 7ea19809e210..a17e4f42bbf6 100644 --- a/sdk/servicebus/service-bus/test/invalidParameters.spec.ts +++ b/sdk/servicebus/service-bus/test/invalidParameters.spec.ts @@ -8,10 +8,10 @@ import chaiAsPromised from "chai-as-promised"; chai.use(chaiAsPromised); import { TestClientType, TestMessage } from "./utils/testUtils"; import { ServiceBusClientForTests, createServiceBusClientForTests } from "./utils/testutils2"; -import { Receiver } from "../src/receivers/receiver"; import { Sender } from "../src/sender"; import { SessionReceiver } from "../src/receivers/sessionReceiver"; import { ReceivedMessageWithLock } from "../src/serviceBusMessage"; +import { ServiceBusClient } from '../src'; describe("invalid parameters", () => { let serviceBusClient: ServiceBusClientForTests; @@ -24,170 +24,6 @@ describe("invalid parameters", () => { return serviceBusClient.test.after(); }); - describe("Invalid parameters in Sender/ReceiverClients for PartitionedQueue", function(): void { - let receiver: Receiver; - - // Since, the below tests never actually make use of any AMQP links, there is no need to create - // new sender/receiver clients before each test. Doing it once for each describe block. - before(async () => { - const entityNames = await serviceBusClient.test.createTestEntities( - TestClientType.PartitionedQueue - ); - - receiver = await serviceBusClient.test.getPeekLockReceiver(entityNames); - }); - - after(async () => { - await serviceBusClient.test.afterEach(); - }); - - it("Peek: Invalid maxMessageCount for Queue", async function(): Promise { - const peekedMessages = await receiver.peekMessages(-100); - should.equal(peekedMessages.length, 0); - }); - - it("Peek: Wrong type maxMessageCount for Queue", async function(): Promise { - let caughtError: Error | undefined; - try { - // @ts-expect-error - await receiver.peekMessages("somestring"); - } catch (error) { - caughtError = error; - } - should.equal(caughtError && caughtError.name, "TypeError"); - should.equal( - caughtError && caughtError.message, - `The parameter "maxMessageCount" should be of type "number"` - ); - }); - - it("PeekBySequenceNumber: Invalid maxMessageCount for Queue", async function(): Promise { - const peekedMessages = await receiver.peekMessages(-100, { - fromSequenceNumber: Long.ZERO - }); - should.equal(peekedMessages.length, 0); - }); - - it("PeekBySequenceNumber: Wrong type maxMessageCount for Queue", async function(): Promise< - void - > { - let caughtError: Error | undefined; - try { - // @ts-expect-error - await receiver.peekMessages("somestring", { - fromSequenceNumber: Long.ZERO - }); - } catch (error) { - caughtError = error; - } - should.equal(caughtError && caughtError.name, "TypeError"); - should.equal( - caughtError && caughtError.message, - `The parameter "maxMessageCount" should be of type "number"` - ); - }); - - it("PeekBySequenceNumber: Wrong type fromSequenceNumber for Queue", async function(): Promise< - void - > { - let caughtError: Error | undefined; - try { - await receiver.peekMessages(1, { fromSequenceNumber: "somestring" as any }); - } catch (error) { - caughtError = error; - } - should.equal(caughtError && caughtError.name, "TypeError"); - should.equal( - caughtError && caughtError.message, - `The parameter "fromSequenceNumber" should be of type "Long"` - ); - }); - }); - - describe("Invalid parameters in Sender/ReceiverClients for PartitionedSubscription", function(): void { - let subscriptionReceiverClient: Receiver; - - // Since, the below tests never actually make use of any AMQP links, there is no need to create - // new sender/receiver clients before each test. Doing it once for each describe block. - before(async () => { - const entityNames = await serviceBusClient.test.createTestEntities( - TestClientType.PartitionedSubscription - ); - - subscriptionReceiverClient = await serviceBusClient.test.getPeekLockReceiver(entityNames); - }); - - after(() => { - return serviceBusClient.test.afterEach(); - }); - - it("Peek: Invalid maxMessageCount for Subscription", async function(): Promise { - const browsedMessages = await subscriptionReceiverClient.peekMessages(-100); - should.equal(browsedMessages.length, 0); - }); - - it("Peek: Wrong type maxMessageCount for Subscription", async function(): Promise { - let caughtError: Error | undefined; - try { - // @ts-expect-error - await subscriptionReceiverClient.peekMessages("somestring"); - } catch (error) { - caughtError = error; - } - should.equal(caughtError && caughtError.name, "TypeError"); - should.equal( - caughtError && caughtError.message, - `The parameter "maxMessageCount" should be of type "number"` - ); - }); - - it("PeekBySequenceNumber: Invalid maxMessageCount for Subscription", async function(): Promise< - void - > { - const browsedMessages = await subscriptionReceiverClient.peekMessages(-100, { - fromSequenceNumber: Long.ZERO - }); - should.equal(browsedMessages.length, 0); - }); - - it("PeekBySequenceNumber: Wrong type maxMessageCount for Subscription", async function(): Promise< - void - > { - let caughtError: Error | undefined; - try { - // @ts-expect-error - await subscriptionReceiverClient.peekMessages("somestring", { - fromSequenceNumber: Long.ZERO - }); - } catch (error) { - caughtError = error; - } - should.equal(caughtError && caughtError.name, "TypeError"); - should.equal( - caughtError && caughtError.message, - `The parameter "maxMessageCount" should be of type "number"` - ); - }); - - it("PeekBySequenceNumber: Wrong type fromSequenceNumber for Subscription", async function(): Promise< - void - > { - let caughtError: Error | undefined; - try { - await subscriptionReceiverClient.peekMessages(1, { - fromSequenceNumber: "somestring" as any - }); - } catch (error) { - caughtError = error; - } - should.equal(caughtError && caughtError.name, "TypeError"); - should.equal( - caughtError && caughtError.message, - `The parameter "fromSequenceNumber" should be of type "Long"` - ); - }); - }); - describe("Invalid parameters in SessionReceiver", function(): void { let sender: Sender; let receiver: SessionReceiver; @@ -393,37 +229,15 @@ describe("invalid parameters", () => { }); describe("Invalid parameters in Receiver", function(): void { - let sender: Sender; - let receiver: Receiver; - - // Since, the below tests never actually make use of any AMQP links, there is no need to create - // new sender/receiver clients before each test. Doing it once for each describe block. - before(async () => { - const entityNames = await serviceBusClient.test.createTestEntities( - TestClientType.PartitionedQueueWithSessions - ); - - sender = serviceBusClient.test.addToCleanup( - serviceBusClient.createSender(entityNames.queue!) - ); - - receiver = await serviceBusClient.test.getPeekLockReceiver(entityNames); - - await sender.sendMessages(TestMessage.getSessionSample()); - }); - - after(async () => { - return serviceBusClient.test.afterEach(); - }); + const mockConnectionString = "Endpoint=sb://test/;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=test"; + const sbClient = new ServiceBusClient(mockConnectionString); + const receiver = sbClient.createReceiver("dummyQueue", "peekLock"); it("Receiver: Missing ReceiveMode", async function(): Promise { let errorCaught: string = ""; try { - const { queue } = serviceBusClient.test.getTestEntities( - TestClientType.PartitionedQueueWithSessions - ); - - await serviceBusClient.createReceiver(queue!, undefined as any); + // @ts-expect-error + sbClient.createReceiver("dummyQueue"); } catch (error) { errorCaught = error.message; } @@ -437,11 +251,8 @@ describe("invalid parameters", () => { it("Receiver: Invalid ReceiveMode", async function(): Promise { let errorCaught: string = ""; try { - const { queue } = serviceBusClient.test.getTestEntities( - TestClientType.PartitionedQueueWithSessions - ); - - await serviceBusClient.createReceiver(queue!, 123 as any); + // @ts-expect-error + sbClient.createReceiver("dummyQueue", 123); } catch (error) { errorCaught = error.message; } @@ -452,6 +263,68 @@ describe("invalid parameters", () => { ); }); + it("Peek: Invalid maxMessageCount for Queue", async function(): Promise { + const peekedMessages = await receiver.peekMessages(-100); + should.equal(peekedMessages.length, 0); + }); + + it("Peek: Wrong type maxMessageCount for Queue", async function(): Promise { + let caughtError: Error | undefined; + try { + // @ts-expect-error + await receiver.peekMessages("somestring"); + } catch (error) { + caughtError = error; + } + should.equal(caughtError && caughtError.name, "TypeError"); + should.equal( + caughtError && caughtError.message, + `The parameter "maxMessageCount" should be of type "number"` + ); + }); + + it("PeekBySequenceNumber: Invalid maxMessageCount for Queue", async function(): Promise { + const peekedMessages = await receiver.peekMessages(-100, { + fromSequenceNumber: Long.ZERO + }); + should.equal(peekedMessages.length, 0); + }); + + it("PeekBySequenceNumber: Wrong type maxMessageCount for Queue", async function(): Promise< + void + > { + let caughtError: Error | undefined; + try { + // @ts-expect-error + await receiver.peekMessages("somestring", { + fromSequenceNumber: Long.ZERO + }); + } catch (error) { + caughtError = error; + } + should.equal(caughtError && caughtError.name, "TypeError"); + should.equal( + caughtError && caughtError.message, + `The parameter "maxMessageCount" should be of type "number"` + ); + }); + + it("PeekBySequenceNumber: Wrong type fromSequenceNumber for Queue", async function(): Promise< + void + > { + let caughtError: Error | undefined; + try { + await receiver.peekMessages(1, { fromSequenceNumber: "somestring" as any }); + } catch (error) { + caughtError = error; + } + should.equal(caughtError && caughtError.name, "TypeError"); + should.equal( + caughtError && caughtError.message, + `The parameter "fromSequenceNumber" should be of type "Long"` + ); + }); + it("RegisterMessageHandler: Missing onMessage in Receiver", async function(): Promise { let caughtError: Error | undefined; try { @@ -523,22 +396,9 @@ describe("invalid parameters", () => { }); describe("Invalid parameters in Sender", function(): void { - let sender: Sender; - - // Since, the below tests never actually make use of any AMQP links, there is no need to create - // new sender/receiver clients before each test. Doing it once for each describe block. - before(async () => { - const { queue } = await serviceBusClient.test.createTestEntities( - TestClientType.PartitionedQueue - ); - - // const clients = await getSenderReceiverClients(TestClientType.PartitionedQueue, "peekLock"); - sender = serviceBusClient.test.addToCleanup(serviceBusClient.createSender(queue!)); - }); - - after(() => { - return serviceBusClient.test.afterEach(); - }); + const mockConnectionString = "Endpoint=sb://test/;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=test"; + const sbClient = new ServiceBusClient(mockConnectionString); + const sender = sbClient.createSender("dummyQueue"); it("ScheduledMessages: Missing date in Sender", async function(): Promise { let caughtError: Error | undefined; diff --git a/sdk/servicebus/service-bus/test/propsToModify.spec.ts b/sdk/servicebus/service-bus/test/propsToModify.spec.ts index 6bd9878f08e7..0d5886f3d00c 100644 --- a/sdk/servicebus/service-bus/test/propsToModify.spec.ts +++ b/sdk/servicebus/service-bus/test/propsToModify.spec.ts @@ -46,9 +46,7 @@ describe("dead lettering", () => { receiver = await serviceBusClient.test.getPeekLockReceiver(entityNames); - const receivedMessages = await receiver.receiveMessages(1, { - maxWaitTimeInMs: 1000 - }); + const receivedMessages = await receiver.receiveMessages(1); if (receivedMessages.length == 0) { throw new Error("No messages were received"); @@ -195,9 +193,7 @@ describe("abandoning", () => { receiver = await serviceBusClient.test.getPeekLockReceiver(entityNames); - const receivedMessages = await receiver.receiveMessages(1, { - maxWaitTimeInMs: 1000 - }); + const receivedMessages = await receiver.receiveMessages(1); if (receivedMessages.length == 0) { throw new Error("No messages were received"); @@ -320,9 +316,7 @@ describe("deferring", () => { receiver = await serviceBusClient.test.getPeekLockReceiver(entityNames); - const receivedMessages = await receiver.receiveMessages(1, { - maxWaitTimeInMs: 1000 - }); + const receivedMessages = await receiver.receiveMessages(1); if (receivedMessages.length == 0) { throw new Error("No messages were received"); diff --git a/sdk/servicebus/service-bus/test/receiveAndDeleteMode.spec.ts b/sdk/servicebus/service-bus/test/receiveAndDeleteMode.spec.ts index c984c7e1651f..f1cbbe3809b9 100644 --- a/sdk/servicebus/service-bus/test/receiveAndDeleteMode.spec.ts +++ b/sdk/servicebus/service-bus/test/receiveAndDeleteMode.spec.ts @@ -16,16 +16,21 @@ import { EntityName, ServiceBusClientForTests, createServiceBusClientForTests, - testPeekMsgsLength + testPeekMsgsLength, + getRandomTestClientTypeWithSessions, + getRandomTestClientTypeWithNoSessions } from "./utils/testutils2"; import { DispositionType, ReceivedMessageWithLock } from "../src/serviceBusMessage"; let errorWasThrown: boolean; +const noSessionTestClientType = getRandomTestClientTypeWithNoSessions(); +const withSessionTestClientType = getRandomTestClientTypeWithSessions(); describe("receive and delete", () => { let sender: Sender; let receiver: Receiver; let serviceBusClient: ServiceBusClientForTests; + let entityName: EntityName; before(() => { serviceBusClient = createServiceBusClientForTests(); @@ -39,19 +44,19 @@ describe("receive and delete", () => { entityType: TestClientType, receiveMode?: "peekLock" | "receiveAndDelete" ): Promise { - const entityNames = await serviceBusClient.test.createTestEntities(entityType); + entityName = await serviceBusClient.test.createTestEntities(entityType); sender = serviceBusClient.test.addToCleanup( - serviceBusClient.createSender(entityNames.queue ?? entityNames.topic!) + serviceBusClient.createSender(entityName.queue ?? entityName.topic!) ); if (receiveMode === "peekLock") { - receiver = await serviceBusClient.test.getPeekLockReceiver(entityNames); + receiver = await serviceBusClient.test.getPeekLockReceiver(entityName); } else { - receiver = await serviceBusClient.test.getReceiveAndDeleteReceiver(entityNames); + receiver = await serviceBusClient.test.getReceiveAndDeleteReceiver(entityName); } errorWasThrown = false; - return entityNames; + return entityName; } function afterEachTest(): Promise { @@ -78,68 +83,30 @@ describe("receive and delete", () => { should.equal(msgs[0].deliveryCount, 0, "DeliveryCount is different than expected"); } - async function testNoSettlement(useSessions?: boolean): Promise { - const testMessages = useSessions ? TestMessage.getSessionSample() : TestMessage.getSample(); + async function testNoSettlement(): Promise { + const testMessages = entityName.usesSessions + ? TestMessage.getSessionSample() + : TestMessage.getSample(); await sendReceiveMsg(testMessages); await testPeekMsgsLength(receiver, 0); } - it("Partitioned Queue: No settlement of the message removes message", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedQueue); - await testNoSettlement(); - }); - - it("Partitioned Subscription: No settlement of the message removes message", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedSubscription); - await testNoSettlement(); - }); - - /* it("Unpartitioned Queue: No settlement of the message removes message", async function(): Promise< - void - > { - await beforeEachTest(ClientType.UnpartitionedQueue, ClientType.UnpartitionedQueue); - await testNoSettlement(); - }); - - it("Unpartitioned Subscription: No settlement of the message removes message", async function(): Promise< - void - > { - await beforeEachTest(ClientType.UnpartitionedTopic, ClientType.UnpartitionedSubscription); - await testNoSettlement(); - });*/ - - it("Partitioned Queue with Sessions: No settlement of the message removes message", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedQueueWithSessions); - await testNoSettlement(true); - }); - - it("Partitioned Subscription with Sessions: No settlement of the message removes message", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedSubscriptionWithSessions); - await testNoSettlement(true); - }); - - it("Unpartitioned Queue with Sessions: No settlement of the message removes message", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedQueueWithSessions); - await testNoSettlement(true); - }); + it( + noSessionTestClientType + ": No settlement of the message removes message", + async function(): Promise { + await beforeEachTest(noSessionTestClientType); + await testNoSettlement(); + } + ); - it("Unpartitioned Subscription with Sessions: No settlement of the message removes message", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedSubscriptionWithSessions); - await testNoSettlement(true); - }); + it( + withSessionTestClientType + ": No settlement of the message removes message", + async function(): Promise { + await beforeEachTest(withSessionTestClientType); + await testNoSettlement(); + } + ); }); describe("Streaming Receiver in ReceiveAndDelete mode", function(): void { @@ -194,127 +161,50 @@ describe("receive and delete", () => { await testPeekMsgsLength(receiver, 0); } - async function testNoSettlement( - autoCompleteFlag: boolean, - useSessions?: boolean - ): Promise { - const testMessages = useSessions ? TestMessage.getSessionSample() : TestMessage.getSample(); + async function testNoSettlement(autoCompleteFlag: boolean): Promise { + const testMessages = entityName.usesSessions + ? TestMessage.getSessionSample() + : TestMessage.getSample(); await sendReceiveMsg(testMessages, autoCompleteFlag); await testPeekMsgsLength(receiver, 0); } - it("Partitioned Queue: With auto-complete enabled, no settlement of the message removes message", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedQueue); - await testNoSettlement(true); - }); - - it("Partitioned Subscription: With auto-complete enabled, no settlement of the message removes message", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedSubscription); - await testNoSettlement(true); - }); - - /* it("Unpartitioned Queue: With auto-complete enabled, no settlement of the message removes message", async function(): Promise< - void - > { - await beforeEachTest(ClientType.UnpartitionedQueue, ClientType.UnpartitionedQueue); - await testNoSettlement(true); - }); - - it("Unpartitioned Subscription: With auto-complete enabled, no settlement of the message removes message", async function(): Promise< - void - > { - await beforeEachTest(ClientType.UnpartitionedTopic, ClientType.UnpartitionedSubscription); - await testNoSettlement(true); - });*/ - - it("Partitioned Queue with Sessions: With auto-complete enabled, no settlement of the message removes message", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedQueueWithSessions); - await testNoSettlement(true, true); - }); - - it("Partitioned Subscription with Sessions: With auto-complete enabled, no settlement of the message removes message", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedSubscriptionWithSessions); - await testNoSettlement(true, true); - }); - - it("Unpartitioned Queue with Sessions: With auto-complete enabled, no settlement of the message removes message", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedQueueWithSessions); - await testNoSettlement(true, true); - }); - - it("Unpartitioned Subscription with Sessions: With auto-complete enabled, no settlement of the message removes message", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedSubscriptionWithSessions); - await testNoSettlement(true, true); - }); - - it("Partitioned Queue: With auto-complete disabled, no settlement of the message removes message", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedQueue); - await testNoSettlement(false); - }); - - it("Partitioned Subscription: With auto-complete disabled, no settlement of the message removes message", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedSubscription); - await testNoSettlement(false); - }); - - /* it("Unpartitioned Queue: With auto-complete disabled, no settlement of the message removes message", async function(): Promise< - void - > { - await beforeEachTest(ClientType.UnpartitionedQueue, ClientType.UnpartitionedQueue); - await testNoSettlement(false); - }); - - it("Unpartitioned Subscription: With auto-complete disabled, no settlement of the message removes message", async function(): Promise< - void - > { - await beforeEachTest(ClientType.UnpartitionedTopic, ClientType.UnpartitionedSubscription); - await testNoSettlement(false); - });*/ - - it("Partitioned Queue with Sessions: With auto-complete disabled, no settlement of the message removes message", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedQueueWithSessions); - await testNoSettlement(false, true); - }); + it( + noSessionTestClientType + + ": With auto-complete enabled, no settlement of the message removes message", + async function(): Promise { + await beforeEachTest(noSessionTestClientType); + await testNoSettlement(true); + } + ); - it("Partitioned Subscription with Sessions: With auto-complete disabled, no settlement of the message removes message", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedSubscriptionWithSessions); - await testNoSettlement(false, true); - }); + it( + withSessionTestClientType + + ": With auto-complete enabled, no settlement of the message removes message", + async function(): Promise { + await beforeEachTest(withSessionTestClientType); + await testNoSettlement(true); + } + ); - it("Unpartitioned Queue with Sessions: With auto-complete disabled, no settlement of the message removes message", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedQueueWithSessions); - await testNoSettlement(false, true); - }); + it( + noSessionTestClientType + + ": With auto-complete disabled, no settlement of the message removes message", + async function(): Promise { + await beforeEachTest(noSessionTestClientType); + await testNoSettlement(false); + } + ); - it("Unpartitioned Subscription with Sessions: With auto-complete disabled, no settlement of the message removes message", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedSubscriptionWithSessions); - await testNoSettlement(false, true); - }); + it( + withSessionTestClientType + + ": With auto-complete disabled, no settlement of the message removes message", + async function(): Promise { + await beforeEachTest(withSessionTestClientType); + await testNoSettlement(false); + } + ); }); describe("Settlement with ReceiveAndDelete mode", () => { @@ -345,11 +235,10 @@ describe("receive and delete", () => { ); }; - async function testSettlement( - operation: DispositionType, - useSessions?: boolean - ): Promise { - const testMessages = useSessions ? TestMessage.getSessionSample() : TestMessage.getSample(); + async function testSettlement(operation: DispositionType): Promise { + const testMessages = entityName.usesSessions + ? TestMessage.getSessionSample() + : TestMessage.getSample(); // we have to force this cast - the type system doesn't allow this if you've chosen receiveAndDelete // as your lock mode. const msg = (await sendReceiveMsg(testMessages)) as ReceivedMessageWithLock; @@ -374,277 +263,46 @@ describe("receive and delete", () => { await testPeekMsgsLength(receiver, 0); } - it("Partitioned Queue: complete() throws error", async function(): Promise { - await beforeEachTest(TestClientType.PartitionedQueue); - await testSettlement(DispositionType.complete); - }); - - it("Partitioned Subscription: complete() throws error", async function(): Promise { - await beforeEachTest(TestClientType.PartitionedSubscription); - await testSettlement(DispositionType.complete); - }); - - /* it("Unpartitioned Queue: complete() throws error", async function(): Promise { - await beforeEachTest(ClientType.UnpartitionedQueue, ClientType.UnpartitionedQueue); + it(noSessionTestClientType + ": complete() throws error", async function(): Promise { + await beforeEachTest(noSessionTestClientType); await testSettlement(DispositionType.complete); }); - it("Unpartitioned Subscription: complete() throws error", async function(): Promise< - void - > { - await beforeEachTest(ClientType.UnpartitionedTopic, ClientType.UnpartitionedSubscription); + it(withSessionTestClientType + ": complete() throws error", async function(): Promise { + await beforeEachTest(withSessionTestClientType); await testSettlement(DispositionType.complete); - });*/ - - it("Partitioned Queue with Sessions: complete() throws error", async function(): Promise { - await beforeEachTest(TestClientType.PartitionedQueueWithSessions); - await testSettlement(DispositionType.complete, true); }); - it("Partitioned Subscription with Sessions: complete() throws error", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedSubscriptionWithSessions); - await testSettlement(DispositionType.complete, true); - }); - - it("Partitioned Queue: abandon() throws error", async function(): Promise { - await beforeEachTest(TestClientType.PartitionedQueue); + it(noSessionTestClientType + ": abandon() throws error", async function(): Promise { + await beforeEachTest(noSessionTestClientType); await testSettlement(DispositionType.abandon); }); - it("Partitioned Subscription: abandon() throws error", async function(): Promise { - await beforeEachTest(TestClientType.PartitionedSubscription); + it(withSessionTestClientType + ": abandon() throws error", async function(): Promise { + await beforeEachTest(withSessionTestClientType); await testSettlement(DispositionType.abandon); }); - /* it("Unpartitioned Queue: abandon() throws error", async function(): Promise { - await beforeEachTest(ClientType.UnpartitionedQueue, ClientType.UnpartitionedQueue); - await testSettlement(DispositionType.abandon); - }); - - it("Unpartitioned Subscription: abandon() throws error", async function(): Promise< - void - > { - await beforeEachTest(ClientType.UnpartitionedTopic, ClientType.UnpartitionedSubscription); - await testSettlement(DispositionType.abandon); - });*/ - - it("Partitioned Queue with Sessions: abandon() throws error", async function(): Promise { - await beforeEachTest(TestClientType.PartitionedQueueWithSessions); - await testSettlement(DispositionType.abandon, true); - }); - - it("Partitioned Subscription with Sessions: abandon() throws error", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedSubscriptionWithSessions); - await testSettlement(DispositionType.abandon, true); - }); - - it("Partitioned Queue: defer() throws error", async function(): Promise { - await beforeEachTest(TestClientType.PartitionedQueue); - await testSettlement(DispositionType.defer); - }); - - it("Partitioned Subscription: defer() throws error", async function(): Promise { - await beforeEachTest(TestClientType.PartitionedSubscription); - await testSettlement(DispositionType.defer); - }); - - /* it("Unpartitioned Queue: defer() throws error", async function(): Promise { - await beforeEachTest(ClientType.UnpartitionedQueue, ClientType.UnpartitionedQueue); + it(noSessionTestClientType + ": defer() throws error", async function(): Promise { + await beforeEachTest(noSessionTestClientType); await testSettlement(DispositionType.defer); }); - it("Unpartitioned Subscription: defer() throws error", async function(): Promise< - void - > { - await beforeEachTest(ClientType.UnpartitionedTopic, ClientType.UnpartitionedSubscription); + it(withSessionTestClientType + ": defer() throws error", async function(): Promise { + await beforeEachTest(withSessionTestClientType); await testSettlement(DispositionType.defer); - });*/ - - it("Partitioned Queue with Sessions: defer() throws error", async function(): Promise { - await beforeEachTest(TestClientType.PartitionedQueueWithSessions); - await testSettlement(DispositionType.defer, true); }); - it("Partitioned Subscription with Sessions: defer() throws error", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedSubscriptionWithSessions); - await testSettlement(DispositionType.defer, true); - }); - - it("Partitioned Queue: deadLetter() throws error", async function(): Promise { - await beforeEachTest(TestClientType.PartitionedQueue); - await testSettlement(DispositionType.deadletter); - }); - - it("Partitioned Subscription: deadLetter() throws error", async function(): Promise { - await beforeEachTest(TestClientType.PartitionedSubscription); - await testSettlement(DispositionType.deadletter); - }); - - /* it("Unpartitioned Queue: deadLetter() throws error", async function(): Promise { - await beforeEachTest(ClientType.UnpartitionedQueue, ClientType.UnpartitionedQueue); - await testSettlement(DispositionType.deadletter); - }); - - it("Unpartitioned Subscription: deadLetter() throws error", async function(): Promise< - void - > { - await beforeEachTest(ClientType.UnpartitionedTopic, ClientType.UnpartitionedSubscription); - await testSettlement(DispositionType.deadletter); - });*/ - - it("Partitioned Queue with Sessions: deadLetter() throws error", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedQueueWithSessions); - await testSettlement(DispositionType.deadletter, true); - }); - - it("Partitioned Subscription with Sessions: deadLetter() throws error", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedSubscriptionWithSessions); - await testSettlement(DispositionType.deadletter, true); - }); - - it("Partitioned Subscription: complete() throws error", async function(): Promise { - await beforeEachTest(TestClientType.PartitionedSubscription); - await testSettlement(DispositionType.complete); - }); - - /* it("Unpartitioned Queue: complete() throws error", async function(): Promise { - await beforeEachTest(ClientType.UnpartitionedQueue, ClientType.UnpartitionedQueue); - await testSettlement(DispositionType.complete); - }); - - it("Unpartitioned Subscription: complete() throws error", async function(): Promise< - void - > { - await beforeEachTest(ClientType.UnpartitionedTopic, ClientType.UnpartitionedSubscription); - await testSettlement(DispositionType.complete); - });*/ - - it("Partitioned Queue with Sessions: complete() throws error", async function(): Promise { - await beforeEachTest(TestClientType.PartitionedQueueWithSessions); - await testSettlement(DispositionType.complete, true); - }); - - it("Partitioned Subscription with Sessions: complete() throws error", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedSubscriptionWithSessions); - await testSettlement(DispositionType.complete, true); - }); - - it("Partitioned Queue: abandon() throws error", async function(): Promise { - await beforeEachTest(TestClientType.PartitionedQueue); - await testSettlement(DispositionType.abandon); - }); - - it("Partitioned Subscription: abandon() throws error", async function(): Promise { - await beforeEachTest(TestClientType.PartitionedSubscription); - await testSettlement(DispositionType.abandon); - }); - - /* it("Unpartitioned Queue: abandon() throws error", async function(): Promise { - await beforeEachTest(ClientType.UnpartitionedQueue, ClientType.UnpartitionedQueue); - await testSettlement(DispositionType.abandon); - }); - - it("Unpartitioned Subscription: abandon() throws error", async function(): Promise< - void - > { - await beforeEachTest(ClientType.UnpartitionedTopic, ClientType.UnpartitionedSubscription); - await testSettlement(DispositionType.abandon); - });*/ - - it("Partitioned Queue with Sessions: abandon() throws error", async function(): Promise { - await beforeEachTest(TestClientType.PartitionedQueueWithSessions); - await testSettlement(DispositionType.abandon, true); - }); - - it("Partitioned Subscription with Sessions: abandon() throws error", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedSubscriptionWithSessions); - await testSettlement(DispositionType.abandon, true); - }); - - it("Partitioned Queue: defer() throws error", async function(): Promise { - await beforeEachTest(TestClientType.PartitionedQueue); - await testSettlement(DispositionType.defer); - }); - - it("Partitioned Subscription: defer() throws error", async function(): Promise { - await beforeEachTest(TestClientType.PartitionedSubscription); - await testSettlement(DispositionType.defer); - }); - - /* it("Unpartitioned Queue: defer() throws error", async function(): Promise { - await beforeEachTest(ClientType.UnpartitionedQueue, ClientType.UnpartitionedQueue); - await testSettlement(DispositionType.defer); - }); - - it("Unpartitioned Subscription: defer() throws error", async function(): Promise< - void - > { - await beforeEachTest(ClientType.UnpartitionedTopic, ClientType.UnpartitionedSubscription); - await testSettlement(DispositionType.defer); - });*/ - - it("Partitioned Queue with Sessions: defer() throws error", async function(): Promise { - await beforeEachTest(TestClientType.PartitionedQueueWithSessions); - await testSettlement(DispositionType.defer, true); - }); - - it("Partitioned Subscription with Sessions: defer() throws error", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedSubscriptionWithSessions); - await testSettlement(DispositionType.defer, true); - }); - - it("Partitioned Queue: deadLetter() throws error", async function(): Promise { - await beforeEachTest(TestClientType.PartitionedQueue); - await testSettlement(DispositionType.deadletter); - }); - - it("Partitioned Subscription: deadLetter() throws error", async function(): Promise { - await beforeEachTest(TestClientType.PartitionedSubscription); + it(noSessionTestClientType + ": deadLetter() throws error", async function(): Promise { + await beforeEachTest(noSessionTestClientType); await testSettlement(DispositionType.deadletter); }); - /* it("Unpartitioned Queue: deadLetter() throws error", async function(): Promise { - await beforeEachTest(ClientType.UnpartitionedQueue, ClientType.UnpartitionedQueue); + it(withSessionTestClientType + ": deadLetter() throws error", async function(): Promise { + await beforeEachTest(withSessionTestClientType); await testSettlement(DispositionType.deadletter); }); - it("Unpartitioned Subscription: deadLetter() throws error", async function(): Promise< - void - > { - await beforeEachTest(ClientType.UnpartitionedTopic, ClientType.UnpartitionedSubscription); - await testSettlement(DispositionType.deadletter); - });*/ - - it("Partitioned Queue with Sessions: deadLetter() throws error", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedQueueWithSessions); - await testSettlement(DispositionType.deadletter, true); - }); - - it("Partitioned Subscription with Sessions: deadLetter() throws error", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedSubscriptionWithSessions); - await testSettlement(DispositionType.deadletter, true); - }); - async function testRenewLock(): Promise { const msg = await sendReceiveMsg(TestMessage.getSample()); @@ -661,31 +319,14 @@ describe("receive and delete", () => { should.equal(errorWasThrown, true, "Error thrown flag must be true"); } - it("Partitioned Queue: Renew message lock throws error", async function(): Promise { - await beforeEachTest(TestClientType.PartitionedQueue); - await testRenewLock(); - }); - - it("Partitioned Subscription: Renew message lock throws error", async function(): Promise< + it(noSessionTestClientType + ": Renew message lock throws error", async function(): Promise< void > { - await beforeEachTest(TestClientType.PartitionedSubscription); + await beforeEachTest(noSessionTestClientType); await testRenewLock(); }); }); - /* it("Unpartitioned Queue: Renew message lock throws error", async function(): Promise { - await beforeEachTest(ClientType.UnpartitionedQueue, ClientType.UnpartitionedQueue); - await testRenewLock(); - }); - - it("Unpartitioned Subscription: Renew message lock throws error", async function(): Promise< - void - > { - await beforeEachTest(ClientType.UnpartitionedTopic, ClientType.UnpartitionedSubscription); - await testRenewLock(); - });*/ - describe("Receive Deferred messages in ReceiveAndDelete mode", function(): void { let sequenceNumber: Long; @@ -722,36 +363,6 @@ describe("receive and delete", () => { await testPeekMsgsLength(receiver, 0); } - /* it("Partitioned Queue: No settlement of the message removes message", async function(): Promise< - void - > { - await beforeEachTest( - TestClientType.PartitionedQueue, - TestClientType.PartitionedQueue, - undefined, - ReceiveMode.peekLock - ); - await deferMessage(); - await receiver.close(); - receiver = receiver.createReceiver(ReceiveMode.receiveAndDelete); - await receiveDeferredMessage(); - }); - - it("Partitioned Subscription: No settlement of the message removes message", async function(): Promise< - void - > { - await beforeEachTest( - TestClientType.PartitionedTopic, - TestClientType.PartitionedSubscription, - undefined, - ReceiveMode.peekLock - ); - await deferMessage(); - await receiver.close(); - receiver = receiver.createReceiver(ReceiveMode.receiveAndDelete); - await receiveDeferredMessage(); - }); */ - async function deferAndReceiveMessage(testClientType: TestClientType) { const entityNames = await beforeEachTest(testClientType, "peekLock"); await deferMessage(entityNames.usesSessions); @@ -760,40 +371,38 @@ describe("receive and delete", () => { await receiveDeferredMessage(); } - it("Unpartitioned Queue: No settlement of the message removes message", async function(): Promise< - void - > { - await deferAndReceiveMessage(TestClientType.UnpartitionedQueue); - }); - - it("Unpartitioned Subscription: No settlement of the message removes message", async function(): Promise< + /* + // The below are commented due to service bug described in https://github.com/Azure/azure-sdk-for-js/issues/2268 + it("Partitioned Queue: No settlement of the message removes message", async function(): Promise< void > { - await deferAndReceiveMessage(TestClientType.UnpartitionedSubscription); + await deferAndReceiveMessage(TestClientType.PartitionedQueue); }); - it("Partitioned Queue with Sessions: No settlement of the message removes message", async function(): Promise< + it("Partitioned Subscription: No settlement of the message removes message", async function(): Promise< void > { - await deferAndReceiveMessage(TestClientType.PartitionedQueueWithSessions); + await deferAndReceiveMessage(TestClientType.PartitionedSubscription); }); + */ - it("Partitioned Subscription with Sessions: No settlement of the message removes message", async function(): Promise< + it("Unpartitioned Queue: No settlement of the message removes message", async function(): Promise< void > { - await deferAndReceiveMessage(TestClientType.PartitionedSubscriptionWithSessions); + await deferAndReceiveMessage(TestClientType.UnpartitionedQueue); }); - it("Unpartitioned Queue with Sessions: No settlement of the message removes message", async function(): Promise< + it("Unpartitioned Subscription: No settlement of the message removes message", async function(): Promise< void > { - await deferAndReceiveMessage(TestClientType.UnpartitionedQueueWithSessions); + await deferAndReceiveMessage(TestClientType.UnpartitionedSubscription); }); - it("Unpartitioned Subscription with Sessions: No settlement of the message removes message", async function(): Promise< - void - > { - await deferAndReceiveMessage(TestClientType.UnpartitionedSubscriptionWithSessions); - }); + it( + withSessionTestClientType + ": No settlement of the message removes message", + async function(): Promise { + await deferAndReceiveMessage(withSessionTestClientType); + } + ); }); }); diff --git a/sdk/servicebus/service-bus/test/renewLock.spec.ts b/sdk/servicebus/service-bus/test/renewLock.spec.ts index 3c96fd65fc42..b092e09388c1 100644 --- a/sdk/servicebus/service-bus/test/renewLock.spec.ts +++ b/sdk/servicebus/service-bus/test/renewLock.spec.ts @@ -6,17 +6,23 @@ const should = chai.should(); import chaiAsPromised from "chai-as-promised"; chai.use(chaiAsPromised); import { delay } from "rhea-promise"; -import { TestClientType, TestMessage } from "./utils/testUtils"; -import { ServiceBusClientForTests, createServiceBusClientForTests } from "./utils/testutils2"; +import { TestMessage } from "./utils/testUtils"; +import { + ServiceBusClientForTests, + createServiceBusClientForTests, + getRandomTestClientTypeWithNoSessions +} from "./utils/testutils2"; import { Receiver } from "../src/receivers/receiver"; import { Sender } from "../src/sender"; import { ReceivedMessageWithLock } from "../src/serviceBusMessage"; -describe("renew lock", () => { +describe("Message Lock Renewal", () => { let serviceBusClient: ServiceBusClientForTests; let sender: Sender; let receiver: Receiver; + const testClientType = getRandomTestClientTypeWithNoSessions(); + before(() => { serviceBusClient = createServiceBusClientForTests(); }); @@ -25,235 +31,85 @@ describe("renew lock", () => { return serviceBusClient.test.after(); }); - async function beforeEachTest(entityType: TestClientType): Promise { - const entityNames = await serviceBusClient.test.createTestEntities(entityType); + beforeEach(async () => { + const entityNames = await serviceBusClient.test.createTestEntities(testClientType); receiver = await serviceBusClient.test.getPeekLockReceiver(entityNames); sender = serviceBusClient.test.addToCleanup( serviceBusClient.createSender(entityNames.queue ?? entityNames.topic!) ); - } - - function afterEachTest(): Promise { - return serviceBusClient.test.afterEach(); - } - - describe("Unpartitioned Queue - Lock Renewal", function(): void { - beforeEach(async () => { - await beforeEachTest(TestClientType.UnpartitionedQueue); - }); - - afterEach(async () => { - await afterEachTest(); - }); - - it("Batch Receiver: renewLock() resets lock duration each time.", async function(): Promise< - void - > { - await testBatchReceiverManualLockRenewalHappyCase(sender, receiver); - }); - - it("Batch Receiver: complete() after lock expiry with throws error", async function(): Promise< - void - > { - await testBatchReceiverManualLockRenewalErrorOnLockExpiry(sender, receiver); - }); - - it("Streaming Receiver: renewLock() resets lock duration each time.", async function(): Promise< - void - > { - await testStreamingReceiverManualLockRenewalHappyCase(sender, receiver); - }); - - it("Streaming Receiver: complete() after lock expiry with auto-renewal disabled throws error", async function(): Promise< - void - > { - await testAutoLockRenewalConfigBehavior( - sender, - receiver, - { - maxAutoRenewDurationInMs: 0, - delayBeforeAttemptingToCompleteMessageInSeconds: 31, - willCompleteFail: true - }, - TestClientType.UnpartitionedQueue - ); - }); - - it("Streaming Receiver: lock will not expire until configured time", async function(): Promise< - void - > { - await testAutoLockRenewalConfigBehavior( - sender, - receiver, - { - maxAutoRenewDurationInMs: 38 * 1000, - delayBeforeAttemptingToCompleteMessageInSeconds: 35, - willCompleteFail: false - }, - TestClientType.UnpartitionedQueue - ); - }); - - it("Streaming Receiver: lock expires sometime after configured time", async function(): Promise< - void - > { - await testAutoLockRenewalConfigBehavior( - sender, - receiver, - { - maxAutoRenewDurationInMs: 35 * 1000, - delayBeforeAttemptingToCompleteMessageInSeconds: 55, - willCompleteFail: true - }, - TestClientType.UnpartitionedQueue - ); - }).timeout(95000 + 30000); - - it("Streaming Receiver: No lock renewal when config value is less than lock duration", async function(): Promise< - void - > { - await testAutoLockRenewalConfigBehavior( - sender, - receiver, - { - maxAutoRenewDurationInMs: 15 * 1000, - delayBeforeAttemptingToCompleteMessageInSeconds: 31, - willCompleteFail: true - }, - TestClientType.UnpartitionedQueue - ); - }); }); - describe("Partitioned Queue - Lock Renewal", function(): void { - beforeEach(async () => { - await beforeEachTest(TestClientType.PartitionedQueue); - }); - - afterEach(async () => { - await afterEachTest(); - }); - - it("Batch Receiver: renewLock() resets lock duration each time.", async function(): Promise< - void - > { - await testBatchReceiverManualLockRenewalHappyCase(sender, receiver); - }); - - it("Batch Receiver: complete() after lock expiry with throws error", async function(): Promise< - void - > { - await testBatchReceiverManualLockRenewalErrorOnLockExpiry(sender, receiver); - }); - - it("Streaming Receiver: renewLock() resets lock duration each time.", async function(): Promise< - void - > { - await testStreamingReceiverManualLockRenewalHappyCase(sender, receiver); - }); - - it("Streaming Receiver: complete() after lock expiry with auto-renewal disabled throws error", async function(): Promise< - void - > { - await testAutoLockRenewalConfigBehavior( - sender, - receiver, - { - maxAutoRenewDurationInMs: 0, - delayBeforeAttemptingToCompleteMessageInSeconds: 31, - willCompleteFail: true - }, - TestClientType.PartitionedQueue - ); - }); - }); - - describe("Unpartitioned Subscription - Lock Renewal", function(): void { - beforeEach(async () => { - await beforeEachTest(TestClientType.UnpartitionedSubscription); - }); - - afterEach(async () => { - await afterEachTest(); - }); - - it("Batch Receiver: renewLock() resets lock duration each time.", async function(): Promise< - void - > { - await testBatchReceiverManualLockRenewalHappyCase(sender, receiver); - }); - - it("Batch Receiver: complete() after lock expiry with throws error", async function(): Promise< - void - > { - await testBatchReceiverManualLockRenewalErrorOnLockExpiry(sender, receiver); - }); - - it("Streaming Receiver: renewLock() resets lock duration each time.", async function(): Promise< - void - > { - await testStreamingReceiverManualLockRenewalHappyCase(sender, receiver); - }); - - it("Streaming Receiver: complete() after lock expiry with auto-renewal disabled throws error", async function(): Promise< - void - > { - await testAutoLockRenewalConfigBehavior( - sender, - receiver, - { - maxAutoRenewDurationInMs: 0, - delayBeforeAttemptingToCompleteMessageInSeconds: 31, - willCompleteFail: true - }, - TestClientType.UnpartitionedSubscription - ); - }); + afterEach(async () => { + await serviceBusClient.test.afterEach(); }); - describe("Partitioned Subscription - Lock Renewal", function(): void { - beforeEach(async () => { - await beforeEachTest(TestClientType.PartitionedSubscription); - }); - - afterEach(async () => { - await afterEachTest(); - }); - - it("Batch Receiver: renewLock() resets lock duration each time.", async function(): Promise< - void - > { + it( + testClientType + ": Batch Receiver: renewLock() resets lock duration each time.", + async function(): Promise { await testBatchReceiverManualLockRenewalHappyCase(sender, receiver); - }); + } + ); - it("Batch Receiver: complete() after lock expiry with throws error", async function(): Promise< - void - > { + it( + testClientType + ": Batch Receiver: complete() after lock expiry with throws error", + async function(): Promise { await testBatchReceiverManualLockRenewalErrorOnLockExpiry(sender, receiver); - }); + } + ); - it("Streaming Receiver: renewLock() resets lock duration each time.", async function(): Promise< - void - > { + it( + testClientType + ": Streaming Receiver: renewLock() resets lock duration each time.", + async function(): Promise { await testStreamingReceiverManualLockRenewalHappyCase(sender, receiver); - }); - - it("Streaming Receiver: complete() after lock expiry with auto-renewal disabled throws error", async function(): Promise< - void - > { - await testAutoLockRenewalConfigBehavior( - sender, - receiver, - { - maxAutoRenewDurationInMs: 0, - delayBeforeAttemptingToCompleteMessageInSeconds: 31, - willCompleteFail: true - }, - TestClientType.PartitionedSubscription - ); - }); - }); + } + ); + + it( + testClientType + + ": Streaming Receiver: complete() after lock expiry with auto-renewal disabled throws error", + async function(): Promise { + await testAutoLockRenewalConfigBehavior(sender, receiver, { + maxAutoRenewDurationInMs: 0, + delayBeforeAttemptingToCompleteMessageInSeconds: 31, + willCompleteFail: true + }); + } + ); + + it( + testClientType + ": Streaming Receiver: lock will not expire until configured time", + async function(): Promise { + await testAutoLockRenewalConfigBehavior(sender, receiver, { + maxAutoRenewDurationInMs: 38 * 1000, + delayBeforeAttemptingToCompleteMessageInSeconds: 35, + willCompleteFail: false + }); + } + ); + + it( + testClientType + ": Streaming Receiver: lock expires sometime after configured time", + async function(): Promise { + await testAutoLockRenewalConfigBehavior(sender, receiver, { + maxAutoRenewDurationInMs: 35 * 1000, + delayBeforeAttemptingToCompleteMessageInSeconds: 55, + willCompleteFail: true + }); + } + ).timeout(95000 + 30000); + + it( + testClientType + + ": Streaming Receiver: No lock renewal when config value is less than lock duration", + async function(): Promise { + await testAutoLockRenewalConfigBehavior(sender, receiver, { + maxAutoRenewDurationInMs: 15 * 1000, + delayBeforeAttemptingToCompleteMessageInSeconds: 31, + willCompleteFail: true + }); + } + ); const lockDurationInMilliseconds = 30000; @@ -426,8 +282,7 @@ describe("renew lock", () => { async function testAutoLockRenewalConfigBehavior( sender: Sender, receiver: Receiver, - options: AutoLockRenewalTestOptions, - entityType: TestClientType + options: AutoLockRenewalTestOptions ): Promise { let numOfMessagesReceived = 0; const testMessage = TestMessage.getSample(); @@ -481,7 +336,7 @@ describe("renew lock", () => { await receiver.close(); receiver = await serviceBusClient.test.getPeekLockReceiver( - await serviceBusClient.test.createTestEntities(entityType) + await serviceBusClient.test.createTestEntities(testClientType) ); const unprocessedMsgsBatch = await receiver.receiveMessages(1); diff --git a/sdk/servicebus/service-bus/test/renewLockSessions.spec.ts b/sdk/servicebus/service-bus/test/renewLockSessions.spec.ts index 29f12da4579e..16e3c99952ea 100644 --- a/sdk/servicebus/service-bus/test/renewLockSessions.spec.ts +++ b/sdk/servicebus/service-bus/test/renewLockSessions.spec.ts @@ -7,19 +7,24 @@ import chaiAsPromised from "chai-as-promised"; chai.use(chaiAsPromised); import { MessagingError, ServiceBusMessage, delay } from "../src"; import { TestClientType, TestMessage, isMessagingError } from "./utils/testUtils"; -import { ServiceBusClientForTests, createServiceBusClientForTests } from "./utils/testutils2"; +import { + ServiceBusClientForTests, + createServiceBusClientForTests, + getRandomTestClientTypeWithSessions +} from "./utils/testutils2"; import { Sender } from "../src/sender"; import { SessionReceiver } from "../src/receivers/sessionReceiver"; import { ReceivedMessageWithLock } from "../src/serviceBusMessage"; -describe("renew lock sessions", () => { +describe("Session Lock Renewal", () => { let sender: Sender; let receiver: SessionReceiver; - let autoRenewLockDurationInMs: number; let sessionId: string; let serviceBusClient: ServiceBusClientForTests; + const testClientType = getRandomTestClientTypeWithSessions(); + before(async () => { serviceBusClient = createServiceBusClientForTests(); }); @@ -28,11 +33,8 @@ describe("renew lock sessions", () => { await serviceBusClient.test.after(); }); - async function beforeEachTest( - entityType: TestClientType, - autoRenewLockDurationInMs: number - ): Promise { - const entityNames = await serviceBusClient.test.createTestEntities(entityType); + async function beforeEachTest(autoRenewLockDurationInMs: number): Promise { + const entityNames = await serviceBusClient.test.createTestEntities(testClientType); sender = serviceBusClient.test.addToCleanup( serviceBusClient.createSender(entityNames.queue ?? entityNames.topic!) @@ -62,265 +64,62 @@ describe("renew lock sessions", () => { // } } - describe("Batch Receiver: renewLock() resets lock duration each time", function(): void { - beforeEach(() => { - autoRenewLockDurationInMs = 0; - }); - - afterEach(() => { - return serviceBusClient.test.afterEach(); - }); - - it("Unpartitioned Queue With Sessions - Lock Renewal for Sessions", async function(): Promise< - void - > { - await beforeEachTest( - TestClientType.UnpartitionedQueueWithSessions, - autoRenewLockDurationInMs - ); - await testBatchReceiverManualLockRenewalHappyCase(sender, receiver); - }); - - it("Partitioned Queue With Sessions - Lock Renewal for Sessions", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedQueueWithSessions, autoRenewLockDurationInMs); - await testBatchReceiverManualLockRenewalHappyCase(sender, receiver); - }); - - it("Unpartitioned Subscription With Sessions - Lock Renewal for Sessions", async function(): Promise< - void - > { - await beforeEachTest( - TestClientType.UnpartitionedSubscriptionWithSessions, - autoRenewLockDurationInMs - ); - await testBatchReceiverManualLockRenewalHappyCase(sender, receiver); - }); - - it("Partitioned Subscription With Sessions - Lock Renewal for Sessions", async function(): Promise< - void - > { - await beforeEachTest( - TestClientType.PartitionedSubscriptionWithSessions, - autoRenewLockDurationInMs - ); - await testBatchReceiverManualLockRenewalHappyCase(sender, receiver); - }); + afterEach(() => { + return serviceBusClient.test.afterEach(); }); - describe("Batch Receiver: complete() after lock expiry with throws error", function(): void { - beforeEach(() => { - autoRenewLockDurationInMs = 0; - }); - - afterEach(() => { - return serviceBusClient.test.afterEach(); - }); - - it("Unpartitioned Queue With Sessions - Lock Renewal for Sessions", async function(): Promise< - void - > { - await beforeEachTest( - TestClientType.UnpartitionedQueueWithSessions, - autoRenewLockDurationInMs - ); - await testBatchReceiverManualLockRenewalErrorOnLockExpiry( - TestClientType.UnpartitionedQueueWithSessions, - sender, - receiver - ); - }); - - it("Partitioned Queue With Sessions - Lock Renewal for Sessions", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedQueueWithSessions, autoRenewLockDurationInMs); - await testBatchReceiverManualLockRenewalErrorOnLockExpiry( - TestClientType.PartitionedQueueWithSessions, - sender, - receiver - ); - }); - - it("Unpartitioned Subscription With Sessions - Lock Renewal for Sessions", async function(): Promise< - void - > { - await beforeEachTest( - TestClientType.UnpartitionedSubscriptionWithSessions, - autoRenewLockDurationInMs - ); - await testBatchReceiverManualLockRenewalErrorOnLockExpiry( - TestClientType.UnpartitionedSubscriptionWithSessions, - sender, - receiver - ); - }); - - it("Partitioned Subscription With Sessions - Lock Renewal for Sessions", async function(): Promise< - void - > { - await beforeEachTest( - TestClientType.PartitionedSubscriptionWithSessions, - autoRenewLockDurationInMs - ); - await testBatchReceiverManualLockRenewalErrorOnLockExpiry( - TestClientType.PartitionedSubscriptionWithSessions, - sender, - receiver - ); - }); - }); - - describe("Streaming Receiver: renewLock() resets lock duration each time", function(): void { - beforeEach(() => { - autoRenewLockDurationInMs = 0; - }); - - afterEach(() => { - return serviceBusClient.test.afterEach(); - }); - - it("Unpartitioned Queue With Sessions - Lock Renewal for Sessions", async function(): Promise< - void - > { - await beforeEachTest( - TestClientType.UnpartitionedQueueWithSessions, - autoRenewLockDurationInMs - ); - await testStreamingReceiverManualLockRenewalHappyCase(sender, receiver); - }); - - it("Partitioned Queue With Sessions - Lock Renewal for Sessions", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedQueueWithSessions, autoRenewLockDurationInMs); - await testStreamingReceiverManualLockRenewalHappyCase(sender, receiver); - }); + it( + testClientType + ": Batch Receiver: renewLock() resets lock duration each time", + async function(): Promise { + await beforeEachTest(0); + await testBatchReceiverManualLockRenewalHappyCase(sender, receiver); + } + ); - it("Unpartitioned Subscription With Sessions - Lock Renewal for Sessions", async function(): Promise< - void - > { - await beforeEachTest( - TestClientType.UnpartitionedSubscriptionWithSessions, - autoRenewLockDurationInMs - ); - await testStreamingReceiverManualLockRenewalHappyCase(sender, receiver); - }); + it( + testClientType + ": Batch Receiver: complete() after lock expiry with throws error", + async function(): Promise { + await beforeEachTest(0); + await testBatchReceiverManualLockRenewalErrorOnLockExpiry(testClientType, sender, receiver); + } + ); - it("Partitioned Subscription With Sessions - Lock Renewal for Sessions", async function(): Promise< - void - > { - await beforeEachTest( - TestClientType.PartitionedSubscriptionWithSessions, - autoRenewLockDurationInMs - ); + it( + testClientType + ": Streaming Receiver: renewLock() resets lock duration each time", + async function(): Promise { + await beforeEachTest(0); await testStreamingReceiverManualLockRenewalHappyCase(sender, receiver); - }); - }); - - describe("Streaming Receiver: complete() after lock expiry with auto-renewal disabled throws error", function(): void { - afterEach(() => { - return serviceBusClient.test.afterEach(); - }); - - const options: AutoLockRenewalTestOptions = { - autoRenewLockDurationInMs: 0, - delayBeforeAttemptingToCompleteMessageInSeconds: 31, - expectSessionLockLostErrorToBeThrown: true - }; - - it("Unpartitioned Queue With Sessions - Lock Renewal for Sessions", async function(): Promise< - void - > { - await beforeEachTest( - TestClientType.UnpartitionedQueueWithSessions, - options.autoRenewLockDurationInMs - ); - await testAutoLockRenewalConfigBehavior(sender, receiver, options); - }); - - it("Partitioned Queue With Sessions - Lock Renewal for Sessions", async function(): Promise< - void - > { - await beforeEachTest( - TestClientType.PartitionedQueueWithSessions, - options.autoRenewLockDurationInMs - ); - await testAutoLockRenewalConfigBehavior(sender, receiver, options); - }); - - it("Unpartitioned Subscription With Sessions - Lock Renewal for Sessions", async function(): Promise< - void - > { - await beforeEachTest( - TestClientType.UnpartitionedSubscriptionWithSessions, - options.autoRenewLockDurationInMs - ); - await testAutoLockRenewalConfigBehavior(sender, receiver, options); - }); + } + ); + + it( + testClientType + + ": Streaming Receiver: complete() after lock expiry with auto-renewal disabled throws error", + async function(): Promise { + const options: AutoLockRenewalTestOptions = { + autoRenewLockDurationInMs: 0, + delayBeforeAttemptingToCompleteMessageInSeconds: 31, + expectSessionLockLostErrorToBeThrown: true + }; - it("Partitioned Subscription With Sessions - Lock Renewal for Sessions", async function(): Promise< - void - > { - await beforeEachTest( - TestClientType.PartitionedSubscriptionWithSessions, - options.autoRenewLockDurationInMs - ); + await beforeEachTest(options.autoRenewLockDurationInMs); await testAutoLockRenewalConfigBehavior(sender, receiver, options); - }); - }); - - describe("Test AutoLockRenewalConfigBehavior - Unpartitioned Queue With Sessions", function(): void { - afterEach(() => { - return serviceBusClient.test.afterEach(); - }); + } + ); - it("Streaming Receiver: lock will not expire until configured time", async function(): Promise< - void - > { - autoRenewLockDurationInMs = 38 * 1000; - await beforeEachTest( - TestClientType.UnpartitionedQueueWithSessions, - autoRenewLockDurationInMs - ); - await testAutoLockRenewalConfigBehavior(sender, receiver, { - autoRenewLockDurationInMs, + it( + testClientType + ": Streaming Receiver: lock will not expire until configured time", + async function(): Promise { + const options: AutoLockRenewalTestOptions = { + autoRenewLockDurationInMs: 38 * 1000, delayBeforeAttemptingToCompleteMessageInSeconds: 35, expectSessionLockLostErrorToBeThrown: false - }); - }); + }; - it("Streaming Receiver: lock expires sometime after configured time", async function(): Promise< - void - > { - autoRenewLockDurationInMs = 35 * 1000; - await beforeEachTest( - TestClientType.UnpartitionedQueueWithSessions, - autoRenewLockDurationInMs - ); - await testAutoLockRenewalConfigBehavior(sender, receiver, { - autoRenewLockDurationInMs, - delayBeforeAttemptingToCompleteMessageInSeconds: 80, - expectSessionLockLostErrorToBeThrown: true - }); - }).timeout(95000); - - it("Receive a msg using Streaming Receiver, lock renewal does not take place when config value is less than lock duration", async function(): Promise< - void - > { - autoRenewLockDurationInMs = 15 * 1000; - await beforeEachTest( - TestClientType.UnpartitionedQueueWithSessions, - autoRenewLockDurationInMs - ); - await testAutoLockRenewalConfigBehavior(sender, receiver, { - autoRenewLockDurationInMs, - delayBeforeAttemptingToCompleteMessageInSeconds: 31, - expectSessionLockLostErrorToBeThrown: true - }); - }); - }); + await beforeEachTest(options.autoRenewLockDurationInMs); + await testAutoLockRenewalConfigBehavior(sender, receiver, options); + } + ); const lockDurationInMilliseconds = 30000; // const autoRenewLockDurationInMs = 300*1000; diff --git a/sdk/servicebus/service-bus/test/retries.spec.ts b/sdk/servicebus/service-bus/test/retries.spec.ts index 7a0b39f774df..e38de773777d 100644 --- a/sdk/servicebus/service-bus/test/retries.spec.ts +++ b/sdk/servicebus/service-bus/test/retries.spec.ts @@ -13,6 +13,7 @@ import { MessagingError } from "@azure/core-amqp"; import Long from "long"; import { BatchingReceiver } from "../src/core/batchingReceiver"; import { delay } from "rhea-promise"; +import { SessionReceiverImpl } from "../src/receivers/sessionReceiver"; describe("Retries - ManagementClient", () => { let sender: Sender; @@ -333,8 +334,13 @@ describe("Retries - Receive methods", () => { const batchingReceiver = BatchingReceiver.create((receiver as any)._context); batchingReceiver.isOpen = () => true; batchingReceiver.receive = fakeFunction; - // Mocking session creation to throw the error and fail - (receiver as any)._createMessageSessionIfDoesntExist = fakeFunction; + + if (receiver instanceof SessionReceiverImpl) { + // Mocking `_messageSession.receiveMessages()` to throw the error and fail + (receiver as SessionReceiverImpl)[ + "_messageSession" + ].receiveMessages = fakeFunction; + } } async function mockReceiveAndVerifyRetries(func: Function) { diff --git a/sdk/servicebus/service-bus/test/sendAndSchedule.spec.ts b/sdk/servicebus/service-bus/test/sendAndSchedule.spec.ts index 8ad86cc5797f..33c294e7160b 100644 --- a/sdk/servicebus/service-bus/test/sendAndSchedule.spec.ts +++ b/sdk/servicebus/service-bus/test/sendAndSchedule.spec.ts @@ -6,22 +6,31 @@ import Long from "long"; const should = chai.should(); import chaiAsPromised from "chai-as-promised"; chai.use(chaiAsPromised); -import { ServiceBusMessage, delay } from "../src"; +import { ServiceBusMessage, delay, ServiceBusClient } from "../src"; import { TestClientType, TestMessage } from "./utils/testUtils"; import { Receiver } from "../src/receivers/receiver"; import { ServiceBusClientForTests, createServiceBusClientForTests, - testPeekMsgsLength + testPeekMsgsLength, + getRandomTestClientTypeWithNoSessions, + getRandomTestClientTypeWithSessions, + EntityName, + getRandomTestClientType } from "./utils/testutils2"; import { Sender } from "../src/sender"; import { ReceivedMessageWithLock } from "../src/serviceBusMessage"; import { AbortController } from "@azure/abort-controller"; -describe("send scheduled messages", () => { +const noSessionTestClientType = getRandomTestClientTypeWithNoSessions(); +const withSessionTestClientType = getRandomTestClientTypeWithSessions(); +const anyRandomTestClientType = getRandomTestClientType(); + +describe("Sender Tests", () => { let sender: Sender; let receiver: Receiver; let serviceBusClient: ServiceBusClientForTests; + let entityName: EntityName; before(() => { serviceBusClient = createServiceBusClientForTests(); @@ -32,703 +41,286 @@ describe("send scheduled messages", () => { }); async function beforeEachTest(entityType: TestClientType): Promise { - const entityNames = await serviceBusClient.test.createTestEntities(entityType); - receiver = await serviceBusClient.test.getPeekLockReceiver(entityNames); + entityName = await serviceBusClient.test.createTestEntities(entityType); + receiver = await serviceBusClient.test.getPeekLockReceiver(entityName); sender = serviceBusClient.test.addToCleanup( - serviceBusClient.createSender(entityNames.queue ?? entityNames.topic!) + serviceBusClient.createSender(entityName.queue ?? entityName.topic!) ); } - async function afterEachTest(): Promise { + afterEach(async () => { await sender.close(); await receiver.close(); - } - - describe("Simple Send", function(): void { - afterEach(async () => { - await afterEachTest(); - }); - - async function testSimpleSend(useSessions: boolean, usePartitions: boolean): Promise { - const testMessage = useSessions ? TestMessage.getSessionSample() : TestMessage.getSample(); - await sender.sendMessages(testMessage); - const msgs = await receiver.receiveMessages(1); - - should.equal(Array.isArray(msgs), true, "`ReceivedMessages` is not an array"); - should.equal(msgs.length, 1, "Unexpected number of messages"); - should.equal(msgs[0].deliveryCount, 0, "DeliveryCount is different than expected"); - - TestMessage.checkMessageContents(testMessage, msgs[0], useSessions, usePartitions); - - await msgs[0].complete(); - - await testPeekMsgsLength(receiver, 0); - } - - it("Partitioned Queue: Simple Send", async function(): Promise { - await beforeEachTest(TestClientType.PartitionedQueue); - await testSimpleSend(false, true); - }); - - it("Partitioned Topic: Simple Send", async function(): Promise { - await beforeEachTest(TestClientType.PartitionedSubscription); - await testSimpleSend(false, true); - }); - - it("Unpartitioned Queue: Simple Send", async function(): Promise { - await beforeEachTest(TestClientType.UnpartitionedQueue); - await testSimpleSend(false, false); - }); - - it("Unpartitioned Topic: Simple Send", async function(): Promise { - await beforeEachTest(TestClientType.UnpartitionedSubscription); - await testSimpleSend(false, false); - }); - - it("Partitioned Queue with Sessions: Simple Send", async function(): Promise { - await beforeEachTest(TestClientType.PartitionedQueueWithSessions); - await testSimpleSend(true, true); - }); - - it("Partitioned Topic with Sessions: Simple Send", async function(): Promise { - await beforeEachTest(TestClientType.PartitionedSubscriptionWithSessions); - await testSimpleSend(true, true); - }); - - it("Unpartitioned Queue with Sessions: Simple Send", async function(): Promise { - await beforeEachTest(TestClientType.UnpartitionedQueueWithSessions); - await testSimpleSend(true, false); - }); - - it("Unpartitioned Topic with Sessions: Simple Send", async function(): Promise { - await beforeEachTest(TestClientType.UnpartitionedSubscriptionWithSessions); - await testSimpleSend(true, false); - }); }); - describe("Send array of messages", function(): void { - afterEach(async () => { - await afterEachTest(); - }); - - async function testSimpleSendBatch( - useSessions: boolean, - usePartitions: boolean - ): Promise { - const testMessages = []; - testMessages.push(useSessions ? TestMessage.getSessionSample() : TestMessage.getSample()); - testMessages.push(useSessions ? TestMessage.getSessionSample() : TestMessage.getSample()); - - await sender.sendMessages(testMessages); - const msgs = await receiver.receiveMessages(2); - - should.equal(Array.isArray(msgs), true, "`ReceivedMessages` is not an array"); - should.equal(msgs.length, 2, "Unexpected number of messages"); - - if (testMessages[0].messageId === msgs[0].messageId) { - TestMessage.checkMessageContents(testMessages[0], msgs[0], useSessions, usePartitions); - TestMessage.checkMessageContents(testMessages[1], msgs[1], useSessions, usePartitions); - } else { - TestMessage.checkMessageContents(testMessages[1], msgs[0], useSessions, usePartitions); - TestMessage.checkMessageContents(testMessages[0], msgs[1], useSessions, usePartitions); - } - - await msgs[0].complete(); - await msgs[1].complete(); - - await testPeekMsgsLength(receiver, 0); - } - - it("Partitioned Queue: Simple SendBatch", async function(): Promise { - await beforeEachTest(TestClientType.PartitionedQueue); - await testSimpleSendBatch(false, true); - }); - - it("Partitioned Topic: Simple SendBatch", async function(): Promise { - await beforeEachTest(TestClientType.PartitionedSubscription); - await testSimpleSendBatch(false, true); - }); - - it("Unpartitioned Queue: Simple SendBatch", async function(): Promise { - await beforeEachTest(TestClientType.UnpartitionedQueue); - await testSimpleSendBatch(false, false); - }); - - it("Unpartitioned Topic: Simple SendBatch", async function(): Promise { - await beforeEachTest(TestClientType.UnpartitionedSubscription); - await testSimpleSendBatch(false, false); - }); - - it("Partitioned Queue with Sessions: Simple SendBatch", async function(): Promise { - await beforeEachTest(TestClientType.PartitionedQueueWithSessions); - await testSimpleSendBatch(true, true); - }); + async function testSimpleSend(): Promise { + const testMessage = entityName.usesSessions + ? TestMessage.getSessionSample() + : TestMessage.getSample(); + await sender.sendMessages(testMessage); + const msgs = await receiver.receiveMessages(1); + + should.equal(Array.isArray(msgs), true, "`ReceivedMessages` is not an array"); + should.equal(msgs.length, 1, "Unexpected number of messages"); + should.equal(msgs[0].deliveryCount, 0, "DeliveryCount is different than expected"); + + TestMessage.checkMessageContents( + testMessage, + msgs[0], + entityName.usesSessions, + entityName.isPartitioned + ); - it("Partitioned Topic with Sessions: Simple SendBatch", async function(): Promise { - await beforeEachTest(TestClientType.PartitionedSubscriptionWithSessions); - await testSimpleSendBatch(true, true); - }); + await msgs[0].complete(); - it("Unpartitioned Queue with Sessions: Simple SendBatch", async function(): Promise { - await beforeEachTest(TestClientType.UnpartitionedQueueWithSessions); - await testSimpleSendBatch(true, false); - }); + await testPeekMsgsLength(receiver, 0); + } - it("Unpartitioned Topic with Sessions: Simple SendBatch", async function(): Promise { - await beforeEachTest(TestClientType.UnpartitionedSubscriptionWithSessions); - await testSimpleSendBatch(true, false); - }); + it(noSessionTestClientType + ": Send single message", async function(): Promise { + await beforeEachTest(noSessionTestClientType); + await testSimpleSend(); }); - describe("Schedule single message", function(): void { - afterEach(async () => { - await afterEachTest(); - }); - - /** - * Schedules a test message message to be sent at a later time, waits and then receives it - * @param useSessions Set to true if using session enabled queues or subscriptions - * @param passSequenceNumberInArray Boolean to indicate whether to pass the sequence number - * as is or in an array to ensure both get code coverage - */ - async function testScheduleMessage( - useSessions: boolean, - passSequenceNumberInArray: boolean - ): Promise { - const testMessage = useSessions ? TestMessage.getSessionSample() : TestMessage.getSample(); - const scheduleTime = new Date(Date.now() + 10000); // 10 seconds from - - await sender.scheduleMessages( - scheduleTime, - passSequenceNumberInArray ? [testMessage] : testMessage - ); - - const msgs = await receiver.receiveMessages(1); - const msgEnqueueTime = msgs[0].enqueuedTimeUtc ? msgs[0].enqueuedTimeUtc.valueOf() : 0; - - should.equal(Array.isArray(msgs), true, "`ReceivedMessages` is not an array"); - should.equal(msgs.length, 1, "Unexpected number of messages"); - should.equal( - msgEnqueueTime - scheduleTime.valueOf() >= 0, - true, - "Enqueued time must be greater than scheduled time" - ); // checking received message enqueue time is greater or equal to the scheduled time. - should.equal(msgs[0].body, testMessage.body, "MessageBody is different than expected"); - should.equal( - msgs[0].messageId, - testMessage.messageId, - "MessageId is different than expected" - ); - - await msgs[0].complete(); - - await testPeekMsgsLength(receiver, 0); - } - - it("Partitioned Queue: Schedule single message", async function(): Promise { - await beforeEachTest(TestClientType.PartitionedQueue); - await testScheduleMessage(false, true); - }); - - it("Partitioned Topic: Schedule single message", async function(): Promise { - await beforeEachTest(TestClientType.PartitionedSubscription); - await testScheduleMessage(false, false); - }); - - it("Unpartitioned Queue: Schedule single message", async function(): Promise { - await beforeEachTest(TestClientType.UnpartitionedQueue); - await testScheduleMessage(false, false); - }); - - it("Unpartitioned Topic: Schedule single message", async function(): Promise { - await beforeEachTest(TestClientType.UnpartitionedSubscription); - await testScheduleMessage(false, true); - }); - - it("Partitioned Queue with Sessions: Schedule single message", async function(): Promise { - await beforeEachTest(TestClientType.PartitionedQueueWithSessions); - await testScheduleMessage(true, true); - }); - - it("Partitioned Topic with Sessions: Schedule single message", async function(): Promise { - await beforeEachTest(TestClientType.PartitionedSubscriptionWithSessions); - await testScheduleMessage(true, true); - }); - - it("Unpartitioned Queue with Sessions: Schedule single message", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedQueueWithSessions); - await testScheduleMessage(true, false); - }); - - it("Unpartitioned Topic with Sessions: Schedule single message", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedSubscriptionWithSessions); - await testScheduleMessage(true, false); - }); + it(withSessionTestClientType + ": Send single message", async function(): Promise { + await beforeEachTest(withSessionTestClientType); + await testSimpleSend(); }); - describe("Schedule multiple messages", function(): void { - afterEach(async () => { - await afterEachTest(); - }); - - const messages: ServiceBusMessage[] = [ - { - body: "hello1", - messageId: `test message ${Math.random()}`, - partitionKey: "dummy" // partitionKey is only for partitioned queue/subscrption, Unpartitioned queue/subscrption do not care about partitionKey. - }, - { - body: "hello2", - messageId: `test message ${Math.random()}`, - partitionKey: "dummy" // partitionKey is only for partitioned queue/subscrption, Unpartitioned queue/subscrption do not care about partitionKey. - } - ]; - const messageWithSessions: ServiceBusMessage[] = [ - { - body: "hello1", - messageId: `test message ${Math.random()}`, - sessionId: TestMessage.sessionId - }, - { - body: "hello2", - messageId: `test message ${Math.random()}`, - sessionId: TestMessage.sessionId - } - ]; - - async function testScheduleMessages(useSessions?: boolean): Promise { - const testMessages = useSessions ? messageWithSessions : messages; - const scheduleTime = new Date(Date.now() + 10000); // 10 seconds from now - await sender.scheduleMessages(scheduleTime, testMessages); + async function testSimpleSendArray(): Promise { + const testMessages = []; + testMessages.push( + entityName.usesSessions ? TestMessage.getSessionSample() : TestMessage.getSample() + ); + testMessages.push( + entityName.usesSessions ? TestMessage.getSessionSample() : TestMessage.getSample() + ); - const msgs = await receiver.receiveMessages(2); - should.equal(Array.isArray(msgs), true, "`ReceivedMessages` is not an array"); - should.equal(msgs.length, 2, "Unexpected number of messages"); + await sender.sendMessages(testMessages); + const msgs = await receiver.receiveMessages(2); - const msgEnqueueTime1 = msgs[0].enqueuedTimeUtc ? msgs[0].enqueuedTimeUtc.valueOf() : 0; - const msgEnqueueTime2 = msgs[1].enqueuedTimeUtc ? msgs[1].enqueuedTimeUtc.valueOf() : 0; + should.equal(Array.isArray(msgs), true, "`ReceivedMessages` is not an array"); + should.equal(msgs.length, 2, "Unexpected number of messages"); - // checking received message enqueue time is greater or equal to the scheduled time. - should.equal( - msgEnqueueTime1 - scheduleTime.valueOf() >= 0, - true, - "msgEnqueueTime1 time must be greater than scheduled time" + if (testMessages[0].messageId === msgs[0].messageId) { + TestMessage.checkMessageContents( + testMessages[0], + msgs[0], + entityName.usesSessions, + entityName.isPartitioned ); - should.equal( - msgEnqueueTime2 - scheduleTime.valueOf() >= 0, - true, - "msgEnqueueTime2 time must be greater than scheduled time" + TestMessage.checkMessageContents( + testMessages[1], + msgs[1], + entityName.usesSessions, + entityName.isPartitioned ); - should.equal( - testMessages.some((x) => x.messageId === msgs[0].messageId), - true, - "MessageId of first message is different than expected" + } else { + TestMessage.checkMessageContents( + testMessages[1], + msgs[0], + entityName.usesSessions, + entityName.isPartitioned ); - should.equal( - testMessages.some((x) => x.messageId === msgs[1].messageId), - true, - "MessageId of second message is different than expected" + TestMessage.checkMessageContents( + testMessages[0], + msgs[1], + entityName.usesSessions, + entityName.isPartitioned ); - - await msgs[0].complete(); - await msgs[1].complete(); - - await testPeekMsgsLength(receiver, 0); } - it("Partitioned Queue: Schedule multiple messages", async function(): Promise { - await beforeEachTest(TestClientType.PartitionedQueue); - await testScheduleMessages(); - }); - - it("Partitioned Topic: Schedule multiple messages", async function(): Promise { - await beforeEachTest(TestClientType.PartitionedSubscription); - await testScheduleMessages(); - }); - - it("UnPartitioned Queue: Schedule multiple messages", async function(): Promise { - await beforeEachTest(TestClientType.UnpartitionedQueue); - await testScheduleMessages(); - }); - - it("UnPartitioned Topic: Schedule multiple messages", async function(): Promise { - await beforeEachTest(TestClientType.UnpartitionedSubscription); - await testScheduleMessages(); - }); - - it("Partitioned Queue with Sessions: Schedule multiple messages", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedQueueWithSessions); - await testScheduleMessages(true); - }); + await msgs[0].complete(); + await msgs[1].complete(); - it("Partitioned Topic with Sessions: Schedule multiple messages", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedSubscriptionWithSessions); - await testScheduleMessages(true); - }); + await testPeekMsgsLength(receiver, 0); + } - it("Unpartitioned Queue with Sessions: Schedule multiple messages", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedQueueWithSessions); - await testScheduleMessages(true); - }); + it(noSessionTestClientType + ": Send Array of messages", async function(): Promise { + await beforeEachTest(noSessionTestClientType); + await testSimpleSendArray(); + }); - it("Unpartitioned Topic with Sessions: Schedule multiple messages", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedSubscriptionWithSessions); - await testScheduleMessages(true); - }); + it(withSessionTestClientType + ": Send Array of messages", async function(): Promise { + await beforeEachTest(withSessionTestClientType); + await testSimpleSendArray(); }); - describe("Cancel single Scheduled message", function(): void { - afterEach(async () => { - await afterEachTest(); - }); + async function testScheduleSingleMessage(): Promise { + const testMessage = entityName.usesSessions + ? TestMessage.getSessionSample() + : TestMessage.getSample(); + const scheduleTime = new Date(Date.now() + 10000); // 10 seconds from - async function testCancelScheduleMessage(useSessions?: boolean): Promise { - const testMessage = useSessions ? TestMessage.getSessionSample() : TestMessage.getSample(); - const scheduleTime = new Date(Date.now() + 30000); // 30 seconds from now as anything less gives inconsistent results for cancelling - const [sequenceNumber] = await sender.scheduleMessages(scheduleTime, testMessage); + await sender.scheduleMessages(scheduleTime, testMessage); - await delay(2000); + const msgs = await receiver.receiveMessages(1); + const msgEnqueueTime = msgs[0].enqueuedTimeUtc ? msgs[0].enqueuedTimeUtc.valueOf() : 0; - await sender.cancelScheduledMessages(sequenceNumber); + should.equal(Array.isArray(msgs), true, "`ReceivedMessages` is not an array"); + should.equal(msgs.length, 1, "Unexpected number of messages"); + should.equal( + msgEnqueueTime - scheduleTime.valueOf() >= 0, + true, + "Enqueued time must be greater than scheduled time" + ); // checking received message enqueue time is greater or equal to the scheduled time. + should.equal(msgs[0].body, testMessage.body, "MessageBody is different than expected"); + should.equal(msgs[0].messageId, testMessage.messageId, "MessageId is different than expected"); - // Wait until we are sure we have passed the schedule time - await delay(30000); - await testReceivedMsgsLength(receiver, 0); - } + await msgs[0].complete(); - it("Partitioned Queue: Cancel single Scheduled message", async function(): Promise { - await beforeEachTest(TestClientType.PartitionedQueue); - await testCancelScheduleMessage(); - }); + await testPeekMsgsLength(receiver, 0); + } - it("Partitioned Topic: Cancel single Scheduled message", async function(): Promise { - await beforeEachTest(TestClientType.PartitionedSubscription); - await testCancelScheduleMessage(); - }); + async function testScheduleMultipleMessages(): Promise { + const testMessages = entityName.usesSessions + ? [TestMessage.getSessionSample(), TestMessage.getSessionSample()] + : [TestMessage.getSample(), TestMessage.getSample()]; + const scheduleTime = new Date(Date.now() + 10000); // 10 seconds from now + await sender.scheduleMessages(scheduleTime, testMessages); - it("Unpartitioned Queue: Cancel single Scheduled message", async function(): Promise { - await beforeEachTest(TestClientType.UnpartitionedQueue); - await testCancelScheduleMessage(); - }); + const msgs = await receiver.receiveMessages(2); + should.equal(Array.isArray(msgs), true, "`ReceivedMessages` is not an array"); + should.equal(msgs.length, 2, "Unexpected number of messages"); - it("Unpartitioned Topic: Cancel single Scheduled message", async function(): Promise { - await beforeEachTest(TestClientType.UnpartitionedSubscription); - await testCancelScheduleMessage(); - }); + const msgEnqueueTime1 = msgs[0].enqueuedTimeUtc ? msgs[0].enqueuedTimeUtc.valueOf() : 0; + const msgEnqueueTime2 = msgs[1].enqueuedTimeUtc ? msgs[1].enqueuedTimeUtc.valueOf() : 0; - it("Partitioned Queue with Sessions: Cancel single Scheduled message", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedQueueWithSessions); - await testCancelScheduleMessage(true); - }); + // checking received message enqueue time is greater or equal to the scheduled time. + should.equal( + msgEnqueueTime1 - scheduleTime.valueOf() >= 0, + true, + "msgEnqueueTime1 time must be greater than scheduled time" + ); + should.equal( + msgEnqueueTime2 - scheduleTime.valueOf() >= 0, + true, + "msgEnqueueTime2 time must be greater than scheduled time" + ); + should.equal( + testMessages.some((x) => x.messageId === msgs[0].messageId), + true, + "MessageId of first message is different than expected" + ); + should.equal( + testMessages.some((x) => x.messageId === msgs[1].messageId), + true, + "MessageId of second message is different than expected" + ); - it("Partitioned Topic with Sessions: Cancel single Scheduled message", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedSubscriptionWithSessions); - await testCancelScheduleMessage(true); - }); + await msgs[0].complete(); + await msgs[1].complete(); - it("Unpartitioned Queue with Sessions: Cancel single Scheduled message", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedQueueWithSessions); - await testCancelScheduleMessage(true); - }); + await testPeekMsgsLength(receiver, 0); + } - it("Unpartitioned Topic with Sessions: Cancel single Scheduled message", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedSubscriptionWithSessions); - await testCancelScheduleMessage(true); - }); + it(anyRandomTestClientType + ": Schedule single message", async function(): Promise { + await beforeEachTest(anyRandomTestClientType); + await testScheduleSingleMessage(); }); - describe("Cancel multiple Scheduled messages", function(): void { - afterEach(async () => { - await afterEachTest(); - }); - - async function testCancelScheduleMessages(useSessions?: boolean): Promise { - const getTestMessage = useSessions ? TestMessage.getSessionSample : TestMessage.getSample; - - const scheduleTime = new Date(Date.now() + 30000); // 30 seconds from now as anything less gives inconsistent results for cancelling - const [sequenceNumber1, sequenceNumber2] = await sender.scheduleMessages(scheduleTime, [ - getTestMessage(), - getTestMessage() - ]); + it(anyRandomTestClientType + ": Schedule multiple messages", async function(): Promise { + await beforeEachTest(anyRandomTestClientType); + await testScheduleMultipleMessages(); + }); - await delay(2000); + async function testCancelSingleScheduledMessage(): Promise { + const testMessage = entityName.usesSessions + ? TestMessage.getSessionSample() + : TestMessage.getSample(); + const scheduleTime = new Date(Date.now() + 30000); // 30 seconds from now as anything less gives inconsistent results for cancelling + const [sequenceNumber] = await sender.scheduleMessages(scheduleTime, testMessage); - await sender.cancelScheduledMessages([sequenceNumber1, sequenceNumber2]); + await delay(2000); - // Wait until we are sure we have passed the schedule time - await delay(30000); - await testReceivedMsgsLength(receiver, 0); - } + await sender.cancelScheduledMessages(sequenceNumber); - it("Partitioned Queue: Cancel scheduled messages", async function(): Promise { - await beforeEachTest(TestClientType.PartitionedQueue); - await testCancelScheduleMessages(false); - }); + // Wait until we are sure we have passed the schedule time + await delay(30000); + await testReceivedMsgsLength(receiver, 0); + } - it("Partitioned Topic: Cancel scheduled messages", async function(): Promise { - await beforeEachTest(TestClientType.PartitionedSubscription); - await testCancelScheduleMessages(false); - }); + async function testCancelMultipleScheduleMessages(): Promise { + const getTestMessage = entityName.usesSessions + ? TestMessage.getSessionSample + : TestMessage.getSample; - it("Unpartitioned Queue: Cancel scheduled messages", async function(): Promise { - await beforeEachTest(TestClientType.UnpartitionedQueue); - await testCancelScheduleMessages(false); - }); + const scheduleTime = new Date(Date.now() + 30000); // 30 seconds from now as anything less gives inconsistent results for cancelling + const [sequenceNumber1, sequenceNumber2] = await sender.scheduleMessages(scheduleTime, [ + getTestMessage(), + getTestMessage() + ]); - it("Unpartitioned Topic: Cancel scheduled messages", async function(): Promise { - await beforeEachTest(TestClientType.UnpartitionedSubscription); - await testCancelScheduleMessages(false); - }); + await delay(2000); - it("Partitioned Queue with Sessions: Cancel scheduled messages", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedQueueWithSessions); - await testCancelScheduleMessages(true); - }); + await sender.cancelScheduledMessages([sequenceNumber1, sequenceNumber2]); - it("Partitioned Topic with Sessions: Cancel scheduled messages", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedSubscriptionWithSessions); - await testCancelScheduleMessages(true); - }); - - it("Unpartitioned Queue with Sessions: Cancel scheduled messages", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedQueueWithSessions); - await testCancelScheduleMessages(true); - }); + // Wait until we are sure we have passed the schedule time + await delay(30000); + await testReceivedMsgsLength(receiver, 0); + } - it("Unpartitioned Topic with Sessions: Cancel scheduled messages", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedSubscriptionWithSessions); - await testCancelScheduleMessages(true); - }); + it(anyRandomTestClientType + ": Cancel single Scheduled message", async function(): Promise< + void + > { + await beforeEachTest(anyRandomTestClientType); + await testCancelSingleScheduledMessage(); }); - describe("Miscellaneous", function(): void { - afterEach(async () => { - await afterEachTest(); - }); - - it("Schedule messages in parallel", async () => { - await beforeEachTest(TestClientType.UnpartitionedQueue); - const date = new Date(); - const messages = [ - { body: "Hello!" }, - { body: "Hello, again!" }, - { body: "Hello, again and again!!" } - ]; - let [result1, result2, result3] = await Promise.all([ - // Schedule messages in parallel - sender.scheduleMessages(date, messages[0]), - sender.scheduleMessages(date, messages[1]), - sender.scheduleMessages(date, messages[2]) - ]); - const sequenceNumbers = [result1[0], result2[0], result3[0]] - compareSequenceNumbers(sequenceNumbers[0], sequenceNumbers[1]); - compareSequenceNumbers(sequenceNumbers[0], sequenceNumbers[2]); - compareSequenceNumbers(sequenceNumbers[1], sequenceNumbers[2]); - - function compareSequenceNumbers(sequenceNumber1: Long.Long, sequenceNumber2: Long.Long) { - should.equal( - sequenceNumber1.compare(sequenceNumber2) != 0, - true, - "Returned sequence numbers for parallel requests are the same" - ); - } - - const receivedMsgs = await receiver.receiveMessages(3); - should.equal(receivedMsgs.length, 3, "Unexpected number of messages"); - for (const seqNum of sequenceNumbers) { - const msgWithSeqNum = receivedMsgs.find( - ({ sequenceNumber }) => sequenceNumber?.comp(seqNum) === 0 - ); - should.equal( - msgWithSeqNum == undefined, - false, - `Sequence number ${seqNum} is not found in the received messages!` - ); - should.equal( - msgWithSeqNum?.body, - messages[sequenceNumbers.indexOf(seqNum)].body, - "Message body did not match though the sequence numbers matched!" - ); - await msgWithSeqNum?.complete(); - } - - await testPeekMsgsLength(receiver, 0); - }); + it(anyRandomTestClientType + ": Cancel multiple Scheduled messages", async function(): Promise< + void + > { + await beforeEachTest(anyRandomTestClientType); + await testCancelMultipleScheduleMessages(); }); - describe("ServiceBusMessage validations", function(): void { - const longString = - "A very very very very very very very very very very very very very very very very very very very very very very very very very long string."; - after(async () => { - await afterEachTest(); - }); - - before(async () => { - await beforeEachTest(TestClientType.PartitionedQueue); - }); - - const testInputs: { - message: ServiceBusMessage; - expectedErrorMessage: string; - title?: string; - }[] = [ - { - message: { body: "", contentType: 1 as any }, - expectedErrorMessage: "The property 'contentType' on the message must be of type 'string'", - title: "contenType is of invalid type" - }, - { - message: { body: "", label: 1 as any }, - expectedErrorMessage: "The property 'label' on the message must be of type 'string'", - title: "label is of invalid type" - }, - { - message: { body: "", to: 1 as any }, - expectedErrorMessage: "The property 'to' on the message must be of type 'string'", - title: "to is of invalid type" - }, - { - message: { body: "", replyToSessionId: 1 as any }, - expectedErrorMessage: - "The property 'replyToSessionId' on the message must be of type 'string'", - title: "replyToSessionId is of invalid type" - }, - { - message: { body: "", sessionId: 1 as any }, - expectedErrorMessage: "The property 'sessionId' on the message must be of type 'string'", - title: "sessionId is of invalid type" - }, - { - message: { body: "", replyTo: 1 as any }, - expectedErrorMessage: "The property 'replyTo' on the message must be of type 'string'", - title: "replyTo is of invalid type" - }, - { - message: { body: "", timeToLive: "" as any }, - expectedErrorMessage: "The property 'timeToLive' on the message must be of type 'number'", - title: "timeToLive is of invalid type" - }, - { - message: { body: "", partitionKey: longString }, - expectedErrorMessage: - "Length of 'partitionKey' property on the message cannot be greater than 128 characters.", - title: "partitionKey is longer than 128 characters" - }, - { - message: { body: "", viaPartitionKey: longString }, - expectedErrorMessage: - "Length of 'viaPartitionKey' property on the message cannot be greater than 128 characters.", - title: "viaPartitionKey is longer than 128 characters" - }, - { - message: { body: "", sessionId: longString }, - expectedErrorMessage: - "Length of 'sessionId' property on the message cannot be greater than 128 characters.", - title: "sessionId is longer than 128 characters" - }, - { - message: { body: "", messageId: longString }, - expectedErrorMessage: - "Length of 'messageId' property on the message cannot be greater than 128 characters.", - title: "messageId is longer than 128 characters" - }, - { - message: { body: "", messageId: {} as any }, - expectedErrorMessage: - "The property 'messageId' on the message must be of type string, number or Buffer", - title: "messageId is of invalid type" - }, - { - message: { body: "", correlationId: {} as any }, - expectedErrorMessage: - "The property 'correlationId' on the message must be of type string, number or Buffer", - title: "correlationId is of invalid type" - } + it(anyRandomTestClientType + ": Schedule messages in parallel", async () => { + await beforeEachTest(TestClientType.UnpartitionedQueue); + const date = new Date(); + const messages = [ + { body: "Hello!" }, + { body: "Hello, again!" }, + { body: "Hello, again and again!!" } ]; + let [result1, result2, result3] = await Promise.all([ + // Schedule messages in parallel + sender.scheduleMessages(date, messages[0]), + sender.scheduleMessages(date, messages[1]), + sender.scheduleMessages(date, messages[2]) + ]); + const sequenceNumbers = [result1[0], result2[0], result3[0]]; + compareSequenceNumbers(sequenceNumbers[0], sequenceNumbers[1]); + compareSequenceNumbers(sequenceNumbers[0], sequenceNumbers[2]); + compareSequenceNumbers(sequenceNumbers[1], sequenceNumbers[2]); + + function compareSequenceNumbers(sequenceNumber1: Long.Long, sequenceNumber2: Long.Long) { + should.equal( + sequenceNumber1.compare(sequenceNumber2) != 0, + true, + "Returned sequence numbers for parallel requests are the same" + ); + } - testInputs.forEach(function(testInput: any): void { - it("SendMessages() throws if " + testInput.title, async function(): Promise { - let actualErrorMsg = ""; - await sender.sendMessages(testInput.message).catch((err) => { - actualErrorMsg = err.message; - }); - should.equal( - actualErrorMsg, - testInput.expectedErrorMessage, - "Error not thrown as expected" - ); - }); + const receivedMsgs = await receiver.receiveMessages(3); + should.equal(receivedMsgs.length, 3, "Unexpected number of messages"); + for (const seqNum of sequenceNumbers) { + const msgWithSeqNum = receivedMsgs.find( + ({ sequenceNumber }) => sequenceNumber?.comp(seqNum) === 0 + ); + should.equal( + msgWithSeqNum == undefined, + false, + `Sequence number ${seqNum} is not found in the received messages!` + ); + should.equal( + msgWithSeqNum?.body, + messages[sequenceNumbers.indexOf(seqNum)].body, + "Message body did not match though the sequence numbers matched!" + ); + await msgWithSeqNum?.complete(); + } - // sendBatch() - Commented - // it( - // "SendBatch() throws if in the first message, " + testInput.title, - // async function(): Promise { - // let actualErrorMsg = ""; - // await sender.sendBatch([testInput.message, { body: "random" }]).catch((err) => { - // actualErrorMsg = err.message; - // }); - // should.equal( - // actualErrorMsg, - // testInput.expectedErrorMessage, - // "Error not thrown as expected" - // ); - // } - // ); - - // it( - // "SendBatch() throws if in the subsequent message, " + testInput.title, - // async function(): Promise { - // let actualErrorMsg = ""; - // await sender.sendBatch([{ body: "random" }, testInput.message]).catch((err) => { - // actualErrorMsg = err.message; - // }); - // should.equal( - // actualErrorMsg, - // testInput.expectedErrorMessage, - // "Error not thrown as expected" - // ); - // } - // ); - - it("ScheduleMessages() throws if " + testInput.title, async function(): Promise { - let actualErrorMsg = ""; - let actualErr; - await sender.scheduleMessages(new Date(), testInput.message).catch((err) => { - actualErr = err; - actualErrorMsg = err.message; - }); - should.equal(actualErrorMsg, testInput.expectedErrorMessage, actualErr); - }); - }); + await testPeekMsgsLength(receiver, 0); }); async function testReceivedMsgsLength( @@ -746,9 +338,10 @@ describe("send scheduled messages", () => { ); } - describe("Cancel operations on the sender", function(): void { - it("Abort scheduleMessages request on the sender", async function(): Promise { - await beforeEachTest(TestClientType.PartitionedQueue); + it( + anyRandomTestClientType + ": Abort scheduleMessages request on the sender", + async function(): Promise { + await beforeEachTest(anyRandomTestClientType); const controller = new AbortController(); setTimeout(() => controller.abort(), 1); try { @@ -759,10 +352,13 @@ describe("send scheduled messages", () => { } catch (err) { err.message.should.equal("The scheduleMessages operation has been cancelled by the user."); } - }); + } + ); - it("Abort cancelScheduledMessages request on the sender", async function(): Promise { - await beforeEachTest(TestClientType.PartitionedQueue); + it( + anyRandomTestClientType + ": Abort cancelScheduledMessages request on the sender", + async function(): Promise { + await beforeEachTest(anyRandomTestClientType); const controller = new AbortController(); setTimeout(() => controller.abort(), 1); try { @@ -773,6 +369,145 @@ describe("send scheduled messages", () => { "The cancelScheduledMessages operation has been cancelled by the user." ); } + } + ); +}); + +describe("ServiceBusMessage validations", function(): void { + const sbClient = new ServiceBusClient( + "Endpoint=sb://a;SharedAccessKeyName=b;SharedAccessKey=c;EntityPath=d" + ); + const sender = sbClient.createSender("dummyQueue"); + const longString = + "A very very very very very very very very very very very very very very very very very very very very very very very very very long string."; + + const testInputs: { + message: ServiceBusMessage; + expectedErrorMessage: string; + title?: string; + }[] = [ + { + message: { body: "", contentType: 1 as any }, + expectedErrorMessage: "The property 'contentType' on the message must be of type 'string'", + title: "contenType is of invalid type" + }, + { + message: { body: "", label: 1 as any }, + expectedErrorMessage: "The property 'label' on the message must be of type 'string'", + title: "label is of invalid type" + }, + { + message: { body: "", to: 1 as any }, + expectedErrorMessage: "The property 'to' on the message must be of type 'string'", + title: "to is of invalid type" + }, + { + message: { body: "", replyToSessionId: 1 as any }, + expectedErrorMessage: + "The property 'replyToSessionId' on the message must be of type 'string'", + title: "replyToSessionId is of invalid type" + }, + { + message: { body: "", sessionId: 1 as any }, + expectedErrorMessage: "The property 'sessionId' on the message must be of type 'string'", + title: "sessionId is of invalid type" + }, + { + message: { body: "", replyTo: 1 as any }, + expectedErrorMessage: "The property 'replyTo' on the message must be of type 'string'", + title: "replyTo is of invalid type" + }, + { + message: { body: "", timeToLive: "" as any }, + expectedErrorMessage: "The property 'timeToLive' on the message must be of type 'number'", + title: "timeToLive is of invalid type" + }, + { + message: { body: "", partitionKey: longString }, + expectedErrorMessage: + "Length of 'partitionKey' property on the message cannot be greater than 128 characters.", + title: "partitionKey is longer than 128 characters" + }, + { + message: { body: "", viaPartitionKey: longString }, + expectedErrorMessage: + "Length of 'viaPartitionKey' property on the message cannot be greater than 128 characters.", + title: "viaPartitionKey is longer than 128 characters" + }, + { + message: { body: "", sessionId: longString }, + expectedErrorMessage: + "Length of 'sessionId' property on the message cannot be greater than 128 characters.", + title: "sessionId is longer than 128 characters" + }, + { + message: { body: "", messageId: longString }, + expectedErrorMessage: + "Length of 'messageId' property on the message cannot be greater than 128 characters.", + title: "messageId is longer than 128 characters" + }, + { + message: { body: "", messageId: {} as any }, + expectedErrorMessage: + "The property 'messageId' on the message must be of type string, number or Buffer", + title: "messageId is of invalid type" + }, + { + message: { body: "", correlationId: {} as any }, + expectedErrorMessage: + "The property 'correlationId' on the message must be of type string, number or Buffer", + title: "correlationId is of invalid type" + } + ]; + + testInputs.forEach(function(testInput: any): void { + it("SendMessages() throws if " + testInput.title, async function(): Promise { + let actualErrorMsg = ""; + await sender.sendMessages(testInput.message).catch((err) => { + actualErrorMsg = err.message; + }); + should.equal(actualErrorMsg, testInput.expectedErrorMessage, "Error not thrown as expected"); + }); + + // sendBatch() - Commented + // it( + // "SendBatch() throws if in the first message, " + testInput.title, + // async function(): Promise { + // let actualErrorMsg = ""; + // await sender.sendBatch([testInput.message, { body: "random" }]).catch((err) => { + // actualErrorMsg = err.message; + // }); + // should.equal( + // actualErrorMsg, + // testInput.expectedErrorMessage, + // "Error not thrown as expected" + // ); + // } + // ); + + // it( + // "SendBatch() throws if in the subsequent message, " + testInput.title, + // async function(): Promise { + // let actualErrorMsg = ""; + // await sender.sendBatch([{ body: "random" }, testInput.message]).catch((err) => { + // actualErrorMsg = err.message; + // }); + // should.equal( + // actualErrorMsg, + // testInput.expectedErrorMessage, + // "Error not thrown as expected" + // ); + // } + // ); + + it("ScheduleMessages() throws if " + testInput.title, async function(): Promise { + let actualErrorMsg = ""; + let actualErr; + await sender.scheduleMessages(new Date(), testInput.message).catch((err) => { + actualErr = err; + actualErrorMsg = err.message; + }); + should.equal(actualErrorMsg, testInput.expectedErrorMessage, actualErr); }); }); }); diff --git a/sdk/servicebus/service-bus/test/sendBatch.spec.ts b/sdk/servicebus/service-bus/test/sendBatch.spec.ts index 26f6464df95c..580ece982382 100644 --- a/sdk/servicebus/service-bus/test/sendBatch.spec.ts +++ b/sdk/servicebus/service-bus/test/sendBatch.spec.ts @@ -10,7 +10,9 @@ import { TestClientType } from "./utils/testUtils"; import { EntityName, ServiceBusClientForTests, - createServiceBusClientForTests + createServiceBusClientForTests, + getRandomTestClientTypeWithSessions, + getRandomTestClientTypeWithNoSessions } from "./utils/testutils2"; import { Sender } from "../src/sender"; import { ConditionErrorNameMapper } from "@azure/core-amqp"; @@ -20,6 +22,8 @@ describe("Send Batch", () => { let serviceBusClient: ServiceBusClientForTests; let entityNames: EntityName; + let noSessionTestClientType = getRandomTestClientTypeWithNoSessions(); + let withSessionTestClientType = getRandomTestClientTypeWithSessions(); before(() => { serviceBusClient = createServiceBusClientForTests(); @@ -85,43 +89,13 @@ describe("Send Batch", () => { ); } - it("Partitioned Queue: SendBatch", async function(): Promise { - await beforeEachTest(TestClientType.PartitionedQueue); + it(`${noSessionTestClientType}: SendBatch`, async function(): Promise { + await beforeEachTest(noSessionTestClientType); await testSendBatch(false); }); - it("Partitioned Topic: SendBatch", async function(): Promise { - await beforeEachTest(TestClientType.PartitionedSubscription); - await testSendBatch(false); - }); - - it("Unpartitioned Queue: SendBatch", async function(): Promise { - await beforeEachTest(TestClientType.UnpartitionedQueue); - await testSendBatch(false); - }); - - it("Unpartitioned Topic: SendBatch", async function(): Promise { - await beforeEachTest(TestClientType.UnpartitionedSubscription); - await testSendBatch(false); - }); - - it("Partitioned Queue with Sessions: SendBatch", async function(): Promise { - await beforeEachTest(TestClientType.PartitionedQueueWithSessions); - await testSendBatch(true); - }); - - it("Partitioned Topic with Sessions: SendBatch", async function(): Promise { - await beforeEachTest(TestClientType.PartitionedSubscriptionWithSessions); - await testSendBatch(true); - }); - - it("Unpartitioned Queue with Sessions: SendBatch", async function(): Promise { - await beforeEachTest(TestClientType.UnpartitionedQueueWithSessions); - await testSendBatch(true); - }); - - it("Unpartitioned Topic with Sessions: SendBatch", async function(): Promise { - await beforeEachTest(TestClientType.UnpartitionedSubscriptionWithSessions); + it(`${withSessionTestClientType}: SendBatch`, async function(): Promise { + await beforeEachTest(withSessionTestClientType); await testSendBatch(true); }); }); @@ -246,43 +220,13 @@ describe("Send Batch", () => { ); } - it("Partitioned Queue: SendBatch", async function(): Promise { - await beforeEachTest(TestClientType.PartitionedQueue); + it(`${noSessionTestClientType}: SendBatch`, async function(): Promise { + await beforeEachTest(noSessionTestClientType); await testSendBatch(false); }); - it("Partitioned Topic: SendBatch", async function(): Promise { - await beforeEachTest(TestClientType.PartitionedSubscription); - await testSendBatch(false); - }); - - it("Unpartitioned Queue: SendBatch", async function(): Promise { - await beforeEachTest(TestClientType.UnpartitionedQueue); - await testSendBatch(false); - }); - - it("Unpartitioned Topic: SendBatch", async function(): Promise { - await beforeEachTest(TestClientType.UnpartitionedSubscription); - await testSendBatch(false); - }); - - it("Partitioned Queue with Sessions: SendBatch", async function(): Promise { - await beforeEachTest(TestClientType.PartitionedQueueWithSessions); - await testSendBatch(true); - }); - - it("Partitioned Topic with Sessions: SendBatch", async function(): Promise { - await beforeEachTest(TestClientType.PartitionedSubscriptionWithSessions); - await testSendBatch(true); - }); - - it("Unpartitioned Queue with Sessions: SendBatch", async function(): Promise { - await beforeEachTest(TestClientType.UnpartitionedQueueWithSessions); - await testSendBatch(true); - }); - - it("Unpartitioned Topic with Sessions: SendBatch", async function(): Promise { - await beforeEachTest(TestClientType.UnpartitionedSubscriptionWithSessions); + it(`${withSessionTestClientType}: SendBatch`, async function(): Promise { + await beforeEachTest(withSessionTestClientType); await testSendBatch(true); }); }); @@ -325,43 +269,13 @@ describe("Send Batch", () => { ); } - it("Partitioned Queue: SendBatch", async function(): Promise { - await beforeEachTest(TestClientType.PartitionedQueue); - await testSendBatch(false); - }); - - it("Partitioned Topic: SendBatch", async function(): Promise { - await beforeEachTest(TestClientType.PartitionedSubscription); + it(`${noSessionTestClientType}: SendBatch`, async function(): Promise { + await beforeEachTest(noSessionTestClientType); await testSendBatch(false); }); - it("Unpartitioned Queue: SendBatch", async function(): Promise { - await beforeEachTest(TestClientType.UnpartitionedQueue); - await testSendBatch(false); - }); - - it("Unpartitioned Topic: SendBatch", async function(): Promise { - await beforeEachTest(TestClientType.UnpartitionedSubscription); - await testSendBatch(false); - }); - - it("Partitioned Queue with Sessions: SendBatch", async function(): Promise { - await beforeEachTest(TestClientType.PartitionedQueueWithSessions); - await testSendBatch(true); - }); - - it("Partitioned Topic with Sessions: SendBatch", async function(): Promise { - await beforeEachTest(TestClientType.PartitionedSubscriptionWithSessions); - await testSendBatch(true); - }); - - it("Unpartitioned Queue with Sessions: SendBatch", async function(): Promise { - await beforeEachTest(TestClientType.UnpartitionedQueueWithSessions); - await testSendBatch(true); - }); - - it("Unpartitioned Topic with Sessions: SendBatch", async function(): Promise { - await beforeEachTest(TestClientType.UnpartitionedSubscriptionWithSessions); + it(`${withSessionTestClientType}: SendBatch`, async function(): Promise { + await beforeEachTest(withSessionTestClientType); await testSendBatch(true); }); }); @@ -423,43 +337,13 @@ describe("Send Batch", () => { ); } - it("Partitioned Queue: SendBatch", async function(): Promise { - await beforeEachTest(TestClientType.PartitionedQueue); + it(`${noSessionTestClientType}: SendBatch`, async function(): Promise { + await beforeEachTest(noSessionTestClientType); await testSendBatch(false); }); - it("Partitioned Topic: SendBatch", async function(): Promise { - await beforeEachTest(TestClientType.PartitionedSubscription); - await testSendBatch(false); - }); - - it("Unpartitioned Queue: SendBatch", async function(): Promise { - await beforeEachTest(TestClientType.UnpartitionedQueue); - await testSendBatch(false); - }); - - it("Unpartitioned Topic: SendBatch", async function(): Promise { - await beforeEachTest(TestClientType.UnpartitionedSubscription); - await testSendBatch(false); - }); - - it("Partitioned Queue with Sessions: SendBatch", async function(): Promise { - await beforeEachTest(TestClientType.PartitionedQueueWithSessions); - await testSendBatch(true); - }); - - it("Partitioned Topic with Sessions: SendBatch", async function(): Promise { - await beforeEachTest(TestClientType.PartitionedSubscriptionWithSessions); - await testSendBatch(true); - }); - - it("Unpartitioned Queue with Sessions: SendBatch", async function(): Promise { - await beforeEachTest(TestClientType.UnpartitionedQueueWithSessions); - await testSendBatch(true); - }); - - it("Unpartitioned Topic with Sessions: SendBatch", async function(): Promise { - await beforeEachTest(TestClientType.UnpartitionedSubscriptionWithSessions); + it(`${withSessionTestClientType}: SendBatch`, async function(): Promise { + await beforeEachTest(withSessionTestClientType); await testSendBatch(true); }); }); @@ -530,43 +414,13 @@ describe("Send Batch", () => { ]); } - it("Partitioned Queue: SendBatch", async function(): Promise { - await beforeEachTest(TestClientType.PartitionedQueue); + it(`${noSessionTestClientType}: SendBatch`, async function(): Promise { + await beforeEachTest(noSessionTestClientType); await testSendBatch(false, 5000); }); - it("Partitioned Topic: SendBatch", async function(): Promise { - await beforeEachTest(TestClientType.PartitionedSubscription); - await testSendBatch(false, 5000); - }); - - it("Unpartitioned Queue: SendBatch", async function(): Promise { - await beforeEachTest(TestClientType.UnpartitionedQueue); - await testSendBatch(false, 5000); - }); - - it("Unpartitioned Topic: SendBatch", async function(): Promise { - await beforeEachTest(TestClientType.UnpartitionedSubscription); - await testSendBatch(false, 5000); - }); - - it("Partitioned Queue with Sessions: SendBatch", async function(): Promise { - await beforeEachTest(TestClientType.PartitionedQueueWithSessions); - await testSendBatch(true, 5000); - }); - - it("Partitioned Topic with Sessions: SendBatch", async function(): Promise { - await beforeEachTest(TestClientType.PartitionedSubscriptionWithSessions); - await testSendBatch(true, 5000); - }); - - it("Unpartitioned Queue with Sessions: SendBatch", async function(): Promise { - await beforeEachTest(TestClientType.UnpartitionedQueueWithSessions); - await testSendBatch(true, 5000); - }); - - it("Unpartitioned Topic with Sessions: SendBatch", async function(): Promise { - await beforeEachTest(TestClientType.UnpartitionedSubscriptionWithSessions); + it(`${withSessionTestClientType}: SendBatch`, async function(): Promise { + await beforeEachTest(withSessionTestClientType); await testSendBatch(true, 5000); }); }); @@ -596,43 +450,13 @@ describe("Send Batch", () => { ); } - it("Partitioned Queue: SendBatch", async function(): Promise { - await beforeEachTest(TestClientType.PartitionedQueue); - await testSendBatch(maxSizeInBytes); - }); - - it("Partitioned Topic: SendBatch", async function(): Promise { - await beforeEachTest(TestClientType.PartitionedSubscription); + it(`${noSessionTestClientType}: SendBatch`, async function(): Promise { + await beforeEachTest(noSessionTestClientType); await testSendBatch(maxSizeInBytes); }); - it("Unpartitioned Queue: SendBatch", async function(): Promise { - await beforeEachTest(TestClientType.UnpartitionedQueue); - await testSendBatch(maxSizeInBytes); - }); - - it("Unpartitioned Topic: SendBatch", async function(): Promise { - await beforeEachTest(TestClientType.UnpartitionedSubscription); - await testSendBatch(maxSizeInBytes); - }); - - it("Partitioned Queue with Sessions: SendBatch", async function(): Promise { - await beforeEachTest(TestClientType.PartitionedQueueWithSessions); - await testSendBatch(maxSizeInBytes); - }); - - it("Partitioned Topic with Sessions: SendBatch", async function(): Promise { - await beforeEachTest(TestClientType.PartitionedSubscriptionWithSessions); - await testSendBatch(maxSizeInBytes); - }); - - it("Unpartitioned Queue with Sessions: SendBatch", async function(): Promise { - await beforeEachTest(TestClientType.UnpartitionedQueueWithSessions); - await testSendBatch(maxSizeInBytes); - }); - - it("Unpartitioned Topic with Sessions: SendBatch", async function(): Promise { - await beforeEachTest(TestClientType.UnpartitionedSubscriptionWithSessions); + it(`${withSessionTestClientType}: SendBatch`, async function(): Promise { + await beforeEachTest(withSessionTestClientType); await testSendBatch(maxSizeInBytes); }); }); diff --git a/sdk/servicebus/service-bus/test/serviceBusClient.spec.ts b/sdk/servicebus/service-bus/test/serviceBusClient.spec.ts index a1eb7e9da08b..897248df69cf 100644 --- a/sdk/servicebus/service-bus/test/serviceBusClient.spec.ts +++ b/sdk/servicebus/service-bus/test/serviceBusClient.spec.ts @@ -8,11 +8,7 @@ import * as dotenv from "dotenv"; import Long from "long"; import { MessagingError, Receiver, ServiceBusClient, SessionReceiver } from "../src"; import { Sender } from "../src/sender"; -import { - DispositionType, - ReceivedMessageWithLock, - ServiceBusMessage -} from "../src/serviceBusMessage"; +import { DispositionType, ReceivedMessageWithLock } from "../src/serviceBusMessage"; import { getReceiverClosedErrorMsg, getSenderClosedErrorMsg } from "../src/util/errors"; import { EnvVarNames, getEnvVars, isNode } from "../test/utils/envVarUtils"; import { checkWithTimeout, isMessagingError, TestClientType, TestMessage } from "./utils/testUtils"; @@ -20,7 +16,9 @@ import { createServiceBusClientForTests, EntityName, ServiceBusClientForTests, - testPeekMsgsLength + testPeekMsgsLength, + getRandomTestClientTypeWithSessions, + getRandomTestClientTypeWithNoSessions } from "./utils/testutils2"; const should = chai.should(); @@ -28,6 +26,9 @@ chai.use(chaiAsPromised); dotenv.config(); +const noSessionTestClientType = getRandomTestClientTypeWithNoSessions(); +const withSessionTestClientType = getRandomTestClientTypeWithSessions(); + describe("Create ServiceBusClient", function(): void { let sbClient: ServiceBusClient; @@ -49,35 +50,29 @@ describe("Create ServiceBusClient", function(): void { }); describe("Random scheme in the endpoint from connection string", function(): void { - let sbClient: ServiceBusClientForTests; - let sbClientWithRelaxedEndPoint: ServiceBusClient; - let entities: EntityName; - let sender: Sender; - let receiver: Receiver; - - async function beforeEachTest(testClientType: TestClientType) { - sbClient = createServiceBusClientForTests(); - entities = await sbClient.test.createTestEntities(testClientType); + it(noSessionTestClientType + ": send and receive message", async function(): Promise { + // Create a test client to get the entity types + const sbClient = createServiceBusClientForTests(); + const entities = await sbClient.test.createTestEntities(noSessionTestClientType); await sbClient.close(); - sbClientWithRelaxedEndPoint = new ServiceBusClient( + + // Create a sb client, sender, receiver with relaxed endpoint + const sbClientWithRelaxedEndPoint = new ServiceBusClient( getEnvVars().SERVICEBUS_CONNECTION_STRING.replace("sb://", "CheeseBurger://") ); - sender = sbClientWithRelaxedEndPoint.createSender(entities.queue!); - receiver = !entities.usesSessions - ? sbClientWithRelaxedEndPoint.createReceiver(entities.queue!, "peekLock") - : await sbClientWithRelaxedEndPoint.createSessionReceiver(entities.queue!, "peekLock", { - sessionId: TestMessage.sessionId - }); - } - - afterEach(async () => { - await sbClient.test.after(); - await sender.close(); - await receiver.close(); - await sbClientWithRelaxedEndPoint.close(); - }); + const sender = sbClientWithRelaxedEndPoint.createSender(entities.queue || entities.topic!); + const receiver = entities.queue + ? sbClientWithRelaxedEndPoint.createReceiver(entities.queue, "peekLock") + : sbClientWithRelaxedEndPoint.createReceiver( + entities.topic!, + entities.subscription!, + "peekLock" + ); - async function sendReceiveMsg(testMessages: ServiceBusMessage): Promise { + // Send and receive messages + const testMessages = entities.usesSessions + ? TestMessage.getSessionSample() + : TestMessage.getSample(); await sender.sendMessages(testMessages); await testPeekMsgsLength(receiver, 1); @@ -91,18 +86,12 @@ describe("Random scheme in the endpoint from connection string", function(): voi await msgs[0].complete(); await testPeekMsgsLength(receiver, 0); - } - - it("Partitioned Queue: send and receive message", async function(): Promise { - await beforeEachTest(TestClientType.PartitionedQueue); - await sendReceiveMsg(TestMessage.getSample()); - }); - it("Unpartitioned Queue With Sessions: send and receive message", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedQueueWithSessions); - await sendReceiveMsg(TestMessage.getSessionSample()); + // Clean up + await sbClient.test.after(); + await sender.close(); + await receiver.close(); + await sbClientWithRelaxedEndPoint.close(); }); }); @@ -274,7 +263,7 @@ describe("Errors with non existing Queue/Topic/Subscription", async function(): }); }); -describe("Test ServiceBusClient creation", function(): void { +describe("Test ServiceBusClient with TokenCredentials", function(): void { let errorWasThrown: boolean = false; const env = getEnvVars(); @@ -350,27 +339,31 @@ describe("Test ServiceBusClient creation", function(): void { should.equal(errorWasThrown, true, "Error thrown flag must be true"); }); - it("sends a message to the ServiceBus entity", async function(): Promise { - const tokenCreds = getDefaultTokenCredential(); + it( + noSessionTestClientType + ": sends a message to the ServiceBus entity", + async function(): Promise { + const tokenCreds = getDefaultTokenCredential(); - const serviceBusClient = createServiceBusClientForTests(); - const entities = await serviceBusClient.test.createTestEntities( - TestClientType.UnpartitionedQueue - ); - await serviceBusClient.close(); - - const sbClient = new ServiceBusClient(serviceBusEndpoint, tokenCreds); - const sender = sbClient.createSender(entities.queue!); - const receiver = sbClient.createReceiver(entities.queue!, "peekLock"); - const testMessages = TestMessage.getSample(); - await sender.sendMessages(testMessages); - const msgs = await receiver.receiveMessages(1); - - should.equal(Array.isArray(msgs), true, "`ReceivedMessages` is not an array"); - should.equal(msgs[0].body, testMessages.body, "MessageBody is different than expected"); - should.equal(msgs.length, 1, "Unexpected number of messages"); - await sbClient.close(); - }); + const serviceBusClient = createServiceBusClientForTests(); + const entities = await serviceBusClient.test.createTestEntities(noSessionTestClientType); + await serviceBusClient.close(); + + const sbClient = new ServiceBusClient(serviceBusEndpoint, tokenCreds); + const sender = sbClient.createSender(entities.queue || entities.topic!); + const receiver = entities.queue + ? sbClient.createReceiver(entities.queue!, "peekLock") + : sbClient.createReceiver(entities.topic!, entities.subscription!, "peekLock"); + + const testMessages = TestMessage.getSample(); + await sender.sendMessages(testMessages); + const msgs = await receiver.receiveMessages(1); + + should.equal(Array.isArray(msgs), true, "`ReceivedMessages` is not an array"); + should.equal(msgs[0].body, testMessages.body, "MessageBody is different than expected"); + should.equal(msgs.length, 1, "Unexpected number of messages"); + await sbClient.close(); + } + ); } }); @@ -636,40 +629,21 @@ describe("Errors after close()", function(): void { const entityToClose = "namespace"; const expectedErrorMsg = "The underlying AMQP connection is closed."; - it("Unpartitioned Queue: errors after close() on namespace", async function(): Promise { - await beforeEachTest(TestClientType.UnpartitionedQueue, entityToClose); - - await testSender(expectedErrorMsg); - await testCreateSender(expectedErrorMsg); - await testReceiver(expectedErrorMsg); - await testCreateReceiver(expectedErrorMsg); - }); - - it("Unpartitioned Queue with sessions: errors after close() on namespace", async function(): Promise< + it(noSessionTestClientType + ": errors after close() on namespace", async function(): Promise< void > { - await beforeEachTest(TestClientType.UnpartitionedQueueWithSessions, entityToClose); - - await testSender(expectedErrorMsg); - await testCreateSender(expectedErrorMsg); - await testSessionReceiver(expectedErrorMsg); - await testCreateReceiver(expectedErrorMsg); - }); + await beforeEachTest(noSessionTestClientType, entityToClose); - it("Unpartitioned Topic/Subscription: errors after close() on namespace", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedSubscription, entityToClose); await testSender(expectedErrorMsg); await testCreateSender(expectedErrorMsg); await testReceiver(expectedErrorMsg); await testCreateReceiver(expectedErrorMsg); }); - it("Unpartitioned Topic/Subscription with sessions: errors after close() on namespace", async function(): Promise< + it(withSessionTestClientType + ": errors after close() on namespace", async function(): Promise< void > { - await beforeEachTest(TestClientType.UnpartitionedSubscriptionWithSessions, entityToClose); + await beforeEachTest(withSessionTestClientType, entityToClose); await testSender(expectedErrorMsg); await testCreateSender(expectedErrorMsg); @@ -681,131 +655,118 @@ describe("Errors after close()", function(): void { describe("Errors after close() on receiver", function(): void { const entityToClose = "receiver"; - it("Unpartitioned Queue: errors after close() on receiver", async function(): Promise { - await beforeEachTest(TestClientType.UnpartitionedQueue, entityToClose); - - await testReceiver(getReceiverClosedErrorMsg(receiver.entityPath, false)); - }); - - it("Unpartitioned Queue with sessions: errors after close() on receiver", async function(): Promise< + it(noSessionTestClientType + ": errors after close() on receiver", async function(): Promise< void > { - await beforeEachTest(TestClientType.UnpartitionedQueueWithSessions, entityToClose); + await beforeEachTest(noSessionTestClientType, entityToClose); - await testReceiver( - getReceiverClosedErrorMsg(receiver.entityPath, false, TestMessage.sessionId) - ); + await testReceiver(getReceiverClosedErrorMsg(receiver.entityPath)); }); - it("Unpartitioned Topic/Subscription: errors after close() on receiver", async function(): Promise< + it(withSessionTestClientType + ": errors after close() on receiver", async function(): Promise< void > { - await beforeEachTest(TestClientType.UnpartitionedSubscription, entityToClose); + await beforeEachTest(withSessionTestClientType, entityToClose); - await testReceiver(getReceiverClosedErrorMsg(receiver.entityPath, false)); - }); + await testReceiver(getReceiverClosedErrorMsg(receiver.entityPath, TestMessage.sessionId)); - it("Unpartitioned Topic/Subscription with sessions: errors after close() on receiver", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedSubscriptionWithSessions, entityToClose); - - await testSessionReceiver( - getReceiverClosedErrorMsg(receiver.entityPath, false, TestMessage.sessionId) - ); + await testAllDispositions(); }); }); describe("Errors after close() on sender", function(): void { const entityToClose = "sender"; - it("Unpartitioned Queue: errors after close() on sender", async function(): Promise { - await beforeEachTest(TestClientType.UnpartitionedQueue, entityToClose); - await testSender(getSenderClosedErrorMsg(sender.entityPath)); - }); - - it("Unpartitioned Topic: errors after close() on sender", async function(): Promise { - await beforeEachTest(TestClientType.UnpartitionedSubscription, entityToClose); - await testSender(getSenderClosedErrorMsg(sender.entityPath)); - }); - }); - - describe("Errors after close() on receiver", function(): void { - const entityToClose = "receiver"; - - it("Unpartitioned Queue with sessions: errors after close() on receiver", async function(): Promise< + it(noSessionTestClientType + ": errors after close() on sender", async function(): Promise< void > { - await beforeEachTest(TestClientType.UnpartitionedQueueWithSessions, entityToClose); - - await testSessionReceiver( - getReceiverClosedErrorMsg(receiver.entityPath, false, TestMessage.sessionId) - ); - await testAllDispositions(); + await beforeEachTest(noSessionTestClientType, entityToClose); + await testSender(getSenderClosedErrorMsg(sender.entityPath)); }); }); }); describe("entityPath on sender and receiver", async () => { - const sbClient = createServiceBusClientForTests(); + let sbClient: ServiceBusClientForTests; + + before(() => { + sbClient = createServiceBusClientForTests(); + }); + afterEach(async () => { await sbClient.test.afterEach(); }); after(async () => { await sbClient.test.after(); }); - it("UnpartitionedQueue", async () => { - const entityName = await sbClient.test.createTestEntities(TestClientType.UnpartitionedQueue); - const sender = sbClient.test.addToCleanup(sbClient.createSender(entityName.queue!)); - const receiver = sbClient.test.addToCleanup( - sbClient.createReceiver(entityName.queue!, "receiveAndDelete") - ); - const deadLetterReceiver = sbClient.test.addToCleanup( - sbClient.createDeadLetterReceiver(entityName.queue!, "receiveAndDelete") + + it("Entity Path on Sender", () => { + const dummyQueueOrTopicName = "dummy"; + const sender = sbClient.createSender(dummyQueueOrTopicName); + should.equal( + sender.entityPath, + dummyQueueOrTopicName, + "Entity path on the sender did not match!" ); - should.equal(sender.entityPath, entityName.queue, "Entity path on the sender did not match!"); + }); + + it("Entity Path on Queue Receiver", () => { + const dummyQueueName = "dummy"; + const receiver = sbClient.createReceiver(dummyQueueName, "peekLock"); should.equal( receiver.entityPath, - entityName.queue, - "Entity path on the receiver did not match!" + dummyQueueName, + "Entity path on the receiver for queue did not match!" ); + }); + + it("Entity Path on Queue deadletter Receiver", () => { + const dummyQueueName = "dummy"; + const receiver = sbClient.createDeadLetterReceiver(dummyQueueName, "peekLock"); should.equal( - deadLetterReceiver.entityPath, - `${entityName.queue}/$DeadLetterQueue`, - "Entity path on the deadLetterReceiver did not match!" + receiver.entityPath, + `${dummyQueueName}/$DeadLetterQueue`, + "Entity path on the receiver for queue did not match!" ); }); - it("PartitionedSubscriptionWithSessions", async () => { - const entityName = await sbClient.test.createTestEntities( - TestClientType.PartitionedSubscriptionWithSessions - ); - const sender = sbClient.test.addToCleanup(sbClient.createSender(entityName.topic!)); - const receiver = sbClient.test.addToCleanup( - await sbClient.createSessionReceiver( - entityName.topic!, - entityName.subscription!, - "receiveAndDelete", - { sessionId: TestMessage.sessionId } - ) + it("Entity Path on Subscription Receiver", () => { + const dummyTopicName = "dummyTopicName"; + const dummySubscriptionName = "dummySubscriptionName"; + const receiver = sbClient.createReceiver(dummyTopicName, dummySubscriptionName, "peekLock"); + should.equal( + receiver.entityPath, + `${dummyTopicName}/Subscriptions/${dummySubscriptionName}`, + "Entity path on the receiver for subscription did not match!" ); - const deadLetterReceiver = sbClient.test.addToCleanup( - sbClient.createDeadLetterReceiver( - entityName.topic!, - entityName.subscription!, - "receiveAndDelete" - ) + }); + + it("Entity Path on Subscription deadletter Receiver", () => { + const dummyTopicName = "dummyTopicName"; + const dummySubscriptionName = "dummySubscriptionName"; + const receiver = sbClient.createDeadLetterReceiver( + dummyTopicName, + dummySubscriptionName, + "peekLock" ); - should.equal(sender.entityPath, entityName.topic, "Entity path on the sender did not match!"); should.equal( receiver.entityPath, - `${entityName.topic}/Subscriptions/${entityName.subscription}`, - "Entity path on the receiver did not match!" + `${dummyTopicName}/Subscriptions/${dummySubscriptionName}/$DeadLetterQueue`, + "Entity path on the receiver for subscription did not match!" ); + }); + + it(withSessionTestClientType + ": EntityPath on Session Receiver", async () => { + const entityName = await sbClient.test.createTestEntities(withSessionTestClientType); + + const receiver = await sbClient.test.getPeekLockReceiver(entityName); + const expectedEntityPath = entityName.queue + ? entityName.queue + : `${entityName.topic}/Subscriptions/${entityName.subscription}`; should.equal( - deadLetterReceiver.entityPath, - `${entityName.topic}/Subscriptions/${entityName.subscription}/$DeadLetterQueue`, - "Entity path on the deadLetterReceiver did not match!" + receiver.entityPath, + expectedEntityPath, + "Entity path on the session receiver for did not match!" ); }); }); diff --git a/sdk/servicebus/service-bus/test/sessionsRequiredCleanEntityTests.spec.ts b/sdk/servicebus/service-bus/test/sessionsRequiredCleanEntityTests.spec.ts index 4dadd845a003..6ffcabfdb53c 100644 --- a/sdk/servicebus/service-bus/test/sessionsRequiredCleanEntityTests.spec.ts +++ b/sdk/servicebus/service-bus/test/sessionsRequiredCleanEntityTests.spec.ts @@ -5,11 +5,12 @@ import chai from "chai"; import { ServiceBusClientForTests, createServiceBusClientForTests, - testPeekMsgsLength + testPeekMsgsLength, + getRandomTestClientTypeWithSessions } from "./utils/testutils2"; import { Sender } from "../src/sender"; import { ServiceBusMessage, SessionReceiver } from "../src"; -import { TestClientType, TestMessage } from "./utils/testUtils"; +import { TestMessage } from "./utils/testUtils"; import { ReceivedMessageWithLock } from "../src/serviceBusMessage"; const should = chai.should(); @@ -24,7 +25,9 @@ describe("sessions tests - requires completely clean entity for each test", () let sender: Sender; let receiver: SessionReceiver; - async function beforeEachNoSessionTest(testClientType: TestClientType): Promise { + let testClientType = getRandomTestClientTypeWithSessions(); + + async function beforeEachNoSessionTest(): Promise { serviceBusClient = createServiceBusClientForTests(); const entityNames = await serviceBusClient.test.createTestEntities(testClientType); @@ -60,15 +63,12 @@ describe("sessions tests - requires completely clean entity for each test", () await afterEachTest(); }); - async function eachTest(testClientType: TestClientType, useSessionId: boolean) { - await beforeEachNoSessionTest(testClientType); - await peekSession(testClientType, useSessionId); + async function eachTest(useSessionId: boolean) { + await beforeEachNoSessionTest(); + await peekSession(useSessionId); } - async function peekSession( - testClientType: TestClientType, - useSessionId: boolean - ): Promise { + async function peekSession(useSessionId: boolean): Promise { const testMessage = TestMessage.getSessionSample(); await sender.sendMessages(testMessage); @@ -112,37 +112,16 @@ describe("sessions tests - requires completely clean entity for each test", () await msgs[0].complete(); } - it("Partitioned Queue - Peek Session with sessionId", async function(): Promise { - await eachTest(TestClientType.PartitionedQueueWithSessions, true); - }); - it("Partitioned Subscription - Peek Session with sessionId", async function(): Promise { - await eachTest(TestClientType.PartitionedSubscriptionWithSessions, true); - }); - it("Unpartitioned Queue - Peek Session with sessionId", async function(): Promise { - await eachTest(TestClientType.UnpartitionedQueueWithSessions, true); - }); - it("Unpartitioned Subscription - Peek Session with sessionId", async function(): Promise { - await eachTest(TestClientType.UnpartitionedSubscriptionWithSessions, true); - }); - it("Partitioned Queue - Peek Session without sessionId", async function(): Promise { - await eachTest(TestClientType.PartitionedQueueWithSessions, false); + it(testClientType + " - Peek Session with sessionId", async function(): Promise { + await eachTest(true); }); - it("Partitioned Subscription - Peek Session without sessionId", async function(): Promise< - void - > { - await eachTest(TestClientType.PartitionedSubscriptionWithSessions, false); - }); - it("Unpartitioned Queue - Peek Session without sessionId", async function(): Promise { - await eachTest(TestClientType.UnpartitionedQueueWithSessions, false); - }); - it("Unpartitioned Subscription - Peek Session without sessionId", async function(): Promise< - void - > { - await eachTest(TestClientType.UnpartitionedSubscriptionWithSessions, false); + + it(testClientType + " - Peek Session without sessionId", async function(): Promise { + await eachTest(false); }); }); - describe("SessionReceiver with no sessionId", function(): void { + describe(testClientType + ": SessionReceiver with no sessionId", function(): void { const testSessionId2 = "my-session2"; afterEach(async () => { @@ -162,7 +141,7 @@ describe("sessions tests - requires completely clean entity for each test", () } ]; - async function testComplete_batching(testClientType: TestClientType): Promise { + async function testComplete_batching(): Promise { await sender.sendMessages(testMessagesWithDifferentSessionIds[0]); await sender.sendMessages(testMessagesWithDifferentSessionIds[1]); @@ -207,36 +186,13 @@ describe("sessions tests - requires completely clean entity for each test", () await testPeekMsgsLength(receiver, 0); } - it("Partitioned Queue: complete() removes message from random session", async function(): Promise< - void - > { - await beforeEachNoSessionTest(TestClientType.PartitionedQueueWithSessions); - await testComplete_batching(TestClientType.PartitionedQueueWithSessions); - }); - - it("Partitioned Subscription: complete() removes message from random session", async function(): Promise< - void - > { - await beforeEachNoSessionTest(TestClientType.PartitionedSubscriptionWithSessions); - await testComplete_batching(TestClientType.PartitionedSubscriptionWithSessions); - }); - - it("Unpartitioned Queue: complete() removes message from random session", async function(): Promise< - void - > { - await beforeEachNoSessionTest(TestClientType.UnpartitionedQueueWithSessions); - await testComplete_batching(TestClientType.UnpartitionedQueueWithSessions); - }); - - it("Unpartitioned Subscription: complete() removes message from random session", async function(): Promise< - void - > { - await beforeEachNoSessionTest(TestClientType.UnpartitionedSubscriptionWithSessions); - await testComplete_batching(TestClientType.UnpartitionedSubscriptionWithSessions); + it("complete() removes message from random session", async function(): Promise { + await beforeEachNoSessionTest(); + await testComplete_batching(); }); }); - describe("SessionReceiver with empty string as sessionId", function(): void { + describe(testClientType + ": SessionReceiver with empty string as sessionId", function(): void { afterEach(async () => { await afterEachTest(); }); @@ -256,7 +212,7 @@ describe("sessions tests - requires completely clean entity for each test", () } ]; - async function testComplete_batching(testClientType: TestClientType): Promise { + async function testComplete_batching(): Promise { await sender.sendMessages(testMessagesWithDifferentSessionIds[0]); await sender.sendMessages(testMessagesWithDifferentSessionIds[1]); @@ -287,32 +243,9 @@ describe("sessions tests - requires completely clean entity for each test", () await receiver.close(); } - it("Partitioned Queue: complete() removes message from random session", async function(): Promise< - void - > { - await beforeEachNoSessionTest(TestClientType.PartitionedQueueWithSessions); - await testComplete_batching(TestClientType.PartitionedQueueWithSessions); - }); - - it("Partitioned Subscription: complete() removes message from random session", async function(): Promise< - void - > { - await beforeEachNoSessionTest(TestClientType.PartitionedSubscriptionWithSessions); - await testComplete_batching(TestClientType.PartitionedSubscriptionWithSessions); - }); - - it("Unpartitioned Queue: complete() removes message from random session", async function(): Promise< - void - > { - await beforeEachNoSessionTest(TestClientType.UnpartitionedQueueWithSessions); - await testComplete_batching(TestClientType.UnpartitionedQueueWithSessions); - }); - - it("Unpartitioned Subscription: complete() removes message from random session", async function(): Promise< - void - > { - await beforeEachNoSessionTest(TestClientType.UnpartitionedSubscriptionWithSessions); - await testComplete_batching(TestClientType.UnpartitionedSubscriptionWithSessions); + it("complete() removes message from random session", async function(): Promise { + await beforeEachNoSessionTest(); + await testComplete_batching(); }); }); }); diff --git a/sdk/servicebus/service-bus/test/sessionsTests.spec.ts b/sdk/servicebus/service-bus/test/sessionsTests.spec.ts index 6905034afbb4..90a071e5f91d 100644 --- a/sdk/servicebus/service-bus/test/sessionsTests.spec.ts +++ b/sdk/servicebus/service-bus/test/sessionsTests.spec.ts @@ -15,7 +15,8 @@ import { EntityName, ServiceBusClientForTests, createServiceBusClientForTests, - testPeekMsgsLength + testPeekMsgsLength, + getRandomTestClientTypeWithSessions } from "./utils/testutils2"; import { ReceivedMessageWithLock } from "../src/serviceBusMessage"; import { AbortController } from "@azure/abort-controller"; @@ -32,8 +33,9 @@ describe("session tests", () => { let serviceBusClient: ServiceBusClientForTests; let sender: Sender; let receiver: SessionReceiver; + let testClientType = getRandomTestClientTypeWithSessions(); - async function beforeEachTest(testClientType: TestClientType, sessionId?: string): Promise { + async function beforeEachTest(sessionId?: string): Promise { serviceBusClient = createServiceBusClientForTests(); const entityNames = await serviceBusClient.test.createTestEntities(testClientType); @@ -62,22 +64,25 @@ describe("session tests", () => { // } } - async function afterEachTest(): Promise { + afterEach(async () => { await serviceBusClient.test.afterEach(); await serviceBusClient.test.after(); - } + }); - describe("createSessionReceiver error scenarios", function(): void { - it("No sessionId on empty queue throws OperationTimeoutError", async function(): Promise< + describe(`${testClientType}: Session Receiver Tests`, function(): void { + it("createSessionReceiver() No sessionId on empty queue throws OperationTimeoutError", async function(): Promise< void > { let expectedErrorThrown = false; let unexpectedError; try { - await beforeEachTest(TestClientType.PartitionedQueueWithSessions); + await beforeEachTest(); } catch (error) { // TODO: https://github.com/Azure/azure-sdk-for-js/issues/9775 to figure out why we get two different errors. - if (isMessagingError(error) && (error.code === "OperationTimeoutError" || error.code === "SessionCannotBeLockedError")) { + if ( + isMessagingError(error) && + (error.code === "OperationTimeoutError" || error.code === "SessionCannotBeLockedError") + ) { expectedErrorThrown = true; } else { unexpectedError = error; @@ -91,12 +96,12 @@ describe("session tests", () => { await serviceBusClient.close(); }); - it("An already locked session throws SessionCannotBeLockedError", async function(): Promise< + it("createSessionReceiver() An already locked session throws SessionCannotBeLockedError", async function(): Promise< void > { let expectedErrorThrown = false; let unexpectedError; - await beforeEachTest(TestClientType.PartitionedQueueWithSessions, "boo"); + await beforeEachTest("boo"); try { await serviceBusClient.test.getSessionPeekLockReceiver( { queue: receiver.entityPath, usesSessions: true }, @@ -116,19 +121,12 @@ describe("session tests", () => { ); await serviceBusClient.close(); }); - }); - - describe("SessionReceiver with invalid sessionId", function(): void { - const nonExistentSessionId: string = "non" + TestMessage.sessionId; - // beforeEach(() => { - // sessionId = ; - // }); - afterEach(async () => { - await afterEachTest(); - }); - - async function test_batching(testClientType: TestClientType): Promise { + it("Batch Receiver: no messages received for invalid sessionId", async function(): Promise< + void + > { + const nonExistentSessionId: string = "non" + TestMessage.sessionId; + await beforeEachTest(nonExistentSessionId); const testMessage = TestMessage.getSessionSample(); await sender.sendMessages(testMessage); @@ -153,43 +151,13 @@ describe("session tests", () => { ); await msgs[0].complete(); await testPeekMsgsLength(receiver, 0); - } - - it("Partitioned Queue - Batch Receiver: no messages received for invalid sessionId", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedQueueWithSessions, nonExistentSessionId); - await test_batching(TestClientType.PartitionedQueueWithSessions); }); - it("Partitioned Subscription - Batch Receiver: no messages received for invalid sessionId", async function(): Promise< + it("Streaming Receiver: no messages received for invalid sessionId", async function(): Promise< void > { - await beforeEachTest( - TestClientType.PartitionedSubscriptionWithSessions, - nonExistentSessionId - ); - await test_batching(TestClientType.PartitionedSubscriptionWithSessions); - }); - - it("Unpartitioned Queue - Batch Receiver: no messages received for invalid sessionId", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedQueueWithSessions, nonExistentSessionId); - await test_batching(TestClientType.UnpartitionedQueueWithSessions); - }); - - it("Unpartitioned Subscription - Batch Receiver: no messages received for invalid sessionId", async function(): Promise< - void - > { - await beforeEachTest( - TestClientType.UnpartitionedSubscriptionWithSessions, - nonExistentSessionId - ); - await test_batching(TestClientType.UnpartitionedSubscriptionWithSessions); - }); - - async function test_streaming(testClientType: TestClientType): Promise { + const nonExistentSessionId: string = "non" + TestMessage.sessionId; + await beforeEachTest(nonExistentSessionId); const testMessage = TestMessage.getSessionSample(); await sender.sendMessages(testMessage); @@ -233,49 +201,10 @@ describe("session tests", () => { should.equal(unexpectedError, undefined, unexpectedError && unexpectedError.message); await testPeekMsgsLength(receiver, 0); - } - - it("Partitioned Queue - Streaming Receiver: no messages received for invalid sessionId", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedQueueWithSessions, nonExistentSessionId); - await test_streaming(TestClientType.PartitionedQueueWithSessions); }); - it("Partitioned Subscription - Streaming Receiver: no messages received for invalid sessionId", async function(): Promise< - void - > { - await beforeEachTest( - TestClientType.PartitionedSubscriptionWithSessions, - nonExistentSessionId - ); - await test_streaming(TestClientType.PartitionedSubscriptionWithSessions); - }); - - it("Unpartitioned Queue - Streaming Receiver: no messages received for invalid sessionId", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedQueueWithSessions, nonExistentSessionId); - await test_streaming(TestClientType.UnpartitionedQueueWithSessions); - }); - - it("Unpartitioned Subscription - Streaming Receiver: no messages received for invalid sessionId", async function(): Promise< - void - > { - await beforeEachTest( - TestClientType.UnpartitionedSubscriptionWithSessions, - nonExistentSessionId - ); - await test_streaming(TestClientType.UnpartitionedSubscriptionWithSessions); - }); - }); - - describe("Session State", function(): void { - afterEach(async () => { - await afterEachTest(); - }); - - async function testGetSetState(testClientType: TestClientType): Promise { + it("Testing getState and setState", async function(): Promise { + await beforeEachTest(TestMessage.sessionId); const testMessage = TestMessage.getSessionSample(); await sender.sendMessages(testMessage); @@ -330,40 +259,10 @@ describe("session tests", () => { await receiver.setState(""); // clearing the session-state await msgs[0].complete(); await testPeekMsgsLength(receiver, 0); - } - it("Partitioned Queue - Testing getState and setState", async function(): Promise { - await beforeEachTest(TestClientType.PartitionedQueueWithSessions, TestMessage.sessionId); - await testGetSetState(TestClientType.PartitionedQueueWithSessions); - }); - it("Partitioned Subscription - Testing getState and setState", async function(): Promise { - await beforeEachTest( - TestClientType.PartitionedSubscriptionWithSessions, - TestMessage.sessionId - ); - await testGetSetState(TestClientType.PartitionedSubscriptionWithSessions); - }); - it("Unpartitioned Queue - Testing getState and setState", async function(): Promise { - await beforeEachTest(TestClientType.UnpartitionedQueueWithSessions, TestMessage.sessionId); - await testGetSetState(TestClientType.UnpartitionedQueueWithSessions); - }); - it("Unpartitioned Subscription - Testing getState and setState", async function(): Promise< - void - > { - await beforeEachTest( - TestClientType.UnpartitionedSubscriptionWithSessions, - TestMessage.sessionId - ); - await testGetSetState(TestClientType.UnpartitionedSubscriptionWithSessions); - }); - }); - - describe("Cancel operations on the session receiver", function(): void { - afterEach(async () => { - await afterEachTest(); }); it("Abort getState request", async function(): Promise { - await beforeEachTest(TestClientType.PartitionedQueueWithSessions, TestMessage.sessionId); + await beforeEachTest(TestMessage.sessionId); const controller = new AbortController(); setTimeout(() => controller.abort(), 1); try { @@ -375,7 +274,7 @@ describe("session tests", () => { }); it("Abort setState request on the session receiver", async function(): Promise { - await beforeEachTest(TestClientType.PartitionedQueueWithSessions, TestMessage.sessionId); + await beforeEachTest(TestMessage.sessionId); const controller = new AbortController(); setTimeout(() => controller.abort(), 1); try { @@ -387,7 +286,7 @@ describe("session tests", () => { }); it("Abort renewSessionLock request on the session receiver", async function(): Promise { - await beforeEachTest(TestClientType.PartitionedQueueWithSessions, TestMessage.sessionId); + await beforeEachTest(TestMessage.sessionId); const controller = new AbortController(); setTimeout(() => controller.abort(), 1); try { @@ -401,7 +300,7 @@ describe("session tests", () => { it("Abort receiveDeferredMessages request on the session receiver", async function(): Promise< void > { - await beforeEachTest(TestClientType.PartitionedQueueWithSessions, TestMessage.sessionId); + await beforeEachTest(TestMessage.sessionId); const controller = new AbortController(); setTimeout(() => controller.abort(), 1); try { diff --git a/sdk/servicebus/service-bus/test/streamingReceiver.spec.ts b/sdk/servicebus/service-bus/test/streamingReceiver.spec.ts index 5e15f322663d..80629fa865c5 100644 --- a/sdk/servicebus/service-bus/test/streamingReceiver.spec.ts +++ b/sdk/servicebus/service-bus/test/streamingReceiver.spec.ts @@ -5,7 +5,7 @@ import chai from "chai"; import chaiAsPromised from "chai-as-promised"; import { ReceivedMessage, delay } from "../src"; import { getAlreadyReceivingErrorMsg } from "../src/util/errors"; -import { TestClientType, TestMessage, checkWithTimeout } from "./utils/testUtils"; +import { TestMessage, checkWithTimeout } from "./utils/testUtils"; import { StreamingReceiver } from "../src/core/streamingReceiver"; import { @@ -21,7 +21,8 @@ import { ServiceBusClientForTests, createServiceBusClientForTests, drainReceiveAndDeleteReceiver, - testPeekMsgsLength + testPeekMsgsLength, + getRandomTestClientTypeWithNoSessions } from "./utils/testutils2"; import { getDeliveryProperty } from "./utils/misc"; import { MessagingError, translate } from "@azure/core-amqp"; @@ -33,6 +34,7 @@ chai.use(chaiAsPromised); let errorWasThrown: boolean; let unexpectedError: Error | undefined; const maxDeliveryCount = 10; +const testClientType = getRandomTestClientTypeWithNoSessions(); async function processError(err: Error): Promise { if (err) { @@ -40,7 +42,7 @@ async function processError(err: Error): Promise { } } -describe("Streaming", () => { +describe("Streaming Receiver Tests", () => { let serviceBusClient: ServiceBusClientForTests; let sender: Sender; let receiver: Receiver | Receiver; @@ -55,10 +57,7 @@ describe("Streaming", () => { await serviceBusClient.test.after(); }); - async function beforeEachTest( - testClientType: TestClientType, - receiveMode?: "peekLock" | "receiveAndDelete" - ): Promise { + async function beforeEachTest(receiveMode?: "peekLock" | "receiveAndDelete"): Promise { entityNames = await serviceBusClient.test.createTestEntities(testClientType); if (receiveMode === "receiveAndDelete") { @@ -76,12 +75,16 @@ describe("Streaming", () => { unexpectedError = undefined; } - describe("Streaming - Misc Tests", function(): void { + describe(testClientType + ": Streaming - Misc Tests", function(): void { afterEach(async () => { return serviceBusClient.test.afterEach(); }); - async function testAutoComplete(): Promise { + beforeEach(async () => { + await beforeEachTest(); + }); + + it("AutoComplete removes the message", async function(): Promise { const testMessage = TestMessage.getSample(); await sender.sendMessages(testMessage); @@ -118,72 +121,11 @@ describe("Streaming", () => { should.equal(unexpectedError, undefined, unexpectedError && unexpectedError.message); should.equal(receivedMsgs.length, 1, "Unexpected number of messages"); await testPeekMsgsLength(receiver, 0); - } - async function testAutoCompleteWithSenderAndReceiver(): Promise { - const testMessage = TestMessage.getSample(); - await sender.sendMessages(testMessage); - - const receivedMsgs: ReceivedMessage[] = []; - receiver.subscribe({ - async processMessage(msg: ReceivedMessage) { - receivedMsgs.push(msg); - should.equal(msg.body, testMessage.body, "MessageBody is different than expected"); - should.equal( - msg.messageId, - testMessage.messageId, - "MessageId is different than expected" - ); - - return Promise.resolve(); - }, - processError - }); - - const msgsCheck = await checkWithTimeout( - () => - receivedMsgs.length === 1 && getDeliveryProperty(receivedMsgs[0]).remote_settled === true - ); - - should.equal( - msgsCheck, - true, - receivedMsgs.length !== 1 - ? `Expected 1, received ${receivedMsgs.length} messages` - : "Message didnt get auto-completed in time" - ); - - should.equal(unexpectedError, undefined, unexpectedError && unexpectedError.message); - should.equal(receivedMsgs.length, 1, "Unexpected number of messages"); - - const peekedMsgs = await receiver.peekMessages(1); - should.equal(peekedMsgs.length, 0, "Unexpected number of msgs found when peeking"); - } - - it("Partitioned Queue: AutoComplete removes the message", async function(): Promise { - await beforeEachTest(TestClientType.PartitionedQueue); - await testAutoCompleteWithSenderAndReceiver(); - }); - - it("Partitioned Subscription: AutoComplete removes the message", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedSubscription); - await testAutoComplete(); - }); - - it("UnPartitioned Queue: AutoComplete removes the message", async function(): Promise { - await beforeEachTest(TestClientType.UnpartitionedQueue); - await testAutoComplete(); }); - it("UnPartitioned Subscription: AutoComplete removes the message", async function(): Promise< + it("Disabled autoComplete, no manual complete retains the message", async function(): Promise< void > { - await beforeEachTest(TestClientType.UnpartitionedSubscription); - await testAutoComplete(); - }); - - async function testManualComplete(): Promise { const testMessage = TestMessage.getSample(); await sender.sendMessages(testMessage); @@ -215,40 +157,11 @@ describe("Streaming", () => { should.equal(unexpectedError, undefined, unexpectedError && unexpectedError.message); await testPeekMsgsLength(receiver, 0); - } - - it("Partitioned Queue: Disabled autoComplete, no manual complete retains the message", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedQueue); - await testManualComplete(); - }); - - it("Partitioned Subscription: Disabled autoComplete, no manual complete retains the message", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedSubscription); - await testManualComplete(); - }); - - it("UnPartitioned Queue: Disabled autoComplete, no manual complete retains the message", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedQueue); - await testManualComplete(); - }); - - it("UnPartitioned Subscription: Disabled autoComplete, no manual complete retains the message", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedSubscription); - await testManualComplete(); }); it("onDetached should forward error messages if it fails to retry", async function(): Promise< void > { - await beforeEachTest(TestClientType.PartitionedQueue); let streamingReceiver: StreamingReceiver | undefined; try { let actualError: Error | undefined; @@ -288,11 +201,15 @@ describe("Streaming", () => { }); }); - describe("Streaming - Complete message", function(): void { + describe(testClientType + ": Streaming - Complete message", function(): void { afterEach(async () => { return serviceBusClient.test.afterEach(); }); + beforeEach(async () => { + await beforeEachTest(); + }); + async function testComplete(autoComplete: boolean): Promise { const testMessage = TestMessage.getSample(); await sender.sendMessages(testMessage); @@ -322,61 +239,25 @@ describe("Streaming", () => { should.equal(receivedMsgs.length, 1, "Unexpected number of messages"); await testPeekMsgsLength(receiver, 0); } - it("Partitioned Queue: complete() removes message", async function(): Promise { - await beforeEachTest(TestClientType.PartitionedQueue); - await testComplete(false); - }); - - it("Partitioned Subscription: complete() removes message", async function(): Promise { - await beforeEachTest(TestClientType.PartitionedSubscription); - await testComplete(false); - }); - - it("UnPartitioned Queue: complete() removes message", async function(): Promise { - await beforeEachTest(TestClientType.UnpartitionedQueue); - await testComplete(false); - }); - - it("UnPartitioned Subscription: complete() removes message", async function(): Promise { - await beforeEachTest(TestClientType.UnpartitionedSubscription); + it("complete() removes message", async function(): Promise { await testComplete(false); }); - it("Partitioned Queue with autoComplete: complete() removes message", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedQueue); - await testComplete(true); - }); - - it("Partitioned Subscription with autoComplete: complete() removes message", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedSubscription); - await testComplete(true); - }); - - it("UnPartitioned Queue with autoComplete: complete() removes message", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedQueue); - await testComplete(true); - }); - - it("UnPartitioned Subscription with autoComplete: complete() removes message", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedSubscription); + it("with autoComplete: complete() removes message", async function(): Promise { await testComplete(true); }); }); - describe("Streaming - Abandon message", function(): void { + describe(testClientType + ": Streaming - Abandon message", function(): void { afterEach(async () => { return serviceBusClient.test.afterEach(); }); - async function testMultipleAbandons(): Promise { + beforeEach(async () => { + await beforeEachTest(); + }); + + it("Multiple abandons until maxDeliveryCount", async function(): Promise { const testMessage = TestMessage.getSample(); await sender.sendMessages(testMessage); @@ -424,42 +305,18 @@ describe("Streaming", () => { await deadLetterMsgs[0].complete(); await testPeekMsgsLength(deadLetterReceiver, 0); - } - - it("Partitioned Queue: Multiple abandons until maxDeliveryCount", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedQueue); - await testMultipleAbandons(); - }); - - it("Partitioned Subscription: Multiple abandons until maxDeliveryCount", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedSubscription); - await testMultipleAbandons(); - }); - - it("Unpartitioned Queue: Multiple abandons until maxDeliveryCount", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedQueue); - await testMultipleAbandons(); - }); - - it("Unpartitioned Subscription: Multiple abandons until maxDeliveryCount", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedSubscription); - await testMultipleAbandons(); }); }); - describe("Streaming - Defer message", function(): void { + describe(testClientType + ": Streaming - Defer message", function(): void { afterEach(async () => { return serviceBusClient.test.afterEach(); }); + beforeEach(async () => { + await beforeEachTest(); + }); + async function testDefer(autoComplete: boolean): Promise { const testMessage = TestMessage.getSample(); await sender.sendMessages(testMessage); @@ -504,68 +361,26 @@ describe("Streaming", () => { await testPeekMsgsLength(receiver, 0); } - it("Partitioned Queue: defer() moves message to deferred queue", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedQueue); + it("defer() moves message to deferred queue", async function(): Promise { await testDefer(false); }); - it("Partitioned Subscription: defer() moves message to deferred queue", async function(): Promise< + it("with autoComplete: defer() moves message to deferred queue", async function(): Promise< void > { - await beforeEachTest(TestClientType.PartitionedSubscription); - await testDefer(false); - }); - - it("UnPartitioned Queue: defer() moves message to deferred queue", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedQueue); - await testDefer(false); - }); - - it("UnPartitioned Subscription: defer() moves message to deferred queue", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedSubscription); - await testDefer(false); - }); - - it("Partitioned Queue with autoComplete: defer() moves message to deferred queue", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedQueue); - await testDefer(true); - }); - - it("Partitioned Subscription with autoComplete: defer() moves message to deferred queue", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedSubscription); - await testDefer(true); - }); - - it("UnPartitioned Queue with autoComplete: defer() moves message to deferred queue", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedQueue); - await testDefer(true); - }); - - it("UnPartitioned Subscription with autoComplete: defer() moves message to deferred queue", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedSubscription); await testDefer(true); }); }); - describe("Streaming - Deadletter message", function(): void { + describe(testClientType + ": Streaming - Deadletter message", function(): void { afterEach(async () => { return serviceBusClient.test.afterEach(); }); + beforeEach(async () => { + await beforeEachTest(); + }); + async function testDeadletter(autoComplete: boolean): Promise { const testMessage = TestMessage.getSample(); await sender.sendMessages(testMessage); @@ -603,64 +418,18 @@ describe("Streaming", () => { await testPeekMsgsLength(deadLetterReceiver, 0); } - it("Partitioned Queue: deadLetter() moves message to deadletter queue", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedQueue); + it("deadLetter() moves message to deadletter queue", async function(): Promise { await testDeadletter(false); }); - it("Partitioned Subscription: deadLetter() moves message to deadletter queue", async function(): Promise< + it("with autoComplete: deadLetter() moves message to deadletter queue", async function(): Promise< void > { - await beforeEachTest(TestClientType.PartitionedSubscription); - await testDeadletter(false); - }); - - it("UnPartitioned Queue: deadLetter() moves message to deadletter queue", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedQueue); - await testDeadletter(false); - }); - - it("UnPartitioned Subscription: deadLetter() moves message to deadletter queue", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedSubscription); - await testDeadletter(false); - }); - - it("Partitioned Queue with autoComplete: deadLetter() moves message to deadletter queue", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedQueue); - await testDeadletter(true); - }); - - it("Partitioned Subscription with autoComplete: deadLetter() moves message to deadletter", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedSubscription); - await testDeadletter(true); - }); - - it("UnPartitioned Queue with autoComplete: deadLetter() moves message to deadletter queue", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedQueue); - await testDeadletter(true); - }); - - it("UnPartitioned Subscription with autoComplete: deadLetter() moves message to deadletter queue", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedSubscription); await testDeadletter(true); }); }); - describe("Streaming - Multiple Receiver Operations", function(): void { + describe(testClientType + ": Streaming - Multiple Receiver Operations", function(): void { afterEach(async () => { return serviceBusClient.test.afterEach(); }); @@ -706,19 +475,23 @@ describe("Streaming", () => { ); } - it("UnPartitioned Queue: Second receive operation should fail if the first streaming receiver is not stopped", async function(): Promise< + it("Second receive operation should fail if the first streaming receiver is not stopped", async function(): Promise< void > { - await beforeEachTest(TestClientType.UnpartitionedQueue); + await beforeEachTest(); await testMultipleReceiveCalls(); }); }); - describe("Streaming - Settle an already Settled message throws error", () => { + describe(testClientType + ": Streaming - Settle an already Settled message throws error", () => { afterEach(async () => { return serviceBusClient.test.afterEach(); }); + beforeEach(async () => { + await beforeEachTest(); + }); + const testError = (err: Error, operation: DispositionType): void => { should.equal( err.message, @@ -781,43 +554,19 @@ describe("Streaming", () => { should.equal(errorWasThrown, true, "Error thrown flag must be true"); } - it("UnPartitioned Queue: complete() throws error", async function(): Promise { - await beforeEachTest(TestClientType.UnpartitionedQueue); + it("complete() throws error", async function(): Promise { await testSettlement(DispositionType.complete); }); - it("UnPartitioned Subscription: complete() throws error", async function(): Promise { - await beforeEachTest(TestClientType.UnpartitionedSubscription); - await testSettlement(DispositionType.complete); - }); - - it("UnPartitioned Queue: abandon() throws error", async function(): Promise { - await beforeEachTest(TestClientType.UnpartitionedQueue); - await testSettlement(DispositionType.abandon); - }); - - it("UnPartitioned Subscription: abandon() throws error", async function(): Promise { - await beforeEachTest(TestClientType.UnpartitionedSubscription); + it("abandon() throws error", async function(): Promise { await testSettlement(DispositionType.abandon); }); - it("UnPartitioned Queue: defer() throws error", async function(): Promise { - await beforeEachTest(TestClientType.UnpartitionedQueue); - await testSettlement(DispositionType.defer); - }); - - it("UnPartitioned Subscription: defer() throws error", async function(): Promise { - await beforeEachTest(TestClientType.UnpartitionedSubscription); + it("defer() throws error", async function(): Promise { await testSettlement(DispositionType.defer); }); - it("UnPartitioned Queue: deadLetter() throws error", async function(): Promise { - await beforeEachTest(TestClientType.UnpartitionedQueue); - await testSettlement(DispositionType.deadletter); - }); - - it("UnPartitioned Subscription: deadLetter() throws error", async function(): Promise { - await beforeEachTest(TestClientType.UnpartitionedSubscription); + it("deadLetter() throws error", async function(): Promise { await testSettlement(DispositionType.deadletter); }); }); @@ -858,94 +607,98 @@ describe("Streaming", () => { should.equal(receivedMsgs.length, 1, "Unexpected number of messages"); } - it("UnPartitioned Queue: onError handler is called for user error", async function(): Promise< + it(testClientType + ": onError handler is called for user error", async function(): Promise< void > { - await beforeEachTest(TestClientType.UnpartitionedQueue); + await beforeEachTest(); await testUserError(); }); }); - describe("Streaming - Failed init should not cache receiver", function(): void { + // describe("Streaming - Failed init should not cache receiver", function(): void { + // afterEach(async () => { + // return serviceBusClient.test.afterEach(); + // }); + + // class TestTokenCredential extends EnvironmentCredential implements TokenCredential { + // private firstCall = true; + // static errorMessage = "This is a faulty token provider."; + // constructor() { + // super(); + // } + + // async getToken(audience: string): Promise { + // if (this.firstCall) { + // this.firstCall = false; + // throw new Error(TestTokenCredential.errorMessage); + // } + // return super.getToken(audience); + // } + // } + + // TODO: what is this test even actually testing? + // it("UnPartitioned Queue: Receiver is not cached when not initialized", async function(): Promise< + // void + // > { + // const env: any = getEnvVars(); + + // // Send a message using service bus client created with connection string + // let clients = await getSenderReceiverClients(TestClientType.UnpartitionedQueue, "peekLock"); + // sender = clients.sender; + // receiver = clients.receiver; + // await sender.send(TestMessage.getSample()); + // await sender.close(); + // await receiver.close(); + + // // Receive using service bus client created with faulty token provider + // const connectionObject: { + // Endpoint: string; + // SharedAccessKeyName: string; + // SharedAccessKey: string; + // } = parseConnectionString(env[EnvVarNames.SERVICEBUS_CONNECTION_STRING]); + // const tokenProvider = new TestTokenCredential(); + // receiver = new ServiceBusReceiverClient( + // { + // host: connectionObject.Endpoint.substr(5), + // tokenCredential: tokenProvider, + // queueName: EntityNames.QUEUE_NAME_NO_PARTITION + // }, + // "peekLock" + // ); + + // let actualError: Error; + // receiver.subscribe({ + // async processMessage(msg: ReceivedMessage) { + // throw new Error("No messages should have been received with faulty token provider"); + // }, + // async processError(err) { + // actualError = err; + // } + // }); + + // // Check for expected error and that receiver was not cached + // const errCheck = await checkWithTimeout(() => !!actualError === true); + // should.equal(errCheck, true, "Expected error to be thrown, but no error found."); + // should.equal( + // actualError!.message, + // TestTokenCredential.errorMessage, + // "Expected error from token provider, but unexpected error found." + // ); + // should.equal( + // !!(clients.receiver as any)._context.streamingReceiver, + // false, + // "Expected Streaming receiver to not be cached" + // ); + // }); + // }); + + describe(testClientType + ": Streaming - maxConcurrentCalls", function(): void { afterEach(async () => { return serviceBusClient.test.afterEach(); }); - // class TestTokenCredential extends EnvironmentCredential implements TokenCredential { - // private firstCall = true; - // static errorMessage = "This is a faulty token provider."; - // constructor() { - // super(); - // } - - // async getToken(audience: string): Promise { - // if (this.firstCall) { - // this.firstCall = false; - // throw new Error(TestTokenCredential.errorMessage); - // } - // return super.getToken(audience); - // } - // } - - // TODO: what is this test even actually testing? - // it("UnPartitioned Queue: Receiver is not cached when not initialized", async function(): Promise< - // void - // > { - // const env: any = getEnvVars(); - - // // Send a message using service bus client created with connection string - // let clients = await getSenderReceiverClients(TestClientType.UnpartitionedQueue, "peekLock"); - // sender = clients.sender; - // receiver = clients.receiver; - // await sender.send(TestMessage.getSample()); - // await sender.close(); - // await receiver.close(); - - // // Receive using service bus client created with faulty token provider - // const connectionObject: { - // Endpoint: string; - // SharedAccessKeyName: string; - // SharedAccessKey: string; - // } = parseConnectionString(env[EnvVarNames.SERVICEBUS_CONNECTION_STRING]); - // const tokenProvider = new TestTokenCredential(); - // receiver = new ServiceBusReceiverClient( - // { - // host: connectionObject.Endpoint.substr(5), - // tokenCredential: tokenProvider, - // queueName: EntityNames.QUEUE_NAME_NO_PARTITION - // }, - // "peekLock" - // ); - - // let actualError: Error; - // receiver.subscribe({ - // async processMessage(msg: ReceivedMessage) { - // throw new Error("No messages should have been received with faulty token provider"); - // }, - // async processError(err) { - // actualError = err; - // } - // }); - - // // Check for expected error and that receiver was not cached - // const errCheck = await checkWithTimeout(() => !!actualError === true); - // should.equal(errCheck, true, "Expected error to be thrown, but no error found."); - // should.equal( - // actualError!.message, - // TestTokenCredential.errorMessage, - // "Expected error from token provider, but unexpected error found." - // ); - // should.equal( - // !!(clients.receiver as any)._context.streamingReceiver, - // false, - // "Expected Streaming receiver to not be cached" - // ); - // }); - }); - - describe("Streaming - maxConcurrentCalls", function(): void { - afterEach(async () => { - return serviceBusClient.test.afterEach(); + beforeEach(async () => { + await beforeEachTest(); }); async function testConcurrency(maxConcurrentCalls?: number): Promise { @@ -991,67 +744,15 @@ describe("Streaming", () => { should.equal(settledMsgs.length, 2, `Expected 2, received ${settledMsgs.length} messages.`); } - it("Partitioned Queue: no maxConcurrentCalls passed", async function(): Promise { - await beforeEachTest(TestClientType.PartitionedQueue); + it("no maxConcurrentCalls passed", async function(): Promise { await testConcurrency(); }); - it("Partitioned Queue: pass 1 for maxConcurrentCalls", async function(): Promise { - await beforeEachTest(TestClientType.PartitionedQueue); + it("pass 1 for maxConcurrentCalls", async function(): Promise { await testConcurrency(1); }); - it("Partitioned Queue: pass 2 for maxConcurrentCalls", async function(): Promise { - await beforeEachTest(TestClientType.PartitionedQueue); - await testConcurrency(2); - }); - - it("Unpartitioned Queue: no maxConcurrentCalls passed", async function(): Promise { - await beforeEachTest(TestClientType.UnpartitionedQueue); - await testConcurrency(); - }); - - it("Unpartitioned Queue: pass 1 for maxConcurrentCalls", async function(): Promise { - await beforeEachTest(TestClientType.UnpartitionedQueue); - await testConcurrency(1); - }); - - it("Unpartitioned Queue: pass 2 for maxConcurrentCalls", async function(): Promise { - await beforeEachTest(TestClientType.UnpartitionedQueue); - await testConcurrency(2); - }); - - it("Partitioned Subscription: no maxConcurrentCalls passed", async function(): Promise { - await beforeEachTest(TestClientType.PartitionedSubscription); - await testConcurrency(); - }); - - it("Partitioned Queue: pass 1 for maxConcurrentCalls", async function(): Promise { - await beforeEachTest(TestClientType.PartitionedSubscription); - await testConcurrency(1); - }); - - it("Partitioned Queue: pass 2 for maxConcurrentCalls", async function(): Promise { - await beforeEachTest(TestClientType.PartitionedSubscription); - await testConcurrency(2); - }); - - it("Unpartitioned Subscription: no maxConcurrentCalls passed", async function(): Promise { - await beforeEachTest(TestClientType.UnpartitionedSubscription); - await testConcurrency(); - }); - - it("Unpartitioned Subscription: pass 1 for maxConcurrentCalls", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedSubscription); - await testConcurrency(1); - }); - - it("Unpartitioned Subscription: pass 2 for maxConcurrentCalls", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedSubscription); + it("pass 2 for maxConcurrentCalls", async function(): Promise { await testConcurrency(2); }); }); @@ -1098,67 +799,75 @@ describe("Streaming", () => { `Expected 0 messages, but received ${receivedMsgs.length}` ); receiver = await serviceBusClient.test.getReceiveAndDeleteReceiver(entityNames); - await testPeekMsgsLength(receiver, totalNumOfMessages); + await verifyMessageCount( + totalNumOfMessages, + entityNames.queue, + entityNames.topic, + entityNames.subscription + ); await drainReceiveAndDeleteReceiver(receiver); - await verifyMessageCount(0, entityNames.queue); + await verifyMessageCount(0, entityNames.queue, entityNames.topic, entityNames.subscription); } - it("UnPartitioned Queue: Not receive messages after receiver is closed", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedQueue); - await testReceiveMessages(); - }); + it( + testClientType + ": Not receive messages after receiver is closed", + async function(): Promise { + await beforeEachTest(); + await testReceiveMessages(); + } + ); - it("UnPartitioned Queue: (Receive And Delete mode) Not receive messages after receiver is closed", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedQueue, "receiveAndDelete"); - await testReceiveMessages(); - }); + it( + testClientType + ": (Receive And Delete mode) Not receive messages after receiver is closed", + async function(): Promise { + await beforeEachTest("receiveAndDelete"); + await testReceiveMessages(); + } + ); }); - it("Streaming - user can stop a message subscription without closing the receiver", async () => { - const entities = await serviceBusClient.test.createTestEntities( - TestClientType.UnpartitionedQueue - ); + it( + testClientType + ": Streaming - stop a message subscription without closing the receiver", + async () => { + const entities = await serviceBusClient.test.createTestEntities(testClientType); - const actualReceiver = await serviceBusClient.test.getPeekLockReceiver(entities); - const receiver2 = await serviceBusClient.test.getReceiveAndDeleteReceiver(entities); - const sender = await serviceBusClient.test.createSender(entities); + const actualReceiver = await serviceBusClient.test.getPeekLockReceiver(entities); + const receiver2 = await serviceBusClient.test.getReceiveAndDeleteReceiver(entities); + const sender = await serviceBusClient.test.createSender(entities); - await sender.sendMessages({ body: ".close() test - first message" }); + await sender.sendMessages({ body: ".close() test - first message" }); - const { subscriber, messages } = await singleMessagePromise(actualReceiver); + const { subscriber, messages } = await singleMessagePromise(actualReceiver); - messages.map((m) => m.body).should.deep.equal([".close() test - first message"]); + messages.map((m) => m.body).should.deep.equal([".close() test - first message"]); - // now we're going to shut down the closeable (ie, subscription). This leaves - // the receiver open but it does drain it (so any remaining messages are delivered - // and will still be settleable). - await subscriber.close(); + // now we're going to shut down the closeable (ie, subscription). This leaves + // the receiver open but it does drain it (so any remaining messages are delivered + // and will still be settleable). + await subscriber.close(); - await messages[0].complete(); - messages.pop(); + await messages[0].complete(); + messages.pop(); - await sender.sendMessages({ - body: ".close test - second message, after closing" - }); + await sender.sendMessages({ + body: ".close test - second message, after closing" + }); - // the subscription is closed so no messages should be received here. - await delay(2000); + // the subscription is closed so no messages should be received here. + await delay(2000); - messages.map((m) => m.body).should.deep.equal([]); + messages.map((m) => m.body).should.deep.equal([]); - // clean out the remaining message that never arrived. - const [finalMessage] = await receiver2.receiveMessages(1, { maxWaitTimeInMs: 5000 }); - finalMessage.body.should.equal(".close test - second message, after closing"); + // clean out the remaining message that never arrived. + const [finalMessage] = await receiver2.receiveMessages(1, { maxWaitTimeInMs: 5000 }); + finalMessage.body.should.equal(".close test - second message, after closing"); - await serviceBusClient.test.afterEach(); - }); + await serviceBusClient.test.afterEach(); + } + ); }); -describe("Streaming - onDetached", function(): void { +describe(testClientType + ": Streaming - onDetached", function(): void { let serviceBusClient: ServiceBusClientForTests; let sender: Sender; let receiver: Receiver | Receiver; @@ -1171,10 +880,7 @@ describe("Streaming - onDetached", function(): void { await serviceBusClient.test.after(); }); - async function beforeEachTest( - testClientType: TestClientType, - receiveMode?: "peekLock" | "receiveAndDelete" - ): Promise { + async function beforeEachTest(receiveMode?: "peekLock" | "receiveAndDelete"): Promise { const entityNames = await serviceBusClient.test.createTestEntities(testClientType); if (receiveMode === "receiveAndDelete") { @@ -1201,7 +907,7 @@ describe("Streaming - onDetached", function(): void { * error handler. */ // Create the sender and receiver. - await beforeEachTest(TestClientType.UnpartitionedQueue, "receiveAndDelete"); + await beforeEachTest("receiveAndDelete"); // Send a message so we can be sure when the receiver is open and active. await sender.sendMessages(TestMessage.getSample()); const receivedErrors: any[] = []; @@ -1236,7 +942,7 @@ describe("Streaming - onDetached", function(): void { void > { // Create the sender and receiver. - await beforeEachTest(TestClientType.UnpartitionedQueue, "receiveAndDelete"); + await beforeEachTest("receiveAndDelete"); // Send a message so we can be sure when the receiver is open and active. await sender.sendMessages(TestMessage.getSample()); const receivedErrors: any[] = []; @@ -1271,7 +977,7 @@ describe("Streaming - onDetached", function(): void { void > { // Create the sender and receiver. - await beforeEachTest(TestClientType.UnpartitionedQueue, "receiveAndDelete"); + await beforeEachTest("receiveAndDelete"); // Send a message so we can be sure when the receiver is open and active. await sender.sendMessages(TestMessage.getSample()); const receivedErrors: any[] = []; @@ -1309,7 +1015,7 @@ describe("Streaming - onDetached", function(): void { void > { // Create the sender and receiver. - await beforeEachTest(TestClientType.UnpartitionedQueue, "receiveAndDelete"); + await beforeEachTest("receiveAndDelete"); // Send a message so we can be sure when the receiver is open and active. await sender.sendMessages(TestMessage.getSample()); const receivedErrors: any[] = []; @@ -1346,7 +1052,7 @@ describe("Streaming - onDetached", function(): void { }); }); -describe("Streaming - disconnects", function(): void { +describe(testClientType + ": Streaming - disconnects", function(): void { let serviceBusClient: ServiceBusClientForTests; let sender: Sender; let receiver: Receiver | Receiver; @@ -1359,7 +1065,7 @@ describe("Streaming - disconnects", function(): void { await serviceBusClient.test.after(); }); - async function beforeEachTest(testClientType: TestClientType): Promise { + async function beforeEachTest(): Promise { const entityNames = await serviceBusClient.test.createTestEntities(testClientType); receiver = await serviceBusClient.test.getPeekLockReceiver(entityNames); sender = serviceBusClient.test.addToCleanup( @@ -1378,7 +1084,7 @@ describe("Streaming - disconnects", function(): void { * error handler. */ // Create the sender and receiver. - await beforeEachTest(TestClientType.UnpartitionedQueue); + await beforeEachTest(); // Send a message so we can be sure when the receiver is open and active. await sender.sendMessages(TestMessage.getSample()); const receivedErrors: any[] = []; diff --git a/sdk/servicebus/service-bus/test/streamingReceiverSessions.spec.ts b/sdk/servicebus/service-bus/test/streamingReceiverSessions.spec.ts index 04f4bf784ead..c6a133f09b60 100644 --- a/sdk/servicebus/service-bus/test/streamingReceiverSessions.spec.ts +++ b/sdk/servicebus/service-bus/test/streamingReceiverSessions.spec.ts @@ -14,7 +14,8 @@ import { EntityName, ServiceBusClientForTests, createServiceBusClientForTests, - testPeekMsgsLength + testPeekMsgsLength, + getRandomTestClientTypeWithSessions } from "./utils/testutils2"; import { getDeliveryProperty } from "./utils/misc"; import { singleMessagePromise } from "./streamingReceiver.spec"; @@ -28,6 +29,7 @@ describe("Streaming with sessions", () => { let errorWasThrown: boolean; let unexpectedError: Error | undefined; let serviceBusClient: ServiceBusClientForTests; + let testClientType = getRandomTestClientTypeWithSessions(); before(() => { serviceBusClient = createServiceBusClientForTests(); @@ -47,7 +49,6 @@ describe("Streaming with sessions", () => { await serviceBusClient.test.afterEach(); } async function beforeEachTest( - testClientType: TestClientType, receiveMode?: "peekLock" | "receiveAndDelete" ): Promise { const entityNames = await createReceiverForTests(testClientType, receiveMode); @@ -100,59 +101,64 @@ describe("Streaming with sessions", () => { return entityNames; } - it("Streaming - user can stop a message subscription without closing the receiver", async () => { - const entities = await serviceBusClient.test.createTestEntities( - TestClientType.UnpartitionedQueueWithSessions - ); + it( + testClientType + ": Streaming - stop a message subscription without closing the receiver", + async () => { + const entities = await serviceBusClient.test.createTestEntities(testClientType); - const sender = await serviceBusClient.test.createSender(entities); - await sender.sendMessages({ - body: ".close() test - first message", - sessionId: TestMessage.sessionId - }); + const sender = await serviceBusClient.test.createSender(entities); + await sender.sendMessages({ + body: ".close() test - first message", + sessionId: TestMessage.sessionId + }); - const actualReceiver = await serviceBusClient.test.getSessionPeekLockReceiver(entities, { - sessionId: TestMessage.sessionId - }); - const { subscriber, messages } = await singleMessagePromise(actualReceiver); + const actualReceiver = await serviceBusClient.test.getSessionPeekLockReceiver(entities, { + sessionId: TestMessage.sessionId + }); + const { subscriber, messages } = await singleMessagePromise(actualReceiver); - messages.map((m) => m.body).should.deep.equal([".close() test - first message"]); + messages.map((m) => m.body).should.deep.equal([".close() test - first message"]); - // now we're going to shut down the closeable (ie, subscription). This leaves - // the receiver open but it does drain it (so any remaining messages are delivered - // and will still be settleable). - await subscriber.close(); + // now we're going to shut down the closeable (ie, subscription). This leaves + // the receiver open but it does drain it (so any remaining messages are delivered + // and will still be settleable). + await subscriber.close(); - await messages[0].complete(); - messages.pop(); + await messages[0].complete(); + messages.pop(); - await sender.sendMessages({ - body: ".close test - second message, after closing", - sessionId: TestMessage.sessionId - }); + await sender.sendMessages({ + body: ".close test - second message, after closing", + sessionId: TestMessage.sessionId + }); - // the subscription is closed so no messages should be received here. - await delay(2000); + // the subscription is closed so no messages should be received here. + await delay(2000); - messages.map((m) => m.body).should.deep.equal([]); + messages.map((m) => m.body).should.deep.equal([]); - await actualReceiver.close(); // release the session lock + await actualReceiver.close(); // release the session lock - const receiver2 = await serviceBusClient.test.getReceiveAndDeleteReceiver(entities); + const receiver2 = await serviceBusClient.test.getReceiveAndDeleteReceiver(entities); - // clean out the remaining message that never arrived. - const [finalMessage] = await receiver2.receiveMessages(1, { maxWaitTimeInMs: 5000 }); - finalMessage.body.should.equal(".close test - second message, after closing"); + // clean out the remaining message that never arrived. + const [finalMessage] = await receiver2.receiveMessages(1, { maxWaitTimeInMs: 5000 }); + finalMessage.body.should.equal(".close test - second message, after closing"); - await serviceBusClient.test.afterEach(); - }); + await serviceBusClient.test.afterEach(); + } + ); - describe("Sessions Streaming - Misc Tests", function(): void { + describe(testClientType + ": Sessions Streaming - Misc Tests", function(): void { afterEach(async () => { await afterEachTest(); }); - async function testAutoComplete(): Promise { + beforeEach(async () => { + await beforeEachTest(); + }); + + it("AutoComplete removes the message(with sessions)", async function(): Promise { const testMessage = TestMessage.getSessionSample(); await sender.sendMessages(testMessage); @@ -186,37 +192,11 @@ describe("Streaming with sessions", () => { should.equal(unexpectedError, undefined, unexpectedError && unexpectedError.message); should.equal(receivedMsgs.length, 1, "Unexpected number of messages"); await testPeekMsgsLength(receiver, 0); - } - - it("Partitioned Queue: AutoComplete removes the message(with sessions)", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedQueueWithSessions); - await testAutoComplete(); - }); - - it("Partitioned Subscription: AutoComplete removes the message(with sessions)", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedSubscriptionWithSessions); - await testAutoComplete(); }); - it("UnPartitioned Queue: AutoComplete removes the message(with sessions)", async function(): Promise< + it("Disabled autoComplete, no manual complete retains the message(with sessions)", async function(): Promise< void > { - await beforeEachTest(TestClientType.UnpartitionedQueueWithSessions); - await testAutoComplete(); - }); - - it("UnPartitioned Subscription: AutoComplete removes the message(with sessions)", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedSubscriptionWithSessions); - await testAutoComplete(); - }); - - async function testManualComplete(): Promise { const testMessage = TestMessage.getSessionSample(); await sender.sendMessages(testMessage); const receivedMsgs: ReceivedMessageWithLock[] = []; @@ -247,42 +227,18 @@ describe("Streaming with sessions", () => { should.equal(unexpectedError, undefined, unexpectedError && unexpectedError.message); should.equal(receivedMsgs.length, 1, "Unexpected number of messages"); await testPeekMsgsLength(receiver, 0); - } - - it("Partitioned Queue: Disabled autoComplete, no manual complete retains the message(with sessions)", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedQueueWithSessions); - await testManualComplete(); - }); - - it("Partitioned Subscription: Disabled autoComplete, no manual complete retains the message(with sessions)", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedSubscriptionWithSessions); - await testManualComplete(); - }); - - it("UnPartitioned Queue: Disabled autoComplete, no manual complete retains the message(with sessions)", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedQueueWithSessions); - await testManualComplete(); - }); - - it("UnPartitioned Subscription: Disabled autoComplete, no manual complete retains the message(with sessions)", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedSubscriptionWithSessions); - await testManualComplete(); }); }); - describe("Sessions Streaming - Complete message", function(): void { + describe(testClientType + ": Sessions Streaming - Complete message", function(): void { afterEach(async () => { await afterEachTest(); }); + beforeEach(async () => { + await beforeEachTest(); + }); + async function testComplete(autoComplete: boolean): Promise { const testMessage = TestMessage.getSessionSample(); await sender.sendMessages(testMessage); @@ -313,69 +269,23 @@ describe("Streaming with sessions", () => { await testPeekMsgsLength(receiver, 0); } - it("Partitioned Queue: complete() removes message(with sessions)", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedQueueWithSessions); - await testComplete(false); - }); - - it("Partitioned Subscription: complete() removes message(with sessions)", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedSubscriptionWithSessions); - await testComplete(false); - }); - - it("UnPartitioned Queue: complete() removes message(with sessions)", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedQueueWithSessions); - await testComplete(false); - }); - - it("UnPartitioned Subscription: complete() removes message(with sessions)", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedSubscriptionWithSessions); + it("complete() removes message(with sessions)", async function(): Promise { await testComplete(false); }); - it("Partitioned Queue with autoComplete: complete() removes message(with sessions)", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedQueueWithSessions); - await testComplete(true); - }); - - it("Partitioned Subscription with autoComplete: complete() removes message(with sessions)", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedSubscriptionWithSessions); - await testComplete(true); - }); - - it("UnPartitioned Queue with autoComplete: complete() removes message(with sessions)", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedQueueWithSessions); - await testComplete(true); - }); - - it("UnPartitioned Subscription with autoComplete: complete() removes message(with sessions)", async function(): Promise< + it("with autoComplete: complete() removes message(with sessions)", async function(): Promise< void > { - await beforeEachTest(TestClientType.UnpartitionedSubscriptionWithSessions); await testComplete(true); }); }); - describe("Sessions Streaming - Abandon message", function(): void { + describe(testClientType + ": Sessions Streaming - Abandon message", function(): void { afterEach(async () => { await afterEachTest(); }); - async function eachTest(testClientType: TestClientType, autoComplete: boolean) { - await beforeEachTest(testClientType); + async function eachTest(autoComplete: boolean) { + await beforeEachTest(); await testAbandon(testClientType, autoComplete); } async function testAbandon( @@ -426,60 +336,28 @@ describe("Streaming with sessions", () => { await (receivedMsgs[0] as ReceivedMessageWithLock).complete(); await testPeekMsgsLength(receiver, 0); } - it("Partitioned Queue: abandon() retains message with incremented deliveryCount(with sessions)", async function(): Promise< - void - > { - await eachTest(TestClientType.PartitionedQueueWithSessions, false); - }); - - it("Partitioned Subscription: abandon() retains message with incremented deliveryCount(with sessions)", async function(): Promise< + it("abandon() retains message with incremented deliveryCount(with sessions)", async function(): Promise< void > { - await eachTest(TestClientType.PartitionedSubscriptionWithSessions, false); + await eachTest(false); }); - it("UnPartitioned Queue: abandon() retains message with incremented deliveryCount(with sessions)", async function(): Promise< + it("with autoComplete: abandon() retains message with incremented deliveryCount(with sessions)", async function(): Promise< void > { - await eachTest(TestClientType.UnpartitionedQueueWithSessions, false); - }); - - it("UnPartitioned Subscription: abandon() retains message with incremented deliveryCount(with sessions)", async function(): Promise< - void - > { - await eachTest(TestClientType.UnpartitionedSubscriptionWithSessions, false); - }); - - it("Partitioned Queue with autoComplete: abandon() retains message with incremented deliveryCount(with sessions)", async function(): Promise< - void - > { - await eachTest(TestClientType.PartitionedQueueWithSessions, true); - }); - - it("Partitioned Subscription with autoComplete: abandon() retains message with incremented deliveryCount(with sessions)", async function(): Promise< - void - > { - await eachTest(TestClientType.PartitionedSubscriptionWithSessions, true); - }); - - it("UnPartitioned Queue with autoComplete: abandon() retains message with incremented deliveryCount(with sessions)", async function(): Promise< - void - > { - await eachTest(TestClientType.UnpartitionedQueueWithSessions, true); - }); - - it("UnPartitioned Subscription with autoComplete: abandon() retains message with incremented deliveryCount(with sessions)", async function(): Promise< - void - > { - await eachTest(TestClientType.UnpartitionedSubscriptionWithSessions, true); + await eachTest(true); }); }); - describe("Sessions Streaming - Defer message", function(): void { + describe(testClientType + ": Sessions Streaming - Defer message", function(): void { afterEach(async () => { await afterEachTest(); }); + beforeEach(async () => { + await beforeEachTest(); + }); + async function testDefer(autoComplete: boolean): Promise { const testMessage = TestMessage.getSessionSample(); await sender.sendMessages(testMessage); @@ -521,68 +399,26 @@ describe("Streaming with sessions", () => { await (deferredMsg as ReceivedMessageWithLock).complete(); await testPeekMsgsLength(receiver, 0); } - it("Partitioned Queue: defer() moves message to deferred queue(with sessions)", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedQueueWithSessions); - await testDefer(false); - }); - - it("Partitioned Subscription: defer() moves message to deferred queue(with sessions)", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedSubscriptionWithSessions); - await testDefer(false); - }); - - it("UnPartitioned Queue: defer() moves message to deferred queue(with sessions)", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedQueueWithSessions); - await testDefer(false); - }); - - it("UnPartitioned Subscription: defer() moves message to deferred queue(with sessions)", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedSubscriptionWithSessions); + it("defer() moves message to deferred queue(with sessions)", async function(): Promise { await testDefer(false); }); - it("Partitioned Queue with autoComplete: defer() moves message to deferred queue(with sessions)", async function(): Promise< + it("with autoComplete: defer() moves message to deferred queue(with sessions)", async function(): Promise< void > { - await beforeEachTest(TestClientType.PartitionedQueueWithSessions); - await testDefer(true); - }); - - it("Partitioned Subscription with autoComplete: defer() moves message to deferred queue(with sessions)", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedSubscriptionWithSessions); - await testDefer(true); - }); - - it("UnPartitioned Queue with autoComplete: defer() moves message to deferred queue(with sessions)", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedQueueWithSessions); - await testDefer(true); - }); - - it("UnPartitioned Subscription with autoComplete: defer() moves message to deferred queue(with sessions)", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedSubscriptionWithSessions); await testDefer(true); }); }); - describe("Sessions Streaming - Deadletter message", function(): void { + describe(testClientType + ": Sessions Streaming - Deadletter message", function(): void { afterEach(async () => { await afterEachTest(); }); + beforeEach(async () => { + await beforeEachTest(); + }); + async function testDeadletter(autoComplete: boolean): Promise { const testMessage = TestMessage.getSessionSample(); await sender.sendMessages(testMessage); @@ -619,59 +455,15 @@ describe("Streaming with sessions", () => { await testPeekMsgsLength(deadLetterReceiver, 0); } - it("Partitioned Queue: deadLetter() moves message to deadletter queue(with sessions)", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedQueueWithSessions); - await testDeadletter(false); - }); - - it("Partitioned Subscription: deadLetter() moves message to deadletter queue(with sessions)", async function(): Promise< + it("deadLetter() moves message to deadletter queue(with sessions)", async function(): Promise< void > { - await beforeEachTest(TestClientType.PartitionedSubscriptionWithSessions); await testDeadletter(false); }); - it("UnPartitioned Queue: deadLetter() moves message to deadletter queue(with sessions)", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedQueueWithSessions); - await testDeadletter(false); - }); - - it("UnPartitioned Subscription: deadLetter() moves message to deadletter queue(with sessions)", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedSubscriptionWithSessions); - await testDeadletter(false); - }); - - it("Partitioned Queue with autoComplete: deadLetter() moves message to deadletter queue(with sessions)", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedQueueWithSessions); - await testDeadletter(true); - }); - - it("Partitioned Subscription with autoComplete: deadLetter() moves message to deadletter(with sessions)", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedSubscriptionWithSessions); - await testDeadletter(true); - }); - - it("UnPartitioned Queue with autoComplete: deadLetter() moves message to deadletter queue(with sessions)", async function(): Promise< + it("with autoComplete: deadLetter() moves message to deadletter queue(with sessions)", async function(): Promise< void > { - await beforeEachTest(TestClientType.UnpartitionedQueueWithSessions); - await testDeadletter(true); - }); - - it("UnPartitioned Subscription with autoComplete: deadLetter() moves message to deadletter queue(with sessions)", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedSubscriptionWithSessions); await testDeadletter(true); }); }); @@ -724,135 +516,107 @@ describe("Streaming with sessions", () => { ); } - it("UnPartitioned Queue: Second receive operation should fail if the first streaming receiver is not stopped(with sessions)", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedQueueWithSessions); - await testMultipleReceiveCalls(); - }); + it( + testClientType + + ": Second receive operation should fail if the first streaming receiver is not stopped(with sessions)", + async function(): Promise { + await beforeEachTest(); + await testMultipleReceiveCalls(); + } + ); }); - describe("Sessions Streaming - Settle an already Settled message throws error", () => { - afterEach(async () => { - await afterEachTest(); - }); - - const testError = (err: Error, operation: DispositionType): void => { - should.equal( - err.message, - `Failed to ${operation} the message as this message is already settled.`, - "ErrorMessage is different than expected" - ); - errorWasThrown = true; - }; - - async function testSettlement(operation: DispositionType): Promise { - const testMessage = TestMessage.getSessionSample(); - await sender.sendMessages(testMessage); - - const receivedMsgs: ReceivedMessageWithLock[] = []; - receiver.subscribe({ - async processMessage(msg: ReceivedMessageWithLock) { - receivedMsgs.push(msg); - return Promise.resolve(); - }, - processError + describe( + testClientType + ": Sessions Streaming - Settle an already Settled message throws error", + () => { + afterEach(async () => { + await afterEachTest(); }); - const msgsCheck = await checkWithTimeout( - () => - receivedMsgs.length === 1 && getDeliveryProperty(receivedMsgs[0]).remote_settled === true - ); - should.equal( - msgsCheck, - true, - receivedMsgs.length !== 1 - ? `Expected 1, received ${receivedMsgs.length} messages` - : "Message didnt get auto-completed in time" - ); - should.equal(unexpectedError, undefined, unexpectedError && unexpectedError.message); + beforeEach(async () => { + await beforeEachTest(); + }); - should.equal(receivedMsgs.length, 1, "Unexpected number of messages"); - should.equal( - receivedMsgs[0].body, - testMessage.body, - "MessageBody is different than expected" - ); - should.equal( - receivedMsgs[0].messageId, - testMessage.messageId, - "MessageId is different than expected" - ); + const testError = (err: Error, operation: DispositionType): void => { + should.equal( + err.message, + `Failed to ${operation} the message as this message is already settled.`, + "ErrorMessage is different than expected" + ); + errorWasThrown = true; + }; - await testPeekMsgsLength(receiver, 0); + async function testSettlement(operation: DispositionType): Promise { + const testMessage = TestMessage.getSessionSample(); + await sender.sendMessages(testMessage); - if (operation === DispositionType.complete) { - await receivedMsgs[0].complete().catch((err) => testError(err, operation)); - } else if (operation === DispositionType.abandon) { - await receivedMsgs[0].abandon().catch((err) => testError(err, operation)); - } else if (operation === DispositionType.deadletter) { - await receivedMsgs[0].deadLetter().catch((err) => testError(err, operation)); - } else if (operation === DispositionType.defer) { - await receivedMsgs[0].defer().catch((err) => testError(err, operation)); - } + const receivedMsgs: ReceivedMessageWithLock[] = []; + receiver.subscribe({ + async processMessage(msg: ReceivedMessageWithLock) { + receivedMsgs.push(msg); + return Promise.resolve(); + }, + processError + }); - should.equal(errorWasThrown, true, "Error thrown flag must be true"); - } + const msgsCheck = await checkWithTimeout( + () => + receivedMsgs.length === 1 && + getDeliveryProperty(receivedMsgs[0]).remote_settled === true + ); + should.equal( + msgsCheck, + true, + receivedMsgs.length !== 1 + ? `Expected 1, received ${receivedMsgs.length} messages` + : "Message didnt get auto-completed in time" + ); + should.equal(unexpectedError, undefined, unexpectedError && unexpectedError.message); - it("UnPartitioned Queue: complete() throws error(with sessions)", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedQueueWithSessions); - await testSettlement(DispositionType.complete); - }); + should.equal(receivedMsgs.length, 1, "Unexpected number of messages"); + should.equal( + receivedMsgs[0].body, + testMessage.body, + "MessageBody is different than expected" + ); + should.equal( + receivedMsgs[0].messageId, + testMessage.messageId, + "MessageId is different than expected" + ); - it("UnPartitioned Subscription: complete() throws error(with sessions)", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedSubscriptionWithSessions); - await testSettlement(DispositionType.complete); - }); + await testPeekMsgsLength(receiver, 0); - it("UnPartitioned Queue: abandon() throws error(with sessions)", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedQueueWithSessions); - await testSettlement(DispositionType.abandon); - }); + if (operation === DispositionType.complete) { + await receivedMsgs[0].complete().catch((err) => testError(err, operation)); + } else if (operation === DispositionType.abandon) { + await receivedMsgs[0].abandon().catch((err) => testError(err, operation)); + } else if (operation === DispositionType.deadletter) { + await receivedMsgs[0].deadLetter().catch((err) => testError(err, operation)); + } else if (operation === DispositionType.defer) { + await receivedMsgs[0].defer().catch((err) => testError(err, operation)); + } - it("UnPartitioned Subscription: abandon() throws error(with sessions)", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedSubscriptionWithSessions); - await testSettlement(DispositionType.abandon); - }); + should.equal(errorWasThrown, true, "Error thrown flag must be true"); + } - it("UnPartitioned Queue: defer() throws error(with sessions)", async function(): Promise { - await beforeEachTest(TestClientType.UnpartitionedQueueWithSessions); - await testSettlement(DispositionType.defer); - }); + it("complete() throws error(with sessions)", async function(): Promise { + await testSettlement(DispositionType.complete); + }); - it("UnPartitioned Subscription: defer() throws error(with sessions)", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedSubscriptionWithSessions); - await testSettlement(DispositionType.defer); - }); + it("abandon() throws error(with sessions)", async function(): Promise { + await testSettlement(DispositionType.abandon); + }); - it("UnPartitioned Queue: deadLetter() throws error(with sessions)", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedQueueWithSessions); - await testSettlement(DispositionType.deadletter); - }); + it("defer() throws error(with sessions)", async function(): Promise { + await testSettlement(DispositionType.defer); + }); - it("UnPartitioned Subscription: deadLetter() throws error(with sessions)", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedSubscriptionWithSessions); - await testSettlement(DispositionType.deadletter); - }); - }); + it("deadLetter() throws error(with sessions)", async function(): Promise { + await testSettlement(DispositionType.deadletter); + }); + } + ); describe("Sessions Streaming - User Error", function(): void { afterEach(async () => { @@ -887,19 +651,24 @@ describe("Streaming with sessions", () => { should.equal(receivedMsgs.length, 1, "Unexpected number of messages"); } - it("UnPartitioned Queue: onError handler is called for user error(with sessions)", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedQueueWithSessions); - await testUserError(); - }); + it( + testClientType + ": onError handler is called for user error(with sessions)", + async function(): Promise { + await beforeEachTest(); + await testUserError(); + } + ); }); - describe("Sessions Streaming - maxConcurrentCalls", function(): void { + describe(testClientType + ": Sessions Streaming - maxConcurrentCalls", function(): void { afterEach(async () => { await afterEachTest(); }); + beforeEach(async () => { + await beforeEachTest(); + }); + async function testConcurrency(maxConcurrentCalls?: number): Promise { if ( typeof maxConcurrentCalls === "number" && @@ -958,87 +727,15 @@ describe("Streaming with sessions", () => { should.equal(settledMsgs.length, 2, `Expected 2, received ${settledMsgs.length} messages.`); } - it("Partitioned Queue: no maxConcurrentCalls passed(with sessions)", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedQueueWithSessions); - await testConcurrency(); - }); - - it("Partitioned Queue: pass 1 for maxConcurrentCalls(with sessions)", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedQueueWithSessions); - await testConcurrency(); - }); - - it("Partitioned Queue: pass 2 for maxConcurrentCalls(with sessions)", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedQueueWithSessions); - await testConcurrency(); - }); - - it("Unpartitioned Queue: no maxConcurrentCalls passed(with sessions)", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedQueueWithSessions); - await testConcurrency(); - }); - - it("Unpartitioned Queue: pass 1 for maxConcurrentCalls(with sessions)", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedQueueWithSessions); + it("no maxConcurrentCalls passed(with sessions)", async function(): Promise { await testConcurrency(); }); - it("Unpartitioned Queue: pass 2 for maxConcurrentCalls(with sessions)", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedQueueWithSessions); - await testConcurrency(); - }); - - it("Partitioned Subscription: no maxConcurrentCalls passed(with sessions)", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedSubscriptionWithSessions); - await testConcurrency(); - }); - - it("Partitioned Queue: pass 1 for maxConcurrentCalls(with sessions)", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedSubscriptionWithSessions); - await testConcurrency(1); - }); - - it("Partitioned Queue: pass 2 for maxConcurrentCalls(with sessions)", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.PartitionedSubscriptionWithSessions); - await testConcurrency(2); - }); - - it("Unpartitioned Subscription: no maxConcurrentCalls passed(with sessions)", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedSubscriptionWithSessions); - await testConcurrency(); - }); - - it("Unpartitioned Subscription: pass 1 for maxConcurrentCalls(with sessions)", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedSubscriptionWithSessions); + it("pass 1 for maxConcurrentCalls(with sessions)", async function(): Promise { await testConcurrency(1); }); - it("Unpartitioned Subscription: pass 2 for maxConcurrentCalls(with sessions)", async function(): Promise< - void - > { - await beforeEachTest(TestClientType.UnpartitionedSubscriptionWithSessions); + it("pass 2 for maxConcurrentCalls(with sessions)", async function(): Promise { await testConcurrency(2); }); }); @@ -1093,21 +790,20 @@ describe("Streaming with sessions", () => { await testPeekMsgsLength(receiver, totalNumOfMessages); } - it("UnPartitioned Queue: Not receive messages after receiver is closed", async function(): Promise< - void - > { - const entityNames = await beforeEachTest(TestClientType.UnpartitionedQueueWithSessions); - await testReceiveMessages(entityNames); - }); + it( + testClientType + ": Not receive messages after receiver is closed", + async function(): Promise { + const entityNames = await beforeEachTest(); + await testReceiveMessages(entityNames); + } + ); - it("UnPartitioned Queue: (Receive And Delete mode) Not receive messages after receiver is closed", async function(): Promise< - void - > { - const entityNames = await beforeEachTest( - TestClientType.UnpartitionedQueueWithSessions, - "receiveAndDelete" - ); - await testReceiveMessages(entityNames); - }); + it( + testClientType + ": (Receive And Delete mode) Not receive messages after receiver is closed", + async function(): Promise { + const entityNames = await beforeEachTest("receiveAndDelete"); + await testReceiveMessages(entityNames); + } + ); }); }); diff --git a/sdk/servicebus/service-bus/test/utils/testUtils.ts b/sdk/servicebus/service-bus/test/utils/testUtils.ts index 2f7bd6a782f0..be077f161007 100644 --- a/sdk/servicebus/service-bus/test/utils/testUtils.ts +++ b/sdk/servicebus/service-bus/test/utils/testUtils.ts @@ -125,21 +125,18 @@ export class TestMessage { } export enum TestClientType { - PartitionedQueue, - PartitionedTopic, - PartitionedSubscription, - UnpartitionedQueue, - UnpartitionedTopic, - UnpartitionedSubscription, - PartitionedQueueWithSessions, - PartitionedTopicWithSessions, - PartitionedSubscriptionWithSessions, - UnpartitionedQueueWithSessions, - UnpartitionedTopicWithSessions, - UnpartitionedSubscriptionWithSessions, - TopicFilterTestTopic, - TopicFilterTestDefaultSubscription, - TopicFilterTestSubscription + PartitionedQueue = "PartitionedQueue", + PartitionedTopic = "PartitionedTopic", + PartitionedSubscription = "PartitionedSubscription", + UnpartitionedQueue = "UnpartitionedQueue", + UnpartitionedTopic = "UnpartitionedTopic", + UnpartitionedSubscription = "UnpartitionedSubscription", + PartitionedQueueWithSessions = "PartitionedQueueWithSessions", + PartitionedTopicWithSessions = "PartitionedTopicWithSessions", + PartitionedSubscriptionWithSessions = "PartitionedSubscriptionWithSessions", + UnpartitionedQueueWithSessions = "UnpartitionedQueueWithSessions", + UnpartitionedTopicWithSessions = "UnpartitionedTopicWithSessions", + UnpartitionedSubscriptionWithSessions = "UnpartitionedSubscriptionWithSessions" } /** diff --git a/sdk/servicebus/service-bus/test/utils/testutils2.ts b/sdk/servicebus/service-bus/test/utils/testutils2.ts index a400488b1a42..75ad80130f93 100644 --- a/sdk/servicebus/service-bus/test/utils/testutils2.ts +++ b/sdk/servicebus/service-bus/test/utils/testutils2.ts @@ -42,7 +42,7 @@ function getEntityNames( usesSessions: boolean; isPartitioned: boolean; } { - const name = TestClientType[testClientType]; + const name = testClientType; let prefix = ""; let isPartitioned = false; @@ -132,6 +132,58 @@ export async function drainAllMessages(receiver: Receiver<{}>): Promise { await receiver.close(); } +/** + * Returns a TestClientType for either a Queue or a Subscription + * @param useSessions + */ +export function getRandomTestClientType(): TestClientType { + const allTestClientTypes = [ + TestClientType.PartitionedQueue, + TestClientType.PartitionedSubscription, + TestClientType.UnpartitionedQueue, + TestClientType.UnpartitionedSubscription, + TestClientType.PartitionedQueueWithSessions, + TestClientType.PartitionedSubscriptionWithSessions, + TestClientType.UnpartitionedQueueWithSessions, + TestClientType.UnpartitionedSubscriptionWithSessions + ]; + + const index = Math.floor(Math.random() * allTestClientTypes.length); + return allTestClientTypes[index]; +} + +/** + * Returns a TestClientType for either a Queue or a Subscription with no + * sessions enabled + */ +export function getRandomTestClientTypeWithNoSessions(): TestClientType { + const noSessionTestClientTypes = [ + TestClientType.PartitionedQueue, + TestClientType.PartitionedSubscription, + TestClientType.UnpartitionedQueue, + TestClientType.UnpartitionedSubscription + ]; + + const index = Math.floor(Math.random() * noSessionTestClientTypes.length); + return noSessionTestClientTypes[index]; +} + +/** + * Returns a TestClientType for either a Queue or a Subscription with + * sessions enabled + */ +export function getRandomTestClientTypeWithSessions(): TestClientType { + const withSessionTestClientTypes = [ + TestClientType.PartitionedQueueWithSessions, + TestClientType.PartitionedSubscriptionWithSessions, + TestClientType.UnpartitionedQueueWithSessions, + TestClientType.UnpartitionedSubscriptionWithSessions + ]; + + const index = Math.floor(Math.random() * withSessionTestClientTypes.length); + return withSessionTestClientTypes[index]; +} + export type EntityName = ReturnType; /** diff --git a/sdk/storage/storage-blob-changefeed/test/blobchangefeedclient.spec.ts b/sdk/storage/storage-blob-changefeed/test/blobchangefeedclient.spec.ts index 4684b459dadf..4a74a865e18c 100644 --- a/sdk/storage/storage-blob-changefeed/test/blobchangefeedclient.spec.ts +++ b/sdk/storage/storage-blob-changefeed/test/blobchangefeedclient.spec.ts @@ -25,7 +25,7 @@ describe("BlobChangeFeedClient", async () => { }); afterEach(async function() { - recorder.stop(); + await recorder.stop(); }); it("next(): fetch all events", async () => { @@ -129,7 +129,7 @@ describe("BlobChangeFeedClient: Change Feed not configured", async () => { }); afterEach(async function() { - recorder.stop(); + await recorder.stop(); }); it("should throw when fetching changes", async () => { diff --git a/sdk/storage/storage-blob/package.json b/sdk/storage/storage-blob/package.json index ce12f58880a9..e45b2078ac18 100644 --- a/sdk/storage/storage-blob/package.json +++ b/sdk/storage/storage-blob/package.json @@ -34,7 +34,7 @@ "build:es6": "tsc -p tsconfig.json", "build:nodebrowser": "rollup -c 2>&1", "build:samples": "npm run clean && npm run build:es6 && cross-env ONLY_NODE=true rollup -c 2>&1 && npm run build:prep-samples", - "build:prep-samples": "node ../../../common/scripts/prep-samples.js && cd samples && tsc", + "build:prep-samples": "dev-tool samples prep && cd dist-samples && tsc", "build:test": "npm run build:es6 && rollup -c rollup.test.config.js 2>&1", "build:types": "downlevel-dts typings/latest typings/3.1", "build": "npm run build:es6 && npm run build:nodebrowser && api-extractor run --local && npm run build:types", @@ -42,9 +42,7 @@ "clean": "rimraf dist dist-esm dist-test typings temp dist-browser/*.js* dist-browser/*.zip statistics.html coverage coverage-browser .nyc_output *.tgz *.log test*.xml TEST*.xml", "clean:samples": "rimraf samples/javascript/node_modules samples/typescript/node_modules samples/typescript/dist samples/typescript/package-lock.json samples/javascript/package-lock.json", "extract-api": "tsc -p . && api-extractor run --local", - "execute:js-samples": "node ../../../common/scripts/run-samples.js samples/javascript/", - "execute:ts-samples": "node ../../../common/scripts/run-samples.js samples/typescript/dist/storage-blob/samples/typescript/src/", - "execute:samples": "npm run build:samples && npm run execute:js-samples && npm run execute:ts-samples", + "execute:samples": "npm run build:samples && dev-tool samples run dist-samples/javascript dist-samples/typescript/dist/storage-blob/dist-samples/typescript/src/", "format": "prettier --write --config ../../.prettierrc.json --ignore-path ../../.prettierignore \"src/**/*.ts\" \"test/**/*.ts\" \"*.{js,json}\"", "integration-test:browser": "karma start --single-run", "integration-test:node": "nyc mocha -r esm --require source-map-support/register --reporter ../../../common/tools/mocha-multi-reporter.js --full-trace -t 300000 dist-esm/storage-blob/test/*.spec.js dist-esm/storage-blob/test/node/*.spec.js", @@ -111,6 +109,7 @@ "tslib": "^2.0.0" }, "devDependencies": { + "@azure/dev-tool": "^1.0.0", "@azure/identity": "^1.1.0-preview", "@azure/test-utils-recorder": "^1.0.0", "@microsoft/api-extractor": "7.7.11", diff --git a/sdk/storage/storage-blob/test/aborter.spec.ts b/sdk/storage/storage-blob/test/aborter.spec.ts index 69ec5477633f..179f3e061871 100644 --- a/sdk/storage/storage-blob/test/aborter.spec.ts +++ b/sdk/storage/storage-blob/test/aborter.spec.ts @@ -21,8 +21,8 @@ describe("Aborter", () => { containerClient = blobServiceClient.getContainerClient(containerName); }); - afterEach(function() { - recorder.stop(); + afterEach(async function() { + await recorder.stop(); }); it("Should abort after aborter timeout", async () => { diff --git a/sdk/storage/storage-blob/test/appendblobclient.spec.ts b/sdk/storage/storage-blob/test/appendblobclient.spec.ts index eb740182d732..48a418aab13a 100644 --- a/sdk/storage/storage-blob/test/appendblobclient.spec.ts +++ b/sdk/storage/storage-blob/test/appendblobclient.spec.ts @@ -31,7 +31,7 @@ describe("AppendBlobClient", () => { afterEach(async function() { await containerClient.delete(); - recorder.stop(); + await recorder.stop(); }); it("create with default parameters", async () => { diff --git a/sdk/storage/storage-blob/test/blobbatch.spec.ts b/sdk/storage/storage-blob/test/blobbatch.spec.ts index 49aa643c461a..e4d073cca579 100644 --- a/sdk/storage/storage-blob/test/blobbatch.spec.ts +++ b/sdk/storage/storage-blob/test/blobbatch.spec.ts @@ -56,7 +56,7 @@ describe("BlobBatch", () => { afterEach(async function() { if (!this.currentTest?.isPending()) { await containerClient.delete(); - recorder.stop(); + await recorder.stop(); } }); diff --git a/sdk/storage/storage-blob/test/blobclient.spec.ts b/sdk/storage/storage-blob/test/blobclient.spec.ts index 6111c6d54917..5e9f11469dc2 100644 --- a/sdk/storage/storage-blob/test/blobclient.spec.ts +++ b/sdk/storage/storage-blob/test/blobclient.spec.ts @@ -47,7 +47,7 @@ describe("BlobClient", () => { afterEach(async function() { if (!this.currentTest?.isPending()) { await containerClient.delete(); - recorder.stop(); + await recorder.stop(); } }); diff --git a/sdk/storage/storage-blob/test/blobclientpollers.spec.ts b/sdk/storage/storage-blob/test/blobclientpollers.spec.ts index 331efd37f019..da5ca6f0eece 100644 --- a/sdk/storage/storage-blob/test/blobclientpollers.spec.ts +++ b/sdk/storage/storage-blob/test/blobclientpollers.spec.ts @@ -49,7 +49,7 @@ describe("BlobClient beginCopyFromURL Poller", () => { if (!this.currentTest?.isPending()) { await containerClient.delete(); await destinationContainerClient.delete(); - recorder.stop(); + await recorder.stop(); } }); diff --git a/sdk/storage/storage-blob/test/blobserviceclient.spec.ts b/sdk/storage/storage-blob/test/blobserviceclient.spec.ts index 72a39af1de67..677da322e472 100644 --- a/sdk/storage/storage-blob/test/blobserviceclient.spec.ts +++ b/sdk/storage/storage-blob/test/blobserviceclient.spec.ts @@ -23,7 +23,7 @@ describe("BlobServiceClient", () => { }); afterEach(async function() { - recorder.stop(); + await recorder.stop(); }); it("ListContainers with default parameters", async () => { diff --git a/sdk/storage/storage-blob/test/blobversioning.spec.ts b/sdk/storage/storage-blob/test/blobversioning.spec.ts index b0173ff33719..a1a40e3c1e37 100644 --- a/sdk/storage/storage-blob/test/blobversioning.spec.ts +++ b/sdk/storage/storage-blob/test/blobversioning.spec.ts @@ -43,7 +43,7 @@ describe("Blob versioning", () => { afterEach(async function() { await containerClient.delete(); - recorder.stop(); + await recorder.stop(); }); it("List Blobs include versions", async () => { diff --git a/sdk/storage/storage-blob/test/blockblobclient.spec.ts b/sdk/storage/storage-blob/test/blockblobclient.spec.ts index 998c8a4fcbf7..2b0de5e10082 100644 --- a/sdk/storage/storage-blob/test/blockblobclient.spec.ts +++ b/sdk/storage/storage-blob/test/blockblobclient.spec.ts @@ -37,7 +37,7 @@ describe("BlockBlobClient", () => { afterEach(async function() { if (!this.currentTest?.isPending()) { await containerClient.delete(); - recorder.stop(); + await recorder.stop(); } }); diff --git a/sdk/storage/storage-blob/test/browser/highlevel.browser.spec.ts b/sdk/storage/storage-blob/test/browser/highlevel.browser.spec.ts index f41a2c54e35f..e5779141ca72 100644 --- a/sdk/storage/storage-blob/test/browser/highlevel.browser.spec.ts +++ b/sdk/storage/storage-blob/test/browser/highlevel.browser.spec.ts @@ -43,7 +43,7 @@ describe("Highlevel", () => { afterEach(async function() { if (!this.currentTest?.isPending()) { await containerClient.delete(); - recorder.stop(); + await recorder.stop(); } }); @@ -51,7 +51,7 @@ describe("Highlevel", () => { recorder = record(this, recorderEnvSetup); tempFile1 = getBrowserFile(recorder.getUniqueName("browserfile"), tempFile1Length); tempFile2 = getBrowserFile(recorder.getUniqueName("browserfile2"), tempFile2Length); - recorder.stop(); + await recorder.stop(); }); after(async () => {}); diff --git a/sdk/storage/storage-blob/test/containerclient.spec.ts b/sdk/storage/storage-blob/test/containerclient.spec.ts index 3a5896a589af..2dcbf5ee6947 100644 --- a/sdk/storage/storage-blob/test/containerclient.spec.ts +++ b/sdk/storage/storage-blob/test/containerclient.spec.ts @@ -36,7 +36,7 @@ describe("ContainerClient", () => { afterEach(async function() { await containerClient.delete(); - recorder.stop(); + await recorder.stop(); }); it("setMetadata", async () => { diff --git a/sdk/storage/storage-blob/test/encrytion.spec.ts b/sdk/storage/storage-blob/test/encrytion.spec.ts index e1a09668f6b0..5680081c5de6 100644 --- a/sdk/storage/storage-blob/test/encrytion.spec.ts +++ b/sdk/storage/storage-blob/test/encrytion.spec.ts @@ -50,7 +50,7 @@ describe("Encryption Scope", function() { if (containerClient) { await containerClient.delete(); } - recorder.stop(); + await recorder.stop(); }); it("create container", async () => { diff --git a/sdk/storage/storage-blob/test/leaseclient.spec.ts b/sdk/storage/storage-blob/test/leaseclient.spec.ts index d1f90d2d55a8..8f4fce62a4ac 100644 --- a/sdk/storage/storage-blob/test/leaseclient.spec.ts +++ b/sdk/storage/storage-blob/test/leaseclient.spec.ts @@ -23,7 +23,7 @@ describe("LeaseClient from Container", () => { afterEach(async function() { await containerClient.delete(); - recorder.stop(); + await recorder.stop(); }); it("acquireLease", async () => { @@ -161,7 +161,7 @@ describe("LeaseClient from Blob", () => { afterEach(async function() { await containerClient.delete(); - recorder.stop(); + await recorder.stop(); }); it("acquireLease", async () => { diff --git a/sdk/storage/storage-blob/test/node/appendblobclient.spec.ts b/sdk/storage/storage-blob/test/node/appendblobclient.spec.ts index 4990d9df44fc..c814910c1ed3 100644 --- a/sdk/storage/storage-blob/test/node/appendblobclient.spec.ts +++ b/sdk/storage/storage-blob/test/node/appendblobclient.spec.ts @@ -43,7 +43,7 @@ describe("AppendBlobClient Node.js only", () => { afterEach(async function() { await containerClient.delete(); - recorder.stop(); + await recorder.stop(); }); it("can be created with a url and a credential", async () => { diff --git a/sdk/storage/storage-blob/test/node/blobclient.spec.ts b/sdk/storage/storage-blob/test/node/blobclient.spec.ts index ea67a13acb7d..43e6d7c42932 100644 --- a/sdk/storage/storage-blob/test/node/blobclient.spec.ts +++ b/sdk/storage/storage-blob/test/node/blobclient.spec.ts @@ -55,7 +55,7 @@ describe("BlobClient Node.js only", () => { afterEach(async function() { await containerClient.delete(); - recorder.stop(); + await recorder.stop(); }); it("download with with default parameters", async () => { diff --git a/sdk/storage/storage-blob/test/node/blobserviceclient.spec.ts b/sdk/storage/storage-blob/test/node/blobserviceclient.spec.ts index ab7ebb931e15..e568ba4f2c0d 100644 --- a/sdk/storage/storage-blob/test/node/blobserviceclient.spec.ts +++ b/sdk/storage/storage-blob/test/node/blobserviceclient.spec.ts @@ -14,7 +14,7 @@ describe("BlobServiceClient Node.js only", () => { }); afterEach(async function() { - recorder.stop(); + await recorder.stop(); }); it("can be created with a url and a credential", async () => { diff --git a/sdk/storage/storage-blob/test/node/blockblobclient.spec.ts b/sdk/storage/storage-blob/test/node/blockblobclient.spec.ts index 50bd0e64e62d..fb947c6ed89e 100644 --- a/sdk/storage/storage-blob/test/node/blockblobclient.spec.ts +++ b/sdk/storage/storage-blob/test/node/blockblobclient.spec.ts @@ -42,7 +42,7 @@ describe("BlockBlobClient Node.js only", () => { afterEach(async function() { if (!this.currentTest?.isPending()) { await containerClient.delete(); - recorder.stop(); + await recorder.stop(); } }); diff --git a/sdk/storage/storage-blob/test/node/containerclient.spec.ts b/sdk/storage/storage-blob/test/node/containerclient.spec.ts index 5298e6b1edda..615884f56ec5 100644 --- a/sdk/storage/storage-blob/test/node/containerclient.spec.ts +++ b/sdk/storage/storage-blob/test/node/containerclient.spec.ts @@ -29,7 +29,7 @@ describe("ContainerClient Node.js only", () => { afterEach(async function() { await containerClient.delete(); - recorder.stop(); + await recorder.stop(); }); it("getAccessPolicy", async () => { diff --git a/sdk/storage/storage-blob/test/node/highlevel.node.spec.ts b/sdk/storage/storage-blob/test/node/highlevel.node.spec.ts index 65b5102ae1e6..8c2aa5df814d 100644 --- a/sdk/storage/storage-blob/test/node/highlevel.node.spec.ts +++ b/sdk/storage/storage-blob/test/node/highlevel.node.spec.ts @@ -43,7 +43,7 @@ describe("Highlevel", () => { afterEach(async function() { if (!this.currentTest?.isPending()) { await containerClient.delete(); - recorder.stop(); + await recorder.stop(); } }); @@ -56,14 +56,14 @@ describe("Highlevel", () => { tempFileLargeLength = 257 * 1024 * 1024; tempFileSmall = await createRandomLocalFile(tempFolderPath, 15, 1024 * 1024); tempFileSmallLength = 15 * 1024 * 1024; - recorder.stop(); + await recorder.stop(); }); after(async function() { recorder = record(this, recorderEnvSetup); fs.unlinkSync(tempFileLarge); fs.unlinkSync(tempFileSmall); - recorder.stop(); + await recorder.stop(); }); it("put blob with maximum size", async () => { diff --git a/sdk/storage/storage-blob/test/node/pageblobclient.spec.ts b/sdk/storage/storage-blob/test/node/pageblobclient.spec.ts index 711a17c3976d..f85964f1873d 100644 --- a/sdk/storage/storage-blob/test/node/pageblobclient.spec.ts +++ b/sdk/storage/storage-blob/test/node/pageblobclient.spec.ts @@ -44,7 +44,7 @@ describe("PageBlobClient Node.js only", () => { afterEach(async function() { await containerClient.delete(); - recorder.stop(); + await recorder.stop(); }); it("startCopyIncremental", async () => { diff --git a/sdk/storage/storage-blob/test/node/sas.spec.ts b/sdk/storage/storage-blob/test/node/sas.spec.ts index ba38da66a31f..22b3a67e41f4 100644 --- a/sdk/storage/storage-blob/test/node/sas.spec.ts +++ b/sdk/storage/storage-blob/test/node/sas.spec.ts @@ -31,8 +31,8 @@ describe("Shared Access Signature (SAS) generation Node.js only", () => { blobServiceClient = getBSU(); }); - afterEach(function() { - recorder.stop(); + afterEach(async function() { + await recorder.stop(); }); it("generateAccountSASQueryParameters should work", async () => { diff --git a/sdk/storage/storage-blob/test/pageblobclient.spec.ts b/sdk/storage/storage-blob/test/pageblobclient.spec.ts index 9281abdc7f96..bd955829799b 100644 --- a/sdk/storage/storage-blob/test/pageblobclient.spec.ts +++ b/sdk/storage/storage-blob/test/pageblobclient.spec.ts @@ -40,7 +40,7 @@ describe("PageBlobClient", () => { afterEach(async function() { await containerClient.delete(); - recorder.stop(); + await recorder.stop(); }); it("create with default parameters", async () => { diff --git a/sdk/storage/storage-blob/test/retrypolicy.spec.ts b/sdk/storage/storage-blob/test/retrypolicy.spec.ts index 734dead3dc32..9c22c343fb21 100644 --- a/sdk/storage/storage-blob/test/retrypolicy.spec.ts +++ b/sdk/storage/storage-blob/test/retrypolicy.spec.ts @@ -28,7 +28,7 @@ describe("RetryPolicy", () => { afterEach(async function() { await containerClient.delete(); - recorder.stop(); + await recorder.stop(); }); it("Retry Policy should work when first request fails with 500", async () => { diff --git a/sdk/storage/storage-blob/test/specialnaming.spec.ts b/sdk/storage/storage-blob/test/specialnaming.spec.ts index 0e9aa309ba1a..ddf488c179b2 100644 --- a/sdk/storage/storage-blob/test/specialnaming.spec.ts +++ b/sdk/storage/storage-blob/test/specialnaming.spec.ts @@ -24,7 +24,7 @@ describe("Special Naming Tests", () => { afterEach(async function() { await containerClient.delete(); - recorder.stop(); + await recorder.stop(); }); it("Should work with special container and blob names with spaces", async () => { diff --git a/sdk/storage/storage-file-datalake/test/aborter.spec.ts b/sdk/storage/storage-file-datalake/test/aborter.spec.ts index f1b3dc790fcd..ecbba25d26eb 100644 --- a/sdk/storage/storage-file-datalake/test/aborter.spec.ts +++ b/sdk/storage/storage-file-datalake/test/aborter.spec.ts @@ -21,8 +21,8 @@ describe("Aborter", () => { fileSystemClient = serviceClient.getFileSystemClient(fileSystemName); }); - afterEach(function() { - recorder.stop(); + afterEach(async function() { + await recorder.stop(); }); it("Should abort after aborter timeout", async () => { diff --git a/sdk/storage/storage-file-datalake/test/browser/highlevel.browser.spec.ts b/sdk/storage/storage-file-datalake/test/browser/highlevel.browser.spec.ts index f73149977eb5..cc7890f05ba1 100644 --- a/sdk/storage/storage-file-datalake/test/browser/highlevel.browser.spec.ts +++ b/sdk/storage/storage-file-datalake/test/browser/highlevel.browser.spec.ts @@ -40,7 +40,7 @@ describe("Highlevel browser only", () => { afterEach(async function() { if (!this.currentTest?.isPending()) { await fileSystemClient.delete(); - recorder.stop(); + await recorder.stop(); } }); @@ -48,7 +48,7 @@ describe("Highlevel browser only", () => { recorder = record(this, recorderEnvSetup); tempFileLarge = getBrowserFile(recorder.getUniqueName("browserfilesmall"), tempFileLargeLength); tempFileSmall = getBrowserFile(recorder.getUniqueName("browserfilelarge"), tempFileSmallLength); - recorder.stop(); + await recorder.stop(); }); after(async () => {}); diff --git a/sdk/storage/storage-file-datalake/test/filesystemclient.spec.ts b/sdk/storage/storage-file-datalake/test/filesystemclient.spec.ts index 00e370a7952f..f6932adb6c95 100644 --- a/sdk/storage/storage-file-datalake/test/filesystemclient.spec.ts +++ b/sdk/storage/storage-file-datalake/test/filesystemclient.spec.ts @@ -30,7 +30,7 @@ describe("DataLakeFileSystemClient", () => { afterEach(async function() { await fileSystemClient.delete(); - recorder.stop(); + await recorder.stop(); }); it("setMetadata", async () => { diff --git a/sdk/storage/storage-file-datalake/test/leaseclient.spec.ts b/sdk/storage/storage-file-datalake/test/leaseclient.spec.ts index cccbda46d9b2..18c5e8682be9 100644 --- a/sdk/storage/storage-file-datalake/test/leaseclient.spec.ts +++ b/sdk/storage/storage-file-datalake/test/leaseclient.spec.ts @@ -23,7 +23,7 @@ describe("LeaseClient from FileSystem", () => { afterEach(async function() { await fileSystemClient.delete(); - recorder.stop(); + await recorder.stop(); }); it("acquireLease", async () => { @@ -158,7 +158,7 @@ describe("LeaseClient from File", () => { afterEach(async function() { await fileSystemClient.delete(); - recorder.stop(); + await recorder.stop(); }); it("acquireLease", async () => { @@ -281,7 +281,7 @@ describe("LeaseClient from Directory", () => { afterEach(async function() { await fileSystemClient.delete(); - recorder.stop(); + await recorder.stop(); }); it("acquireLease", async () => { diff --git a/sdk/storage/storage-file-datalake/test/node/filesystemclient.spec.ts b/sdk/storage/storage-file-datalake/test/node/filesystemclient.spec.ts index 4cb9bda7f332..8f56e6db64de 100644 --- a/sdk/storage/storage-file-datalake/test/node/filesystemclient.spec.ts +++ b/sdk/storage/storage-file-datalake/test/node/filesystemclient.spec.ts @@ -27,7 +27,7 @@ describe("DataLakeFileSystemClient Node.js only", () => { afterEach(async function() { await fileSystemClient.delete(); - recorder.stop(); + await recorder.stop(); }); it("getAccessPolicy", async () => { diff --git a/sdk/storage/storage-file-datalake/test/node/highlevel.node.spec.ts b/sdk/storage/storage-file-datalake/test/node/highlevel.node.spec.ts index 6e6d67c58bb0..844373eea4c5 100644 --- a/sdk/storage/storage-file-datalake/test/node/highlevel.node.spec.ts +++ b/sdk/storage/storage-file-datalake/test/node/highlevel.node.spec.ts @@ -36,7 +36,7 @@ describe("Highlevel Node.js only", () => { let recorder: any; - beforeEach(async function () { + beforeEach(async function() { recorder = record(this, recorderEnvSetup); const serviceClient = getDataLakeServiceClient(); fileSystemName = recorder.getUniqueName("filesystem"); @@ -46,14 +46,14 @@ describe("Highlevel Node.js only", () => { fileClient = fileSystemClient.getFileClient(fileName); }); - afterEach(async function () { + afterEach(async function() { if (!this.currentTest?.isPending()) { await fileSystemClient.delete(); - recorder.stop(); + await recorder.stop(); } }); - before(async function () { + before(async function() { recorder = record(this, recorderEnvSetup); if (!fs.existsSync(tempFolderPath)) { fs.mkdirSync(tempFolderPath); @@ -63,14 +63,14 @@ describe("Highlevel Node.js only", () => { tempFileSmall = await createRandomLocalFile(tempFolderPath, 15, MB); tempFileSmallLength = 15 * MB; - recorder.stop(); + await recorder.stop(); }); - after(async function () { + after(async function() { recorder = record(this, recorderEnvSetup); fs.unlinkSync(tempFileLarge); fs.unlinkSync(tempFileSmall); - recorder.stop(); + await recorder.stop(); }); it("upload should work for large data", async () => { diff --git a/sdk/storage/storage-file-datalake/test/node/pathclient.spec.ts b/sdk/storage/storage-file-datalake/test/node/pathclient.spec.ts index 1cd01e916b19..61c459d06c15 100644 --- a/sdk/storage/storage-file-datalake/test/node/pathclient.spec.ts +++ b/sdk/storage/storage-file-datalake/test/node/pathclient.spec.ts @@ -38,7 +38,7 @@ describe("DataLakePathClient Node.js only", () => { afterEach(async function() { await fileSystemClient.delete(); - recorder.stop(); + await recorder.stop(); }); it("setAccessControl", async () => { diff --git a/sdk/storage/storage-file-datalake/test/node/sas.spec.ts b/sdk/storage/storage-file-datalake/test/node/sas.spec.ts index 1ee2ec96c7d5..ff5603f2caba 100644 --- a/sdk/storage/storage-file-datalake/test/node/sas.spec.ts +++ b/sdk/storage/storage-file-datalake/test/node/sas.spec.ts @@ -32,8 +32,8 @@ describe("Shared Access Signature (SAS) generation Node.js only", () => { serviceClient = getDataLakeServiceClient(); }); - afterEach(function() { - recorder.stop(); + afterEach(async function() { + await recorder.stop(); }); it("generateAccountSASQueryParameters should work", async () => { diff --git a/sdk/storage/storage-file-datalake/test/pathclient.spec.ts b/sdk/storage/storage-file-datalake/test/pathclient.spec.ts index bf84cb084fe7..f0a30186f286 100644 --- a/sdk/storage/storage-file-datalake/test/pathclient.spec.ts +++ b/sdk/storage/storage-file-datalake/test/pathclient.spec.ts @@ -35,7 +35,7 @@ describe("DataLakePathClient", () => { afterEach(async function() { await fileSystemClient.delete(); - recorder.stop(); + await recorder.stop(); }); it("read with with default parameters", async () => { diff --git a/sdk/storage/storage-file-datalake/test/retrypolicy.spec.ts b/sdk/storage/storage-file-datalake/test/retrypolicy.spec.ts index 376f42bb7d50..924a84871bd3 100644 --- a/sdk/storage/storage-file-datalake/test/retrypolicy.spec.ts +++ b/sdk/storage/storage-file-datalake/test/retrypolicy.spec.ts @@ -27,7 +27,7 @@ describe("RetryPolicy", () => { afterEach(async function() { await dataLakeFileSystemClient.delete(); - recorder.stop(); + await recorder.stop(); }); it("Retry Policy should work when first request fails with 500", async () => { diff --git a/sdk/storage/storage-file-datalake/test/serviceclient.spec.ts b/sdk/storage/storage-file-datalake/test/serviceclient.spec.ts index 865105646f45..e5b7b3f8db49 100644 --- a/sdk/storage/storage-file-datalake/test/serviceclient.spec.ts +++ b/sdk/storage/storage-file-datalake/test/serviceclient.spec.ts @@ -15,7 +15,7 @@ describe("DataLakeServiceClient", () => { }); afterEach(async function() { - recorder.stop(); + await recorder.stop(); }); it("ListFileSystems with default parameters", async () => { diff --git a/sdk/storage/storage-file-datalake/test/specialnaming.spec.ts b/sdk/storage/storage-file-datalake/test/specialnaming.spec.ts index 8cd12773025a..1d0390a59bf5 100644 --- a/sdk/storage/storage-file-datalake/test/specialnaming.spec.ts +++ b/sdk/storage/storage-file-datalake/test/specialnaming.spec.ts @@ -26,7 +26,7 @@ describe("Special Naming Tests", () => { afterEach(async function() { await fileSystemClient.delete(); - recorder.stop(); + await recorder.stop(); }); it("Should work with special container and blob names with spaces", async () => { diff --git a/sdk/storage/storage-file-datalake/test/utils.spec.ts b/sdk/storage/storage-file-datalake/test/utils.spec.ts index 05a338d4affe..15a6b413e6d2 100644 --- a/sdk/storage/storage-file-datalake/test/utils.spec.ts +++ b/sdk/storage/storage-file-datalake/test/utils.spec.ts @@ -36,8 +36,8 @@ describe("Utility Helpers", () => { recorder = record(this, recorderEnvSetup); }); - afterEach(function() { - recorder.stop(); + afterEach(async function() { + await recorder.stop(); }); it("sanitizeURL redacts SAS token", () => { diff --git a/sdk/storage/storage-file-share/package.json b/sdk/storage/storage-file-share/package.json index 9e2b960819e8..8476528ae04a 100644 --- a/sdk/storage/storage-file-share/package.json +++ b/sdk/storage/storage-file-share/package.json @@ -32,7 +32,7 @@ "build:es6": "tsc -p tsconfig.json", "build:nodebrowser": "rollup -c 2>&1", "build:samples": "npm run clean && npm run build:es6 && cross-env ONLY_NODE=true rollup -c 2>&1 && npm run build:prep-samples", - "build:prep-samples": "node ../../../common/scripts/prep-samples.js && cd samples && tsc", + "build:prep-samples": "dev-tool samples prep && cd dist-samples && tsc", "build:test": "npm run build:es6 && rollup -c rollup.test.config.js 2>&1", "build:types": "downlevel-dts typings/latest typings/3.1", "build": "npm run build:es6 && npm run build:nodebrowser && api-extractor run --local && npm run build:types", @@ -40,9 +40,7 @@ "clean": "rimraf dist dist-esm dist-test typings temp dist-browser/*.js* dist-browser/*.zip statistics.html coverage coverage-browser .nyc_output *.tgz *.log test*.xml TEST*.xml", "clean:samples": "rimraf samples/javascript/node_modules samples/typescript/node_modules samples/typescript/dist samples/typescript/package-lock.json samples/javascript/package-lock.json", "extract-api": "tsc -p . && api-extractor run --local", - "execute:js-samples": "node ../../../common/scripts/run-samples.js samples/javascript/", - "execute:ts-samples": "node ../../../common/scripts/run-samples.js samples/typescript/dist/samples/typescript/src/", - "execute:samples": "npm run build:samples && npm run execute:js-samples && npm run execute:ts-samples", + "execute:samples": "npm run build:samples && dev-tool samples run dist-samples/javascript dist-samples/typescript/dist/dist-samples/typescript/src/", "format": "prettier --write --config ../../.prettierrc.json --ignore-path ../../.prettierignore \"src/**/*.ts\" \"test/**/*.ts\" \"*.{js,json}\"", "integration-test:browser": "karma start --single-run", "integration-test:node": "nyc mocha -r esm --require source-map-support/register --reporter ../../../common/tools/mocha-multi-reporter.js --full-trace -t 300000 dist-esm/test/*.spec.js dist-esm/test/node/*.spec.js", @@ -111,6 +109,7 @@ "tslib": "^2.0.0" }, "devDependencies": { + "@azure/dev-tool": "^1.0.0", "@azure/test-utils-recorder": "^1.0.0", "@microsoft/api-extractor": "7.7.11", "@rollup/plugin-commonjs": "11.0.2", diff --git a/sdk/storage/storage-file-share/test/aborter.spec.ts b/sdk/storage/storage-file-share/test/aborter.spec.ts index 3478978c7984..debbd48aa7bd 100644 --- a/sdk/storage/storage-file-share/test/aborter.spec.ts +++ b/sdk/storage/storage-file-share/test/aborter.spec.ts @@ -21,8 +21,8 @@ describe("Aborter", () => { shareClient = serviceClient.getShareClient(shareName); }); - afterEach(function() { - recorder.stop(); + afterEach(async function() { + await recorder.stop(); }); it("Should abort after aborter timeout", async () => { diff --git a/sdk/storage/storage-file-share/test/directoryclient.spec.ts b/sdk/storage/storage-file-share/test/directoryclient.spec.ts index 827509d99849..1c1d161628bb 100644 --- a/sdk/storage/storage-file-share/test/directoryclient.spec.ts +++ b/sdk/storage/storage-file-share/test/directoryclient.spec.ts @@ -51,7 +51,7 @@ describe("DirectoryClient", () => { afterEach(async function() { await shareClient.delete(); - recorder.stop(); + await recorder.stop(); }); it("setMetadata", async () => { diff --git a/sdk/storage/storage-file-share/test/fileclient.spec.ts b/sdk/storage/storage-file-share/test/fileclient.spec.ts index 5d725d588b15..08a233c29ce0 100644 --- a/sdk/storage/storage-file-share/test/fileclient.spec.ts +++ b/sdk/storage/storage-file-share/test/fileclient.spec.ts @@ -61,7 +61,7 @@ describe("FileClient", () => { afterEach(async function() { if (!this.currentTest?.isPending()) { await shareClient.delete(); - recorder.stop(); + await recorder.stop(); } }); diff --git a/sdk/storage/storage-file-share/test/fileserviceclient.spec.ts b/sdk/storage/storage-file-share/test/fileserviceclient.spec.ts index 4ff76dd093a3..7cf45078d50e 100644 --- a/sdk/storage/storage-file-share/test/fileserviceclient.spec.ts +++ b/sdk/storage/storage-file-share/test/fileserviceclient.spec.ts @@ -13,8 +13,8 @@ describe("FileServiceClient", () => { recorder = record(this, recorderEnvSetup); }); - afterEach(function() { - recorder.stop(); + afterEach(async function() { + await recorder.stop(); }); it("ListShares with default parameters", async () => { diff --git a/sdk/storage/storage-file-share/test/leaseclient.spec.ts b/sdk/storage/storage-file-share/test/leaseclient.spec.ts index 19817ccdfeac..58111ff8ce92 100644 --- a/sdk/storage/storage-file-share/test/leaseclient.spec.ts +++ b/sdk/storage/storage-file-share/test/leaseclient.spec.ts @@ -48,7 +48,7 @@ describe("LeaseClient", () => { afterEach(async function() { await shareClient.delete(); - recorder.stop(); + await recorder.stop(); }); // lease management: diff --git a/sdk/storage/storage-file-share/test/node/directoryclient.spec.ts b/sdk/storage/storage-file-share/test/node/directoryclient.spec.ts index 311d74df9389..a65bd2d30378 100644 --- a/sdk/storage/storage-file-share/test/node/directoryclient.spec.ts +++ b/sdk/storage/storage-file-share/test/node/directoryclient.spec.ts @@ -33,7 +33,7 @@ describe("DirectoryClient Node.js only", () => { afterEach(async function() { await dirClient.delete(); await shareClient.delete(); - recorder.stop(); + await recorder.stop(); }); it("can be created with a url and a credential", async () => { diff --git a/sdk/storage/storage-file-share/test/node/fileclient.spec.ts b/sdk/storage/storage-file-share/test/node/fileclient.spec.ts index 35200b2c4573..7da1da8a3841 100644 --- a/sdk/storage/storage-file-share/test/node/fileclient.spec.ts +++ b/sdk/storage/storage-file-share/test/node/fileclient.spec.ts @@ -49,7 +49,7 @@ describe("FileClient Node.js only", () => { afterEach(async function() { if (!this.currentTest?.isPending()) { await shareClient.delete(); - recorder.stop(); + await recorder.stop(); } }); diff --git a/sdk/storage/storage-file-share/test/node/fileserviceclient.spec.ts b/sdk/storage/storage-file-share/test/node/fileserviceclient.spec.ts index 23332fcc0c7e..6fcfc8e7e25c 100644 --- a/sdk/storage/storage-file-share/test/node/fileserviceclient.spec.ts +++ b/sdk/storage/storage-file-share/test/node/fileserviceclient.spec.ts @@ -13,7 +13,7 @@ describe("FileServiceClient Node.js only", () => { }); afterEach(async function() { - recorder.stop(); + await recorder.stop(); }); it("can be created with a url and a credential", async () => { diff --git a/sdk/storage/storage-file-share/test/node/highlevel.node.spec.ts b/sdk/storage/storage-file-share/test/node/highlevel.node.spec.ts index af52b93986fa..6ac0de8d723f 100644 --- a/sdk/storage/storage-file-share/test/node/highlevel.node.spec.ts +++ b/sdk/storage/storage-file-share/test/node/highlevel.node.spec.ts @@ -43,7 +43,7 @@ describe("Highlevel Node.js only", () => { afterEach(async function() { if (!this.currentTest?.isPending()) { await shareClient.delete(); - recorder.stop(); + await recorder.stop(); } }); diff --git a/sdk/storage/storage-file-share/test/node/sas.spec.ts b/sdk/storage/storage-file-share/test/node/sas.spec.ts index 237538d780c8..af321b089c81 100644 --- a/sdk/storage/storage-file-share/test/node/sas.spec.ts +++ b/sdk/storage/storage-file-share/test/node/sas.spec.ts @@ -28,8 +28,8 @@ describe("Shared Access Signature (SAS) generation Node.js only", () => { serviceClient = getBSU(); }); - afterEach(function() { - recorder.stop(); + afterEach(async function() { + await recorder.stop(); }); it("generateAccountSASQueryParameters should work", async () => { diff --git a/sdk/storage/storage-file-share/test/node/shareclient.spec.ts b/sdk/storage/storage-file-share/test/node/shareclient.spec.ts index 5307652a96de..2018cc066817 100644 --- a/sdk/storage/storage-file-share/test/node/shareclient.spec.ts +++ b/sdk/storage/storage-file-share/test/node/shareclient.spec.ts @@ -19,7 +19,7 @@ describe("ShareClient Node.js only", () => { afterEach(async function() { await shareClient.delete(); - recorder.stop(); + await recorder.stop(); }); it("setAccessPolicy", async () => { diff --git a/sdk/storage/storage-file-share/test/node/sharedkeycredentialpolicy.spec.ts b/sdk/storage/storage-file-share/test/node/sharedkeycredentialpolicy.spec.ts index 272d1ae06a2f..624499142764 100644 --- a/sdk/storage/storage-file-share/test/node/sharedkeycredentialpolicy.spec.ts +++ b/sdk/storage/storage-file-share/test/node/sharedkeycredentialpolicy.spec.ts @@ -14,21 +14,21 @@ describe("StorageSharedKeyCredentialPolicy Node.js only", () => { shareName = recorder.getUniqueName("1share-with-dash"); shareClient = serviceClient.getShareClient(shareName); await shareClient.create(); - recorder.stop(); + await recorder.stop(); }); after(async function() { recorder = record(this, recorderEnvSetup); await shareClient.delete(); - recorder.stop(); + await recorder.stop(); }); beforeEach(function() { recorder = record(this, recorderEnvSetup); }); - afterEach(function() { - recorder.stop(); + afterEach(async function() { + await recorder.stop(); }); it("StorageSharedKeyCredentialPolicy should work with special share and file names with spaces", async () => { diff --git a/sdk/storage/storage-file-share/test/node/utils.spec.ts b/sdk/storage/storage-file-share/test/node/utils.spec.ts index ee5e17fb2c6d..80d6e10ee8c1 100644 --- a/sdk/storage/storage-file-share/test/node/utils.spec.ts +++ b/sdk/storage/storage-file-share/test/node/utils.spec.ts @@ -37,7 +37,7 @@ describe("Utility Helpers Node.js only", () => { }); afterEach(async function() { - recorder.stop(); + await recorder.stop(); }); it("extractConnectionStringParts throws error when passed an invalid protocol in the connection string", async () => { diff --git a/sdk/storage/storage-file-share/test/retrypolicy.spec.ts b/sdk/storage/storage-file-share/test/retrypolicy.spec.ts index 9bdcf416d3fb..71f241a5a628 100644 --- a/sdk/storage/storage-file-share/test/retrypolicy.spec.ts +++ b/sdk/storage/storage-file-share/test/retrypolicy.spec.ts @@ -25,7 +25,7 @@ describe("RetryPolicy", () => { afterEach(async function() { await shareClient.delete(); - recorder.stop(); + await recorder.stop(); }); it("Retry Policy should work when first request fails with 500", async () => { diff --git a/sdk/storage/storage-file-share/test/shareclient.spec.ts b/sdk/storage/storage-file-share/test/shareclient.spec.ts index 0b32922940ba..4bffc887ddd0 100644 --- a/sdk/storage/storage-file-share/test/shareclient.spec.ts +++ b/sdk/storage/storage-file-share/test/shareclient.spec.ts @@ -22,7 +22,7 @@ describe("ShareClient", () => { afterEach(async function() { await shareClient.delete(); - recorder.stop(); + await recorder.stop(); }); it("setMetadata", async () => { diff --git a/sdk/storage/storage-file-share/test/specialnaming.spec.ts b/sdk/storage/storage-file-share/test/specialnaming.spec.ts index 28580c365af1..b687cd121e68 100644 --- a/sdk/storage/storage-file-share/test/specialnaming.spec.ts +++ b/sdk/storage/storage-file-share/test/specialnaming.spec.ts @@ -29,21 +29,21 @@ describe("Special Naming Tests", () => { await shareClient.create(); await directoryClient.create(); - recorder.stop(); + await recorder.stop(); }); after(async function() { recorder = record(this, recorderEnvSetup); await shareClient.delete(); - recorder.stop(); + await recorder.stop(); }); beforeEach(function() { recorder = record(this, recorderEnvSetup); }); - afterEach(function() { - recorder.stop(); + afterEach(async function() { + await recorder.stop(); }); it("Should work with special container and file names with spaces", async () => { diff --git a/sdk/storage/storage-file-share/test/utils.spec.ts b/sdk/storage/storage-file-share/test/utils.spec.ts index b1ac9089213d..a2c7ce8cc57c 100644 --- a/sdk/storage/storage-file-share/test/utils.spec.ts +++ b/sdk/storage/storage-file-share/test/utils.spec.ts @@ -37,7 +37,7 @@ describe("Utility Helpers", () => { }); afterEach(async function() { - recorder.stop(); + await recorder.stop(); }); it("sanitizeURL redacts SAS token", () => { diff --git a/sdk/storage/storage-queue/package.json b/sdk/storage/storage-queue/package.json index ef215a8d596f..8eb2c70908ae 100644 --- a/sdk/storage/storage-queue/package.json +++ b/sdk/storage/storage-queue/package.json @@ -29,7 +29,7 @@ "build:es6": "tsc -p tsconfig.json", "build:nodebrowser": "rollup -c 2>&1", "build:samples": "npm run clean && npm run build:es6 && cross-env ONLY_NODE=true rollup -c 2>&1 && npm run build:prep-samples", - "build:prep-samples": "node ../../../common/scripts/prep-samples.js && cd samples && tsc", + "build:prep-samples": "dev-tool samples prep && cd dist-samples && tsc", "build:test": "npm run build:es6 && rollup -c rollup.test.config.js 2>&1", "build:types": "downlevel-dts typings/latest typings/3.1", "build": "npm run build:es6 && npm run build:nodebrowser && api-extractor run --local && npm run build:types", @@ -37,9 +37,7 @@ "clean": "rimraf dist dist-esm dist-test typings temp dist-browser/*.js* dist-browser/*.zip statistics.html coverage coverage-browser .nyc_output *.tgz *.log test*.xml TEST*.xml", "clean:samples": "rimraf samples/javascript/node_modules samples/typescript/node_modules samples/typescript/dist samples/typescript/package-lock.json samples/javascript/package-lock.json", "extract-api": "tsc -p . && api-extractor run --local", - "execute:js-samples": "node ../../../common/scripts/run-samples.js samples/javascript/", - "execute:ts-samples": "node ../../../common/scripts/run-samples.js samples/typescript/dist/samples/typescript/src/", - "execute:samples": "npm run build:samples && npm run execute:js-samples && npm run execute:ts-samples", + "execute:samples": "npm run build:samples && dev-tool samples run dist-samples/javascript dist-samples/typescript/dist/dist-samples/typescript/src/", "format": "prettier --write --config ../../.prettierrc.json --ignore-path ../../.prettierignore \"src/**/*.ts\" \"test/**/*.ts\" \"*.{js,json}\"", "integration-test:browser": "karma start --single-run", "integration-test:node": "nyc mocha -r esm --require source-map-support/register --reporter ../../../common/tools/mocha-multi-reporter.js --full-trace -t 120000 dist-esm/test/*.spec.js dist-esm/test/node/*.spec.js", @@ -107,6 +105,7 @@ "tslib": "^2.0.0" }, "devDependencies": { + "@azure/dev-tool": "^1.0.0", "@azure/identity": "^1.1.0-preview", "@azure/test-utils-recorder": "^1.0.0", "@microsoft/api-extractor": "7.7.11", diff --git a/sdk/storage/storage-queue/test/aborter.spec.ts b/sdk/storage/storage-queue/test/aborter.spec.ts index e2ccf4e135e2..724c6a5c788e 100644 --- a/sdk/storage/storage-queue/test/aborter.spec.ts +++ b/sdk/storage/storage-queue/test/aborter.spec.ts @@ -23,7 +23,7 @@ describe("Aborter", () => { }); afterEach(async function() { - recorder.stop(); + await recorder.stop(); }); it("should not abort after calling abort()", async () => { diff --git a/sdk/storage/storage-queue/test/messageidclient.spec.ts b/sdk/storage/storage-queue/test/messageidclient.spec.ts index 9a8d44acd475..eae5d21d32b2 100644 --- a/sdk/storage/storage-queue/test/messageidclient.spec.ts +++ b/sdk/storage/storage-queue/test/messageidclient.spec.ts @@ -24,7 +24,7 @@ describe("QueueClient messageId methods", () => { afterEach(async function() { await queueClient.delete(); - recorder.stop(); + await recorder.stop(); }); it("update and delete empty message with default parameters", async () => { diff --git a/sdk/storage/storage-queue/test/node/messageidclient.spec.ts b/sdk/storage/storage-queue/test/node/messageidclient.spec.ts index d2f1234ed348..f1c6c96e3e56 100644 --- a/sdk/storage/storage-queue/test/node/messageidclient.spec.ts +++ b/sdk/storage/storage-queue/test/node/messageidclient.spec.ts @@ -23,7 +23,7 @@ describe("QueueClient messageId methods, Node.js only", () => { afterEach(async function() { await queueClient.delete(); - recorder.stop(); + await recorder.stop(); }); it("update message with 64KB characters including special char which is computed after encoding", async () => { diff --git a/sdk/storage/storage-queue/test/node/messagesclient.spec.ts b/sdk/storage/storage-queue/test/node/messagesclient.spec.ts index 900ac0cbb4b6..1fa47d9b4f15 100644 --- a/sdk/storage/storage-queue/test/node/messagesclient.spec.ts +++ b/sdk/storage/storage-queue/test/node/messagesclient.spec.ts @@ -25,7 +25,7 @@ describe("QueueClient message methods, Node.js only", () => { afterEach(async function() { await queueClient.delete(); - recorder.stop(); + await recorder.stop(); }); it("enqueue, peek, dequeue with 64KB characters including special char which is computed after encoding", async () => { diff --git a/sdk/storage/storage-queue/test/node/queueclient.spec.ts b/sdk/storage/storage-queue/test/node/queueclient.spec.ts index ddb22bec4067..8b6f7b69cb2c 100644 --- a/sdk/storage/storage-queue/test/node/queueclient.spec.ts +++ b/sdk/storage/storage-queue/test/node/queueclient.spec.ts @@ -22,7 +22,7 @@ describe("QueueClient Node.js only", () => { afterEach(async function() { await queueClient.delete(); - recorder.stop(); + await recorder.stop(); }); it("getAccessPolicy", async () => { diff --git a/sdk/storage/storage-queue/test/node/queueserviceclient.spec.ts b/sdk/storage/storage-queue/test/node/queueserviceclient.spec.ts index 0bb288169a75..0cfd8011fd38 100644 --- a/sdk/storage/storage-queue/test/node/queueserviceclient.spec.ts +++ b/sdk/storage/storage-queue/test/node/queueserviceclient.spec.ts @@ -15,8 +15,8 @@ describe("QueueServiceClient Node.js only", () => { recorder = record(this, recorderEnvSetup); }); - afterEach(function() { - recorder.stop(); + afterEach(async function() { + await recorder.stop(); }); it("can be created with a url and a credential", async () => { diff --git a/sdk/storage/storage-queue/test/node/sas.spec.ts b/sdk/storage/storage-queue/test/node/sas.spec.ts index 555e56e2b453..0e24b4877d49 100644 --- a/sdk/storage/storage-queue/test/node/sas.spec.ts +++ b/sdk/storage/storage-queue/test/node/sas.spec.ts @@ -27,8 +27,8 @@ describe("Shared Access Signature (SAS) generation Node.js only", () => { queueServiceClient = getQSU(); }); - afterEach(function() { - recorder.stop(); + afterEach(async function() { + await recorder.stop(); }); it("generateAccountSASQueryParameters should work", async () => { diff --git a/sdk/storage/storage-queue/test/node/utils.spec.ts b/sdk/storage/storage-queue/test/node/utils.spec.ts index d9ec11870445..2eb2d06a468d 100644 --- a/sdk/storage/storage-queue/test/node/utils.spec.ts +++ b/sdk/storage/storage-queue/test/node/utils.spec.ts @@ -37,7 +37,7 @@ describe("Utility Helpers Node.js only", () => { }); afterEach(async function() { - recorder.stop(); + await recorder.stop(); }); it("extractConnectionStringParts throws error when passed an invalid protocol in the connection string", async () => { diff --git a/sdk/storage/storage-queue/test/queueclient.spec.ts b/sdk/storage/storage-queue/test/queueclient.spec.ts index 0d1d850cbfdd..bb38005fbde2 100644 --- a/sdk/storage/storage-queue/test/queueclient.spec.ts +++ b/sdk/storage/storage-queue/test/queueclient.spec.ts @@ -25,7 +25,7 @@ describe("QueueClient", () => { afterEach(async function() { await queueClient.delete(); - recorder.stop(); + await recorder.stop(); }); it("setMetadata", async () => { diff --git a/sdk/storage/storage-queue/test/queueclientmessages.spec.ts b/sdk/storage/storage-queue/test/queueclientmessages.spec.ts index 85b0028bfcff..2c71e88c0584 100644 --- a/sdk/storage/storage-queue/test/queueclientmessages.spec.ts +++ b/sdk/storage/storage-queue/test/queueclientmessages.spec.ts @@ -24,7 +24,7 @@ describe("QueueClient message methods", () => { afterEach(async function() { await queueClient.delete(); - recorder.stop(); + await recorder.stop(); }); it("enqueue, peek, dequeue and clear message with default parameters", async () => { diff --git a/sdk/storage/storage-queue/test/queueserviceclient.spec.ts b/sdk/storage/storage-queue/test/queueserviceclient.spec.ts index dee58fb1d5f1..ba31da668c21 100644 --- a/sdk/storage/storage-queue/test/queueserviceclient.spec.ts +++ b/sdk/storage/storage-queue/test/queueserviceclient.spec.ts @@ -13,8 +13,8 @@ describe("QueueServiceClient", () => { recorder = record(this, recorderEnvSetup); }); - afterEach(function() { - recorder.stop(); + afterEach(async function() { + await recorder.stop(); }); it("listQueues with default parameters", async () => { diff --git a/sdk/storage/storage-queue/test/retrypolicy.spec.ts b/sdk/storage/storage-queue/test/retrypolicy.spec.ts index 1223a0d884b8..be5dcc393b5b 100644 --- a/sdk/storage/storage-queue/test/retrypolicy.spec.ts +++ b/sdk/storage/storage-queue/test/retrypolicy.spec.ts @@ -28,7 +28,7 @@ describe("RetryPolicy", () => { afterEach(async function() { await queueClient.delete(); - recorder.stop(); + await recorder.stop(); }); it("Retry policy should work when first request fails with 500", async () => { diff --git a/sdk/storage/storage-queue/test/utils.spec.ts b/sdk/storage/storage-queue/test/utils.spec.ts index 936ed12d702a..5dcb58f94a60 100644 --- a/sdk/storage/storage-queue/test/utils.spec.ts +++ b/sdk/storage/storage-queue/test/utils.spec.ts @@ -37,7 +37,7 @@ describe("Utility Helpers", () => { }); afterEach(async function() { - recorder.stop(); + await recorder.stop(); }); it("sanitizeURL redacts SAS token", () => { diff --git a/sdk/test-utils/recorder/CHANGELOG.md b/sdk/test-utils/recorder/CHANGELOG.md index 37d2ec16a306..ce326fb5327c 100644 --- a/sdk/test-utils/recorder/CHANGELOG.md +++ b/sdk/test-utils/recorder/CHANGELOG.md @@ -2,6 +2,10 @@ ## 1.0.0 (Unreleased) +## 2020-07-10 + +- [Bug Fix] Fixed an issue where the browser-recording file is saved before all the recorded requests are pushed to the array of recordings(request-response pairs). + ## 2020-04-30 - Since Mocha 7.0.0, Mocha behaves as follows: "When conditionally skipping in the `it` test, related afterEach hooks are now executed" diff --git a/sdk/test-utils/recorder/src/baseRecorder.ts b/sdk/test-utils/recorder/src/baseRecorder.ts index ab046ade0ee7..96ca3bb6eb32 100644 --- a/sdk/test-utils/recorder/src/baseRecorder.ts +++ b/sdk/test-utils/recorder/src/baseRecorder.ts @@ -107,7 +107,7 @@ export abstract class BaseRecorder { * @memberof BaseRecorder */ public abstract playback(environmentSetup: RecorderEnvironmentSetup, filePath: string): void; - public abstract stop(): void; + public abstract async stop(): Promise; } export class NockRecorder extends BaseRecorder { @@ -139,7 +139,7 @@ export class NockRecorder extends BaseRecorder { ).testInfo; } - public stop(): void { + public async stop(): Promise { if (isRecordMode()) { // Importing "nock" library in the recording and appending the testInfo part in the recording const importNockStatement = @@ -215,6 +215,7 @@ export class NockRecorder extends BaseRecorder { // This class overrides requests' 'open', 'send' and 'onreadystatechange' functions, adding our own code to them to deal with requests export class NiseRecorder extends BaseRecorder { private recordings: any[] = []; + private recordingInFlight: Promise[] = []; private xhr: nise.FakeXMLHttpRequestStatic | undefined; constructor(hash: string, testSuiteTitle: string, testTitle: string) { @@ -317,7 +318,7 @@ export class NiseRecorder extends BaseRecorder { // More info on readyState - https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/readyState if (req.readyState === 4) { // Record the request once the response is obtained - self.recordRequest(req, data); + self.recordingInFlight.push(self.recordRequest(req, data)); } // Sometimes the client doesn't implement an 'onreadystatechange' function, so we need to make sure it exists before calling the original implementation if (reqStateChange) { @@ -403,8 +404,9 @@ export class NiseRecorder extends BaseRecorder { }; } - public stop(): void { + public async stop(): Promise { if (isRecordMode()) { + await Promise.all(this.recordingInFlight); // recordings at this point are in the JSON format. this.recordings = this.filterSecrets(this.recordings); diff --git a/sdk/test-utils/recorder/src/customConsoleLog.ts b/sdk/test-utils/recorder/src/customConsoleLog.ts index 4c98835dde44..002510f6a7f1 100644 --- a/sdk/test-utils/recorder/src/customConsoleLog.ts +++ b/sdk/test-utils/recorder/src/customConsoleLog.ts @@ -1,6 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. See License.txt in the project root for license information. +import { isBrowser } from "./utils"; + // Converting content corresponding to all the console statements // into (JSON.stringify)-ed content in record mode for browser tests. // @@ -24,12 +26,21 @@ // - Example - console.warn("hello"); -> console.log({ warn: "hello" }); // - Example - console.log("hello"); -> console.log({ log: "hello" }); +export let consoleLog: (msg: any, ...args: any[]) => void; + +if (isBrowser()) { + consoleLog = window.console.log; +} + +export function setConsoleLogForTesting(func: (msg: any, ...args: any[]) => void) { + consoleLog = func; +} + /** * Converts content corresponding to all the console statements into (JSON.stringify)-ed content in record mode for browser tests. * This allows filtering certain console.logs to generate the recordings for browser tests. */ export function customConsoleLog() { - const consoleLog = window.console.log; for (const method in window.console) { if ( window.console.hasOwnProperty(method) && diff --git a/sdk/test-utils/recorder/src/recorder.ts b/sdk/test-utils/recorder/src/recorder.ts index 6e8356b8015a..b516df838f21 100644 --- a/sdk/test-utils/recorder/src/recorder.ts +++ b/sdk/test-utils/recorder/src/recorder.ts @@ -30,7 +30,7 @@ export interface Recorder { * `stop()` method is supposed to be called at the end of the test, stops and saves the recording in the "record" mode. * Has no effect in the playback/live test modes. */ - stop(): void; + stop(): Promise; /** * `{recorder.skip("node")}` and `{recorder.skip("browser")}` will skip the test in node.js and browser runtimes respectively. * If the `{runtime}` is `{undefined}`, the test will be skipped in both the node and browser runtimes. @@ -160,10 +160,10 @@ export function record( // If TEST_MODE=live, hits the live-service and no recordings are generated. return { - stop: function() { + stop: async function() { // We check wether we're on record or playback inside of the recorder's stop method. if (recorder) { - recorder.stop(); + await recorder.stop(); } }, /** diff --git a/sdk/test-utils/recorder/test/browser/recorder.spec.ts b/sdk/test-utils/recorder/test/browser/recorder.spec.ts index 2ef73b2ed6ca..6318c5d7153b 100644 --- a/sdk/test-utils/recorder/test/browser/recorder.spec.ts +++ b/sdk/test-utils/recorder/test/browser/recorder.spec.ts @@ -3,6 +3,7 @@ import { record, TestContextInterface, TestContext, TestContextTest } from "../. import xhrMock from "xhr-mock"; import MD5 from "md5"; import chai from "chai"; +import { consoleLog, setConsoleLogForTesting } from "../../src/customConsoleLog"; const { expect } = chai; const expectedHttpResponse = "Hello World!"; @@ -69,11 +70,17 @@ describe("The recorder's public API, on a browser", () => { // The recorder outputs files into the console, // so we need to mock the console.log function to capture and test the recorder output. - const originalConsoleLog = console.log; + const originalConsoleLog = consoleLog; const savedConsoleLogParams: any[] = []; - console.log = (...params: any[]) => { - savedConsoleLogParams.push(params); - }; + setConsoleLogForTesting((...params: any[]) => { + if (params && params.length > 0) { + try { + if (JSON.parse(params[0]).writeFile) { + savedConsoleLogParams.push(params); + } + } catch (err) {} + } + }); // The recorder should start in the beforeEach call. // We have to do this to emulate that. @@ -96,8 +103,8 @@ describe("The recorder's public API, on a browser", () => { // Cleaning everything before we continue verifying the results. xhrMock.teardown(); - recorder.stop(); - console.log = originalConsoleLog; + await recorder.stop(); + setConsoleLogForTesting(originalConsoleLog); // Here we confirm that the recorder generated an expected output on the console.logs. // This output is used to generate the recording files in the filesystem, though here we're only @@ -163,7 +170,7 @@ describe("The recorder's public API, on a browser", () => { // The playback code served the appropriate response based on the recordings. expect(response).to.equal(expectedHttpResponse); - recorder.stop(); + await recorder.stop(); }); it("soft-record should re-record a simple outdated test", async function() { @@ -203,12 +210,18 @@ describe("The recorder's public API, on a browser", () => { const originalXHR = XMLHttpRequest; // The recorder outputs files into the console, - // so we need to mock the console.log function to capture and test the recorder output. - const originalConsoleLog = console.log; + // so we need to override the consoleLog function to capture and test the recorder output. + const originalConsoleLog = consoleLog; const savedConsoleLogParams: any[] = []; - console.log = (...params: any) => { - savedConsoleLogParams.push(params); - }; + setConsoleLogForTesting((...params: any[]) => { + if (params && params.length > 0) { + try { + if (JSON.parse(params[0]).writeFile) { + savedConsoleLogParams.push(params); + } + } catch (err) {} + } + }); // The recorder should start in the beforeEach call. // To emulate that behavior while keeping the test code as contained as possible, @@ -233,8 +246,8 @@ describe("The recorder's public API, on a browser", () => { // Cleaning everything before we continue verifying the results. xhrMock.teardown(); - recorder.stop(); - console.log = originalConsoleLog; + await recorder.stop(); + setConsoleLogForTesting(originalConsoleLog); // Now we check the hash has changed in the recorded console.log output. diff --git a/sdk/test-utils/recorder/test/node/recorder.spec.ts b/sdk/test-utils/recorder/test/node/recorder.spec.ts index e2325bc0fe31..05eca57d189c 100644 --- a/sdk/test-utils/recorder/test/node/recorder.spec.ts +++ b/sdk/test-utils/recorder/test/node/recorder.spec.ts @@ -102,7 +102,7 @@ describe("The recorder's public API, on NodeJS", () => { // Cleaning everything before we continue verifying the results. server.close(); - recorder.stop(); + await recorder.stop(); // The recorder takes some time to finish writing the output file. // It's not a second, but we're being pessimists. @@ -148,7 +148,7 @@ describe("The recorder's public API, on NodeJS", () => { // The playback code served the appropriate response based on the recordings. expect(response).to.equal(expectedHttpResponse); - recorder.stop(); + await recorder.stop(); }); it("soft-record should re-record a simple outdated test", async function() { @@ -193,7 +193,7 @@ describe("The recorder's public API, on NodeJS", () => { // Cleaning everything before we continue verifying the results. server.close(); - recorder.stop(); + await recorder.stop(); // The recorder takes some time to finish writing the output file. // It's not a second, but we're being pessimists. diff --git a/sdk/textanalytics/ai-text-analytics/package.json b/sdk/textanalytics/ai-text-analytics/package.json index c096d2bed7d0..77b2494a99dd 100644 --- a/sdk/textanalytics/ai-text-analytics/package.json +++ b/sdk/textanalytics/ai-text-analytics/package.json @@ -46,14 +46,12 @@ "audit": "node ../../../common/scripts/rush-audit.js && rimraf node_modules package-lock.json && npm i --package-lock-only 2>&1 && npm audit", "build:browser": "tsc -p . && cross-env ONLY_BROWSER=true rollup -c 2>&1", "build:node": "tsc -p . && cross-env ONLY_NODE=true rollup -c 2>&1", - "build:samples": "node ../../../common/scripts/prep-samples.js && cd samples && tsc -p .", + "build:samples": "dev-tool samples prep && cd dist-samples && tsc -p .", "build:test": "tsc -p . && rollup -c rollup.test.config.js 2>&1", "build": "tsc -p . && rollup -c 2>&1 && api-extractor run --local", "check-format": "prettier --list-different --config ../../.prettierrc.json --ignore-path ../../.prettierignore \"src/**/*.ts\" \"test/**/*.ts\" \"*.{js,json}\"", "clean": "rimraf dist dist-browser dist-esm test-dist temp types *.tgz *.log", - "execute:js-samples": "node ../../../common/scripts/run-samples.js samples/javascript/", - "execute:ts-samples": "node ../../../common/scripts/run-samples.js samples/typescript/dist/samples/typescript/src/", - "execute:samples": "npm run build:samples && npm run execute:js-samples && npm run execute:ts-samples", + "execute:samples": "npm run build:samples && dev-tool samples run dist-samples/javascript dist-samples/typescript/dist/dist-samples/typescript/src/", "extract-api": "tsc -p . && api-extractor run --local", "format": "prettier --write --config ../../.prettierrc.json --ignore-path ../../.prettierignore \"src/**/*.ts\" \"test/**/*.ts\" \"*.{js,json}\"", "integration-test:browser": "karma start --single-run", @@ -81,6 +79,7 @@ "tslib": "^2.0.0" }, "devDependencies": { + "@azure/dev-tool": "^1.0.0", "@azure/eslint-plugin-azure-sdk": "^3.0.0", "@azure/identity": "^1.1.0-preview", "@azure/test-utils-recorder": "^1.0.0", diff --git a/sdk/textanalytics/ai-text-analytics/samples/javascript/alternativeDocumentInput.js b/sdk/textanalytics/ai-text-analytics/samples/javascript/alternativeDocumentInput.js index faaede25a520..394dd7694d61 100644 --- a/sdk/textanalytics/ai-text-analytics/samples/javascript/alternativeDocumentInput.js +++ b/sdk/textanalytics/ai-text-analytics/samples/javascript/alternativeDocumentInput.js @@ -17,9 +17,11 @@ const endpoint = process.env["ENDPOINT"] || ""; const apiKey = process.env["TEXT_ANALYTICS_API_KEY"] || ""; /** - * Inputs for the `detectLanguage` method have an `id`, the document `text, and an optional - * `countryHint` (an ISO 3166 two-letter country code). The `id` field is required and must - * be unique for each document in a given request. + * DetectLanguageInput objects allow for specification of country hints on a + * document-by-document basis. + * + * When using DetectLanguageInput, the `id` field is required and must be unique + * for each document in a given request. */ const detectLanguageInputs = [ { id: "0", countryHint: "us", text: "I had the best day of my life." }, @@ -28,13 +30,16 @@ const detectLanguageInputs = [ { id: "3", countryHint: "fr", - text: "L'hôtel n'était pas très confortable. L'éclairage était trop sombre.", - }, + text: "L'hôtel n'était pas très confortable. L'éclairage était trop sombre." + } ]; /** - * Inputs for all other methods are similar to the input for `detectLanguage`, but have an - * optional `language` field (a ISO 639-1 two-letter language code) and no `countryHint` field. + * TextDocumentInput objects are used by all methods except for `detectLanguage`. + * They allow for specification of input language on a document-by-document basis. + * + * Like `DetectLanguageInput`, the `id` field is required and must be unique for + * each document in the request. */ const textDocumentInputs = [ { id: "0", language: "en", text: "I had the best day of my life." }, @@ -43,8 +48,8 @@ const textDocumentInputs = [ { id: "3", language: "fr", - text: "L'hôtel n'était pas très confortable. L'éclairage était trop sombre.", - }, + text: "L'hôtel n'était pas très confortable. L'éclairage était trop sombre." + } ]; async function main() { diff --git a/sdk/textanalytics/ai-text-analytics/samples/javascript/analyzeSentiment.js b/sdk/textanalytics/ai-text-analytics/samples/javascript/analyzeSentiment.js index f2ff3169d317..aca300ecbbe8 100644 --- a/sdk/textanalytics/ai-text-analytics/samples/javascript/analyzeSentiment.js +++ b/sdk/textanalytics/ai-text-analytics/samples/javascript/analyzeSentiment.js @@ -18,7 +18,7 @@ const apiKey = process.env["TEXT_ANALYTICS_API_KEY"] || ""; const documents = [ "I had the best day of my life.", - "This was a waste of my time. The speaker put me to sleep.", + "This was a waste of my time. The speaker put me to sleep." ]; async function main() { diff --git a/sdk/textanalytics/ai-text-analytics/samples/javascript/detectLanguage.js b/sdk/textanalytics/ai-text-analytics/samples/javascript/detectLanguage.js index 3aaa10383c8e..248058b1dd02 100644 --- a/sdk/textanalytics/ai-text-analytics/samples/javascript/detectLanguage.js +++ b/sdk/textanalytics/ai-text-analytics/samples/javascript/detectLanguage.js @@ -20,7 +20,7 @@ const documents = [ "Este es un document escrito en Español.", "这是一个用中文写的文件", "Dies ist ein Dokument in deutsche Sprache.", - "Detta är ett dokument skrivet på engelska.", + "Detta är ett dokument skrivet på engelska." ]; async function main() { diff --git a/sdk/textanalytics/ai-text-analytics/samples/javascript/extractKeyPhrases.js b/sdk/textanalytics/ai-text-analytics/samples/javascript/extractKeyPhrases.js index 8f6ea63fe6dc..af4349271527 100644 --- a/sdk/textanalytics/ai-text-analytics/samples/javascript/extractKeyPhrases.js +++ b/sdk/textanalytics/ai-text-analytics/samples/javascript/extractKeyPhrases.js @@ -18,7 +18,7 @@ const apiKey = process.env["TEXT_ANALYTICS_API_KEY"] || ""; const documents = [ "Redmond is a city in King County, Washington, United States, located 15 miles east of Seattle.", "I need to take my cat to the veterinarian.", - "I will travel to South America in the summer.", + "I will travel to South America in the summer." ]; async function main() { diff --git a/sdk/textanalytics/ai-text-analytics/samples/javascript/recognizeEntities.js b/sdk/textanalytics/ai-text-analytics/samples/javascript/recognizeEntities.js index 432a9c53b3b3..dde4a0dd059b 100644 --- a/sdk/textanalytics/ai-text-analytics/samples/javascript/recognizeEntities.js +++ b/sdk/textanalytics/ai-text-analytics/samples/javascript/recognizeEntities.js @@ -18,7 +18,7 @@ const apiKey = process.env["TEXT_ANALYTICS_API_KEY"] || ""; const documents = [ "Microsoft was founded by Bill Gates and Paul Allen.", "I had a wonderful trip to Seattle last week.", - "I visited the Space Needle 2 times.", + "I visited the Space Needle 2 times." ]; async function main() { diff --git a/sdk/textanalytics/ai-text-analytics/test/apiKey.spec.ts b/sdk/textanalytics/ai-text-analytics/test/apiKey.spec.ts index 9792074ee0d4..1a19a0771324 100644 --- a/sdk/textanalytics/ai-text-analytics/test/apiKey.spec.ts +++ b/sdk/textanalytics/ai-text-analytics/test/apiKey.spec.ts @@ -30,8 +30,8 @@ describe("[API Key] TextAnalyticsClient", function() { ({ client, recorder } = createRecordedClient(this, apiKey)); }); - afterEach(() => { - recorder.stop(); + afterEach(async function() { + await recorder.stop(); }); it("#analyzeSentiment", async () => { diff --git a/sdk/textanalytics/ai-text-analytics/test/textAnalyticsClient.spec.ts b/sdk/textanalytics/ai-text-analytics/test/textAnalyticsClient.spec.ts index a1bc720ffb0a..331b898de49c 100644 --- a/sdk/textanalytics/ai-text-analytics/test/textAnalyticsClient.spec.ts +++ b/sdk/textanalytics/ai-text-analytics/test/textAnalyticsClient.spec.ts @@ -43,8 +43,8 @@ describe("[AAD] TextAnalyticsClient", function() { }; }); - afterEach(() => { - recorder.stop(); + afterEach(async function() { + await recorder.stop(); }); describe("#analyzeSentiment", () => {