diff --git a/sdk/core/core-amqp/CHANGELOG.md b/sdk/core/core-amqp/CHANGELOG.md index 7fb0fc21abc4..3adc9cd918d3 100644 --- a/sdk/core/core-amqp/CHANGELOG.md +++ b/sdk/core/core-amqp/CHANGELOG.md @@ -4,6 +4,12 @@ - Improved detection of when an established socket is no longer receiving data from the service. - Added logging around the network connectivity check. +- Updated the translate() utility function used to convert AmqpError or system errors to MessagingError as below: + - Non-messaging errors like TypeError, RangeError or any Node.js system errors not related to network issues + are returned as is instead of being converted to a MessagingError. + - If a MessagingError is returned by translate(), use code instead of the name property to + differentiate between different kinds of messaging errors. + The name property henceforth will always be "MessagingError" on this error class. ## 1.0.0-preview.6 (2019-12-03) diff --git a/sdk/core/core-amqp/src/errors.ts b/sdk/core/core-amqp/src/errors.ts index 39bc51e48be1..25eddfcb6156 100644 --- a/sdk/core/core-amqp/src/errors.ts +++ b/sdk/core/core-amqp/src/errors.ts @@ -1,8 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -import { AmqpResponseStatusCode, isAmqpError, AmqpError } from "rhea-promise"; -import { isNode } from "../src/util/utils"; +import { AmqpResponseStatusCode, isAmqpError as rheaIsAmqpError, AmqpError } from "rhea-promise"; +import { isNode, isString, isNumber } from "../src/util/utils"; /** * Maps the conditions to the numeric AMQP Response status codes. @@ -435,6 +435,33 @@ export enum ErrorNameConditionMapper { SystemError = "system:error" } +/** + * Describes the fields on a Node.js SystemError. + * Omits fields that are not related to network calls (e.g. file system calls). + * See https://nodejs.org/dist/latest-v12.x/docs/api/errors.html#errors_class_systemerror + */ +interface NetworkSystemError { + address?: string; + code: string; + errno: string | number; + info?: any; + message: string; + name: string; + port?: number; + stack: string; + syscall: string; +} + +const systemErrorFieldsToCopy: (keyof Omit)[] = [ + "address", + "code", + "errno", + "info", + "port", + "stack", + "syscall" +]; + /** * Describes the base class for Messaging Error. * @class {MessagingError} @@ -442,31 +469,60 @@ export enum ErrorNameConditionMapper { */ export class MessagingError extends Error { /** - * @property {string} [condition] The error condition. + * Address to which the network connection failed. + * Only present if the `MessagingError` was instantiated with a Node.js `SystemError`. */ - condition?: string; + address?: string; + /** + * A string label that identifies the error. + */ + code?: string; + /** + * System-provided error number. + * Only present if the `MessagingError` was instantiated with a Node.js `SystemError`. + */ + errno?: number | string; /** * @property {string} name The error name. Default value: "MessagingError". */ name: string = "MessagingError"; /** - * @property {boolean} translated Has the error been translated. Default: true. + * The unavailable network connection port. + * Only present if the `MessagingError` was instantiated with a Node.js `SystemError`. */ - translated: boolean = true; + port?: number; + /** + * Name of the system call that triggered the error. + * Only present if the `MessagingError` was instantiated with a Node.js `SystemError`. + */ + syscall?: string; /** * * @property {boolean} retryable Describes whether the error is retryable. Default: true. */ retryable: boolean = true; /** - * @property {any} [info] Any additional error information given by the service. + * @property {any} [info] Extra details about the error. */ info?: any; /** * @param {string} message The error message that provides more information about the error. + * @param originalError An error whose properties will be copied to the MessagingError if the + * property matches one found on the Node.js `SystemError`. */ - constructor(message: string) { + constructor(message: string, originalError?: Error) { super(message); + + if (!originalError) { + return; + } + + // copy properties from system error + for (const propName of systemErrorFieldsToCopy) { + if ((originalError as NetworkSystemError)[propName] != undefined) { + this[propName] = (originalError as NetworkSystemError)[propName]; + } + } } } @@ -514,17 +570,24 @@ export enum SystemErrorConditionMapper { ENONET = "com.microsoft:timeout" } -export function isSystemError(err: any): boolean { - let result: boolean = false; - if ( - err.code && - typeof err.code === "string" && - (err.syscall && typeof err.syscall === "string") && - (err.errno && (typeof err.errno === "string" || typeof err.errno === "number")) - ) { - result = true; +/** + * Checks whether the provided error is a node.js SystemError. + * @param err An object that may contain error information. + */ +export function isSystemError(err: any): err is NetworkSystemError { + if (!err) { + return false; } - return result; + + if (!isString(err.code) || !isString(err.syscall)) { + return false; + } + + if (!isString(err.errno) && !isNumber(err.errno)) { + return false; + } + + return true; } /** @@ -547,65 +610,73 @@ function isBrowserWebsocketError(err: any): boolean { return result; } +const rheaPromiseErrors = [ + // OperationTimeoutError occurs when the service fails to respond within a given timeframe. + "OperationTimeoutError", + + // InsufficientCreditError occurs when the number of credits available on Rhea link is insufficient. + "InsufficientCreditError", + + // Defines the error that occurs when the Sender fails to send a message. + "SendOperationFailedError" +]; + /** - * Translates the AQMP error received at the protocol layer or a generic Error into a MessagingError. + * Translates the AQMP error received at the protocol layer or a SystemError into a MessagingError. + * All other errors are returned unaltered. * * @param {AmqpError} err The amqp error that was received. * @returns {MessagingError} MessagingError object. */ -export function translate(err: AmqpError | Error): MessagingError { - if ((err as MessagingError).translated) { - // already translated - return err as MessagingError; - } - - let error: MessagingError = err as MessagingError; - +export function translate(err: AmqpError | Error): MessagingError | Error { // Built-in errors like TypeError and RangeError should not be retryable as these indicate issues // with user input and not an issue with the Messaging process. if (err instanceof TypeError || err instanceof RangeError) { - error.retryable = false; - return error; + return err; } if (isAmqpError(err)) { // translate - const condition = (err as AmqpError).condition; - const description = (err as AmqpError).description as string; - error = new MessagingError(description); + const condition = err.condition; + const description = err.description!; + const error = new MessagingError(description); if ((err as any).stack) error.stack = (err as any).stack; - error.info = (err as AmqpError).info; - error.condition = condition; + error.info = err.info; if (condition) { - error.name = ConditionErrorNameMapper[condition as keyof typeof ConditionErrorNameMapper]; + error.code = ConditionErrorNameMapper[condition as keyof typeof ConditionErrorNameMapper]; } - if (!error.name) error.name = "MessagingError"; if ( description && (description.includes("status-code: 404") || description.match(/The messaging entity .* could not be found.*/i) !== null) ) { - error.name = "MessagingEntityNotFoundError"; + error.code = "MessagingEntityNotFoundError"; } - if (retryableErrors.indexOf(error.name) === -1) { + if (error.code && retryableErrors.indexOf(error.code) === -1) { // not found error.retryable = false; } return error; } + if (err.name === "MessagingError") { + // already translated + return err; + } + if (isSystemError(err)) { // translate - const condition = (err as any).code; - const description = (err as Error).message; - error = new MessagingError(description); - if ((err as any).stack) error.stack = (err as any).stack; + const condition = err.code; + const description = err.message; + const error = new MessagingError(description, err); + let errorType = "SystemError"; if (condition) { - const amqpErrorCondition = SystemErrorConditionMapper[condition as keyof typeof SystemErrorConditionMapper]; - error.name = ConditionErrorNameMapper[amqpErrorCondition as keyof typeof ConditionErrorNameMapper]; + const amqpErrorCondition = + SystemErrorConditionMapper[condition as keyof typeof SystemErrorConditionMapper]; + errorType = + ConditionErrorNameMapper[amqpErrorCondition as keyof typeof ConditionErrorNameMapper]; } - if (!error.name) error.name = "SystemError"; - if (retryableErrors.indexOf(error.name) === -1) { + if (retryableErrors.indexOf(errorType) === -1) { // not found error.retryable = false; } @@ -614,27 +685,27 @@ export function translate(err: AmqpError | Error): MessagingError { if (isBrowserWebsocketError(err)) { // Translate browser communication errors during opening handshake to generic SeviceCommunicationError - error = new MessagingError("Websocket connection failed."); - error.name = ConditionErrorNameMapper[ErrorNameConditionMapper.ServiceCommunicationError]; + const error = new MessagingError("Websocket connection failed."); + error.code = ConditionErrorNameMapper[ErrorNameConditionMapper.ServiceCommunicationError]; error.retryable = false; return error; } - // instanceof checks on custom Errors doesn't work without manually setting the prototype within the error. - // Must do a name check until the custom error is updated, and that doesn't break compatibility - // https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work - const errorName = (err as Error).name; - if (retryableErrors.indexOf(errorName) > -1) { - error.retryable = true; - return error; - } - if (errorName === "AbortError") { - error.retryable = false; + // Some errors come from rhea-promise and need to be converted to MessagingError. + // A subset of these are also retryable. + if (rheaPromiseErrors.indexOf(err.name) !== -1) { + const error = new MessagingError(err.message, err); + error.code = err.name; + if (error.code && retryableErrors.indexOf(error.code) === -1) { + // not found + error.retryable = false; + } return error; } - // Translate a generic error into MessagingError. - error = new MessagingError((err as Error).message); - error.stack = (err as Error).stack; - return error; + return err; +} + +function isAmqpError(error: any): error is AmqpError { + return rheaIsAmqpError(error); } diff --git a/sdk/core/core-amqp/src/util/utils.ts b/sdk/core/core-amqp/src/util/utils.ts index 736cd82decd1..4fbddf39655b 100644 --- a/sdk/core/core-amqp/src/util/utils.ts +++ b/sdk/core/core-amqp/src/util/utils.ts @@ -298,3 +298,19 @@ export function isIotHubConnectionString(connectionString: string): boolean { } return result; } + +/** + * @ignore + * @internal + */ +export function isString(s: any): s is string { + return typeof s === "string"; +} + +/** + * @ignore + * @internal + */ +export function isNumber(n: any): n is number { + return typeof n === "number"; +} diff --git a/sdk/core/core-amqp/test/errors.spec.ts b/sdk/core/core-amqp/test/errors.spec.ts index 1a68af024d40..36393e54a4ca 100644 --- a/sdk/core/core-amqp/test/errors.spec.ts +++ b/sdk/core/core-amqp/test/errors.spec.ts @@ -20,22 +20,30 @@ class AMQPError { describe("Errors", function() { describe("translate", function() { - it("Converts to MessagingError, and acts as a passthrough if the input is not an AmqpProtocolError", function() { - const MyError: any = function() {}; - const err: any = new MyError(); - const msg: any = undefined; - const ehError = new Errors.MessagingError(msg); - const translatedError = Errors.translate(err); - translatedError.name.should.equal(ehError.name); - translatedError.retryable.should.equal(ehError.retryable); - translatedError.message.should.equal(ehError.message); + it("Does not touch errors that are neither AmqpError nor SystemError", function() { + const testError = new Error("Test error"); + const translatedError = Errors.translate(testError); + translatedError.should.deep.equal(testError); + }); + + it("Does not touch TypeError", function() { + const testError = new TypeError("This is a wrong type!!"); + const translatedError = Errors.translate(testError); + translatedError.should.deep.equal(testError); + }); + + it("Does not touch RangeError", function() { + const testError = new RangeError("Out of range!!"); + const translatedError = Errors.translate(testError); + translatedError.should.deep.equal(testError); }); it("Sets retryable to true, if input is custom error and name is OperationTimeoutError", function() { const err = new Error("error message"); err.name = "OperationTimeoutError"; - const translatedError = Errors.translate(err); - should.equal(translatedError.name === "OperationTimeoutError", true); + const translatedError = Errors.translate(err) as Errors.MessagingError; + should.equal(translatedError.name === "MessagingError", true); + should.equal(translatedError.code === "OperationTimeoutError", true); translatedError.message.should.equal(err.message); translatedError.stack!.should.equal(err.stack); translatedError.retryable.should.equal(true); @@ -44,38 +52,32 @@ describe("Errors", function() { it("Sets retryable to true, if input is custom error and name is InsufficientCreditError", function() { const err = new Error("error message"); err.name = "InsufficientCreditError"; - const translatedError = Errors.translate(err); - should.equal(translatedError.name === "InsufficientCreditError", true); + const translatedError = Errors.translate(err) as Errors.MessagingError; + should.equal(translatedError.name === "MessagingError", true); + should.equal(translatedError.code === "InsufficientCreditError", true); translatedError.message.should.equal(err.message); translatedError.stack!.should.equal(err.stack); translatedError.retryable.should.equal(true); }); - it("Sets retryable to false, if input is the custom AbortError", function() { - const err = new AbortError("error message"); - const translatedError = Errors.translate(err); - should.equal(translatedError.name === "AbortError", true); - translatedError.message.should.equal(err.message); - translatedError.stack!.should.equal(err.stack); - translatedError.retryable.should.equal(false); - }); - - it("Sets retryable to false, and acts as a passthrough if the input is TypeError", function() { - const err = new TypeError("This is a wrong type!!"); - const translatedError = Errors.translate(err); - should.equal(translatedError instanceof TypeError, true); + it("Does not sets retryable to true, if input is custom error and name is SendOperationFailedError", function() { + const err = new Error("error message"); + err.name = "SendOperationFailedError"; + const translatedError = Errors.translate(err) as Errors.MessagingError; + should.equal(translatedError.name === "MessagingError", true); + should.equal(translatedError.code === "SendOperationFailedError", true); translatedError.message.should.equal(err.message); translatedError.stack!.should.equal(err.stack); translatedError.retryable.should.equal(false); }); - it("Sets retryable to false, and acts as a passthrough if the input is RangeError", function() { - const err = new RangeError("Out of range!!"); + it("Does not set retryable, if input is the custom AbortError", function() { + const err = new AbortError("error message"); const translatedError = Errors.translate(err); - should.equal(translatedError instanceof RangeError, true); + should.equal(translatedError.name === "AbortError", true); translatedError.message.should.equal(err.message); translatedError.stack!.should.equal(err.stack); - translatedError.retryable.should.equal(false); + should.equal((translatedError as Errors.MessagingError).retryable, undefined); }); [ @@ -94,15 +96,20 @@ describe("Errors", function() { to: "ArgumentOutOfRangeError", message: "some message" }, - { from: "", to: "MessagingError" } + { from: "", to: "MessagingError", message: "some message" } ].forEach(function(mapping) { it("translates " + mapping.from + " into " + mapping.to, function() { - const err: any = new AMQPError(mapping.from as any, mapping.message as any); + const err: any = new AMQPError(mapping.from, mapping.message); const translatedError = Errors.translate(err); - translatedError.name.should.equal(mapping.to); + // won't have a code since it has no matching condition + if (translatedError.code) { + translatedError.code.should.equal(mapping.to); + } + translatedError.name.should.equal("MessagingError"); if ( - translatedError.name === "ServerBusyError" || - translatedError.name === "MessagingError" + translatedError.code === "ServerBusyError" || + translatedError.code === "MessagingError" || + translatedError.code == undefined ) { translatedError.retryable.should.equal(true); } else { @@ -147,20 +154,11 @@ describe("Errors", function() { "SystemError from node.js with code: '" + mapping.code + "' to a MessagingError", function() { const translatedError = Errors.translate(mapping as any); - if (mapping.code === "ECONNRESET") { - translatedError.name.should.equal("ServiceUnavailableError"); - translatedError.retryable.should.equal(true); - } else if (mapping.code === "ECONNREFUSED") { - translatedError.name.should.equal("ConnectionForcedError"); + translatedError.name.should.equal("MessagingError"); + translatedError.code!.should.equal(mapping.code); + if (["ECONNRESET", "ECONNREFUSED", "EBUSY"].indexOf(mapping.code) !== -1) { translatedError.retryable.should.equal(true); - } else if (mapping.code === "EBUSY") { - translatedError.name.should.equal("ServerBusyError"); - translatedError.retryable.should.equal(true); - } else if (mapping.code === "ENOTFOUND") { - translatedError.name.should.equal("ServiceCommunicationError"); - translatedError.retryable.should.equal(false); - } else if (mapping.code === "ESOMETHINGRANDOM") { - translatedError.name.should.equal("SystemError"); + } else { translatedError.retryable.should.equal(false); } } diff --git a/sdk/eventhub/event-hubs/src/partitionPump.ts b/sdk/eventhub/event-hubs/src/partitionPump.ts index 0a54844e054c..5056b7332fb2 100644 --- a/sdk/eventhub/event-hubs/src/partitionPump.ts +++ b/sdk/eventhub/event-hubs/src/partitionPump.ts @@ -119,7 +119,7 @@ export class PartitionPump { try { // If the exception indicates that the partition was stolen (i.e some other consumer with same ownerlevel // started consuming the partition), update the closeReason - if (err.name === "ReceiverDisconnectedError") { + if (err.code === "ReceiverDisconnectedError") { return await this.stop(CloseReason.OwnershipLost); } // this will close the pump and will break us out of the while loop diff --git a/sdk/eventhub/event-hubs/test/client.spec.ts b/sdk/eventhub/event-hubs/test/client.spec.ts index a16efa1e80fe..69d8e582a89e 100644 --- a/sdk/eventhub/event-hubs/test/client.spec.ts +++ b/sdk/eventhub/event-hubs/test/client.spec.ts @@ -13,7 +13,7 @@ const debug = debugModule("azure:event-hubs:client-spec"); import { TokenCredential, earliestEventPosition } from "../src"; import { EventHubClient } from "../src/impl/eventHubClient"; import { packageJsonInfo } from "../src/util/constants"; -import { EnvVarKeys, getEnvVars } from "./utils/testUtils"; +import { EnvVarKeys, getEnvVars, isNode } from "./utils/testUtils"; import { EnvironmentCredential } from "@azure/identity"; import { EventHubConsumer } from "../src/receiver"; import { EventHubProducer } from "../src/sender"; @@ -128,7 +128,7 @@ describe("Create EventHubClient using Azure Identity", function(): void { describe("ServiceCommunicationError for non existent namespace #RunnableInBrowser", function(): void { let client: EventHubClient; - + const expectedErrCode = isNode ? "ENOTFOUND" : "ServiceCommunicationError" beforeEach(() => { client = new EventHubClient( "Endpoint=sb://a;SharedAccessKeyName=b;SharedAccessKey=c;EntityPath=d" @@ -147,7 +147,7 @@ describe("ServiceCommunicationError for non existent namespace #RunnableInBrowse throw new Error("Test failure"); } catch (err) { debug(err); - should.equal(err.name, "ServiceCommunicationError"); + should.equal(err.code, expectedErrCode); } }); @@ -159,7 +159,7 @@ describe("ServiceCommunicationError for non existent namespace #RunnableInBrowse throw new Error("Test failure"); } catch (err) { debug(err); - should.equal(err.name, "ServiceCommunicationError"); + should.equal(err.code, expectedErrCode); } }); @@ -172,7 +172,7 @@ describe("ServiceCommunicationError for non existent namespace #RunnableInBrowse throw new Error("Test failure"); } catch (err) { debug(err); - should.equal(err.name, "ServiceCommunicationError"); + should.equal(err.code, expectedErrCode); } }); @@ -189,7 +189,7 @@ describe("ServiceCommunicationError for non existent namespace #RunnableInBrowse throw new Error("Test failure"); } catch (err) { debug(err); - should.equal(err.name, "ServiceCommunicationError"); + should.equal(err.code, expectedErrCode); } }); }); @@ -217,7 +217,7 @@ describe("MessagingEntityNotFoundError for non existent eventhub #RunnableInBrow throw new Error("Test failure"); } catch (err) { debug(err); - should.equal(err.name, "MessagingEntityNotFoundError"); + should.equal(err.code, "MessagingEntityNotFoundError"); } }); @@ -229,7 +229,7 @@ describe("MessagingEntityNotFoundError for non existent eventhub #RunnableInBrow throw new Error("Test failure"); } catch (err) { debug(err); - should.equal(err.name, "MessagingEntityNotFoundError"); + should.equal(err.code, "MessagingEntityNotFoundError"); } }); @@ -242,7 +242,7 @@ describe("MessagingEntityNotFoundError for non existent eventhub #RunnableInBrow throw new Error("Test failure"); } catch (err) { debug(err); - should.equal(err.name, "MessagingEntityNotFoundError"); + should.equal(err.code, "MessagingEntityNotFoundError"); } }); @@ -259,7 +259,7 @@ describe("MessagingEntityNotFoundError for non existent eventhub #RunnableInBrow throw new Error("Test failure"); } catch (err) { debug(err); - should.equal(err.name, "MessagingEntityNotFoundError"); + should.equal(err.code, "MessagingEntityNotFoundError"); } }); }); diff --git a/sdk/eventhub/event-hubs/test/eventProcessor.spec.ts b/sdk/eventhub/event-hubs/test/eventProcessor.spec.ts index f9c69c822619..40aecf5e5cfa 100644 --- a/sdk/eventhub/event-hubs/test/eventProcessor.spec.ts +++ b/sdk/eventhub/event-hubs/test/eventProcessor.spec.ts @@ -1077,7 +1077,7 @@ describe("Event Processor", function(): void { async processError(err: Error, context: PartitionContext) { loggerForTest(`processError(${context.partitionId})`); didError = true; - errorName = err.name; + errorName = (err as any).code; } } diff --git a/sdk/eventhub/event-hubs/test/receiver.spec.ts b/sdk/eventhub/event-hubs/test/receiver.spec.ts index dfc2c1def448..f5660a19eb5c 100644 --- a/sdk/eventhub/event-hubs/test/receiver.spec.ts +++ b/sdk/eventhub/event-hubs/test/receiver.spec.ts @@ -655,7 +655,7 @@ describe("EventHub Receiver #RunnableInBrowser", function(): void { // link and it's session are being closed (and the session being removed from rhea's // internal map) can create havoc. setTimeout(() => { - done(should.equal(error.name, "MessagingEntityNotFoundError")); + done(should.equal(error.code, "MessagingEntityNotFoundError")); }, 3000); }; receiver = client.createConsumer("some-random-name", "0", earliestEventPosition); @@ -737,7 +737,7 @@ describe("EventHub Receiver #RunnableInBrowser", function(): void { const onError2 = (error: MessagingError | Error) => { debug(">>>> ownerLevel Receiver 2", error); should.exist(error); - should.equal(error.name, "ReceiverDisconnectedError"); + should.equal((error as any).code, "ReceiverDisconnectedError"); ownerLevelRcvr2 .stop() .then(() => receiver2.close()) @@ -776,7 +776,7 @@ describe("EventHub Receiver #RunnableInBrowser", function(): void { const onError = (error: MessagingError | Error) => { debug(">>>> ownerLevel Receiver 1", error); should.exist(error); - should.equal(error.name, "ReceiverDisconnectedError"); + should.equal((error as any).code, "ReceiverDisconnectedError"); ownerLevelRcvr1 .stop() .then(() => receiver1.close()) @@ -853,7 +853,7 @@ describe("EventHub Receiver #RunnableInBrowser", function(): void { const onerr2 = (error: MessagingError | Error) => { debug(">>>> non ownerLevel Receiver", error); should.exist(error); - should.equal(error.name, "ReceiverDisconnectedError"); + should.equal((error as any).code, "ReceiverDisconnectedError"); nonownerLevelRcvr .stop() .then(() => receiver2.close()) @@ -889,7 +889,7 @@ describe("EventHub Receiver #RunnableInBrowser", function(): void { const onerr3 = (error: MessagingError | Error) => { debug(">>>> non ownerLevel Receiver", error); should.exist(error); - should.equal(error.name, "ReceiverDisconnectedError"); + should.equal((error as any).code, "ReceiverDisconnectedError"); nonownerLevelRcvr .stop() .then(() => receiver1.close()) @@ -1033,7 +1033,7 @@ describe("EventHub Receiver #RunnableInBrowser", function(): void { const onerr2 = (err: MessagingError | Error) => { debug("@@@@ Error received by receiver rcvr-6"); debug(err); - should.equal(err.name, "QuotaExceededError"); + should.equal((err as any).code, "QuotaExceededError"); const promises = []; for (const rcvr of rcvHndlrs) { promises.push(rcvr.stop()); diff --git a/sdk/eventhub/event-hubs/test/sender.spec.ts b/sdk/eventhub/event-hubs/test/sender.spec.ts index ae9fde2debcb..004ef159642c 100644 --- a/sdk/eventhub/event-hubs/test/sender.spec.ts +++ b/sdk/eventhub/event-hubs/test/sender.spec.ts @@ -689,7 +689,7 @@ describe("EventHub Sender #RunnableInBrowser", function(): void { } catch (err) { debug(err); should.exist(err); - should.equal(err.name, "MessageTooLargeError"); + should.equal(err.code, "MessageTooLargeError"); err.message.should.match( /.*The received message \(delivery-id:(\d+), size:(\d+) bytes\) exceeds the limit \((\d+) bytes\) currently allowed on the link\..*/gi ); @@ -837,7 +837,7 @@ describe("EventHub Sender #RunnableInBrowser", function(): void { } catch (err) { debug(err); should.exist(err); - should.equal(err.name, "MessageTooLargeError"); + should.equal(err.code, "MessageTooLargeError"); err.message.should.match( /.*The received message \(delivery-id:(\d+), size:(\d+) bytes\) exceeds the limit \((\d+) bytes\) currently allowed on the link\..*/gi ); diff --git a/sdk/eventhub/event-hubs/test/utils/receivedMessagesTester.ts b/sdk/eventhub/event-hubs/test/utils/receivedMessagesTester.ts index 587872c91661..97db00b18163 100644 --- a/sdk/eventhub/event-hubs/test/utils/receivedMessagesTester.ts +++ b/sdk/eventhub/event-hubs/test/utils/receivedMessagesTester.ts @@ -55,7 +55,7 @@ export class ReceivedMessagesTester implements Required