From 744eedfad746f87d3c8e06170768e0cd4ba1c089 Mon Sep 17 00:00:00 2001 From: "David R. Williamson" Date: Wed, 29 Mar 2023 14:13:36 -0700 Subject: [PATCH] Ensure device client methods throw an object disposed exception --- iothub/device/src/ClientFactory.cs | 1 + iothub/device/src/InternalClient.cs | 21 +- .../src/Pipeline/DefaultDelegatingHandler.cs | 8 +- .../device/tests/DeviceClientDisposeTests.cs | 201 ++++++++++++++++++ iothub/device/tests/DeviceClientTests.cs | 44 ---- 5 files changed, 225 insertions(+), 50 deletions(-) create mode 100644 iothub/device/tests/DeviceClientDisposeTests.cs diff --git a/iothub/device/src/ClientFactory.cs b/iothub/device/src/ClientFactory.cs index 24dea205ee..631c26ba22 100644 --- a/iothub/device/src/ClientFactory.cs +++ b/iothub/device/src/ClientFactory.cs @@ -535,6 +535,7 @@ private static IDeviceClientPipelineBuilder BuildPipeline() { var transporthandlerFactory = new TransportHandlerFactory(); IDeviceClientPipelineBuilder pipelineBuilder = new DeviceClientPipelineBuilder() + .With((ctx, innerHandler) => new DefaultDelegatingHandler(ctx, innerHandler)) .With((ctx, innerHandler) => new RetryDelegatingHandler(ctx, innerHandler)) .With((ctx, innerHandler) => new ErrorDelegatingHandler(ctx, innerHandler)) .With((ctx, innerHandler) => new ProtocolRoutingDelegatingHandler(ctx, innerHandler)) diff --git a/iothub/device/src/InternalClient.cs b/iothub/device/src/InternalClient.cs index 278be06b9b..290f93205b 100644 --- a/iothub/device/src/InternalClient.cs +++ b/iothub/device/src/InternalClient.cs @@ -115,6 +115,7 @@ internal class InternalClient : IDisposable private readonly HttpTransportHandler _fileUploadHttpTransportHandler; private readonly ITransportSettings[] _transportSettings; private readonly ClientOptions _clientOptions; + private volatile bool _isDisposed; // Stores message input names supported by the client module and their associated delegate. private volatile Dictionary> _receiveEventEndpoints; @@ -1378,6 +1379,11 @@ internal Task GetFileUploadSasUriAsync( FileUploadSasUriRequest request, CancellationToken cancellationToken = default) { + if (_isDisposed) + { + throw new ObjectDisposedException("IoT client", DefaultDelegatingHandler.ClientDisposedMessage); + } + return _fileUploadHttpTransportHandler.GetFileUploadSasUriAsync(request, cancellationToken); } @@ -1385,6 +1391,11 @@ internal Task CompleteFileUploadAsync( FileUploadCompletionNotification notification, CancellationToken cancellationToken = default) { + if (_isDisposed) + { + throw new ObjectDisposedException("IoT client", DefaultDelegatingHandler.ClientDisposedMessage); + } + return _fileUploadHttpTransportHandler.CompleteFileUploadAsync(notification, cancellationToken); } @@ -1413,10 +1424,15 @@ public Task UploadToBlobAsync(string blobName, Stream source) [Obsolete("This API has been split into three APIs: GetFileUploadSasUri, uploading to blob directly using the Azure Storage SDK, and CompleteFileUploadAsync")] public Task UploadToBlobAsync(string blobName, Stream source, CancellationToken cancellationToken) { + if (Logging.IsEnabled) + Logging.Enter(this, blobName, source, nameof(UploadToBlobAsync)); + try { - if (Logging.IsEnabled) - Logging.Enter(this, blobName, source, nameof(UploadToBlobAsync)); + if (_isDisposed) + { + throw new ObjectDisposedException("IoT client", DefaultDelegatingHandler.ClientDisposedMessage); + } if (string.IsNullOrEmpty(blobName)) { @@ -1830,6 +1846,7 @@ internal void ValidateModuleTransportHandler(string apiName) public void Dispose() { + _isDisposed = true; InnerHandler?.Dispose(); _methodsSemaphore?.Dispose(); _moduleReceiveMessageSemaphore?.Dispose(); diff --git a/iothub/device/src/Pipeline/DefaultDelegatingHandler.cs b/iothub/device/src/Pipeline/DefaultDelegatingHandler.cs index 269b78dc73..5c37988ee0 100644 --- a/iothub/device/src/Pipeline/DefaultDelegatingHandler.cs +++ b/iothub/device/src/Pipeline/DefaultDelegatingHandler.cs @@ -9,13 +9,13 @@ namespace Microsoft.Azure.Devices.Client.Transport { - internal abstract class DefaultDelegatingHandler : IDelegatingHandler + internal class DefaultDelegatingHandler : IDelegatingHandler { - protected const string ClientDisposedMessage = "The client has been disposed and is no longer usable."; + protected internal const string ClientDisposedMessage = "The client has been disposed and is no longer usable."; protected volatile bool _isDisposed; private volatile IDelegatingHandler _innerHandler; - protected DefaultDelegatingHandler(PipelineContext context, IDelegatingHandler innerHandler) + protected internal DefaultDelegatingHandler(PipelineContext context, IDelegatingHandler innerHandler) { Context = context; _innerHandler = innerHandler; @@ -206,7 +206,7 @@ public virtual void Dispose() GC.SuppressFinalize(this); } - protected void ThrowIfDisposed() + protected internal void ThrowIfDisposed() { if (_isDisposed) { diff --git a/iothub/device/tests/DeviceClientDisposeTests.cs b/iothub/device/tests/DeviceClientDisposeTests.cs new file mode 100644 index 0000000000..fda5f781c1 --- /dev/null +++ b/iothub/device/tests/DeviceClientDisposeTests.cs @@ -0,0 +1,201 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using FluentAssertions; +using Microsoft.Azure.Devices.Client.Transport; +using Microsoft.Azure.Devices.Shared; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace Microsoft.Azure.Devices.Client.Tests +{ + [TestClass] + /// + /// Ensure that any calls to a disposed device client result in an ObjectDisposedException. + /// + public class DeviceClientDisposeTests + { + private static DeviceClient s_client; + private const int DefaultTimeToLiveSeconds = 1 * 60 * 60; + + [ClassInitialize] + public static void ClassInitialize(TestContext context) + { + // Create a disposed device client for the tests in this class + var rndBytes = new byte[32]; + new Random().NextBytes(rndBytes); + string testSharedAccessKey = Convert.ToBase64String(rndBytes); + var csBuilder = IotHubConnectionStringBuilder.Create( + "contoso.azure-devices.net", + new DeviceAuthenticationWithRegistrySymmetricKey("deviceId", testSharedAccessKey)); + s_client = DeviceClient.CreateFromConnectionString(csBuilder.ToString()); + s_client.Dispose(); + } + + [TestMethod] + public async Task DeviceClient_OpenAsync_ThrowsWhenClientIsDisposed() + { + using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(1)); + Func op = async () => await s_client.OpenAsync(cts.Token).ConfigureAwait(false); + await op.Should().ThrowAsync().ConfigureAwait(false); + } + + [TestMethod] + public async Task DeviceClient_CloseAsync_ThrowsWhenClientIsDisposed() + { + using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(1)); + Func op = async () => await s_client.CloseAsync(cts.Token).ConfigureAwait(false); + await op.Should().ThrowAsync().ConfigureAwait(false); + } + + [TestMethod] + public async Task DeviceClient_SetMethodHandlerAsync_ThrowsWhenClientIsDisposed() + { + using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(1)); + Func op = async () => await s_client + .SetMethodHandlerAsync( + "methodName", + (request, userContext) => Task.FromResult(new MethodResponse(400)), + cts.Token) + .ConfigureAwait(false); + await op.Should().ThrowAsync().ConfigureAwait(false); + } + + [TestMethod] + public async Task DeviceClient_SetMethodDefaultHandlerAsync_ThrowsWhenClientIsDisposed() + { + using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(1)); + Func op = async () => await s_client + .SetMethodDefaultHandlerAsync( + (request, userContext) => Task.FromResult(new MethodResponse(400)), + cts.Token) + .ConfigureAwait(false); + await op.Should().ThrowAsync().ConfigureAwait(false); + } + + [TestMethod] + public async Task DeviceClient_SetDesiredPropertyUpdateCallbackAsync_ThrowsWhenClientIsDisposed() + { + using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(1)); + Func op = async () => await s_client + .SetDesiredPropertyUpdateCallbackAsync( + (desiredProperties, userContext) => TaskHelpers.CompletedTask, + null, + cts.Token) + .ConfigureAwait(false); + await op.Should().ThrowAsync().ConfigureAwait(false); + } + + [TestMethod] + public async Task DeviceClient_SetReceiveMessageHandlerAsync_ThrowsWhenClientIsDisposed() + { + using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(1)); + Func op = async () => await s_client + .SetReceiveMessageHandlerAsync( + (message, userContext) => TaskHelpers.CompletedTask, + null, + cts.Token) + .ConfigureAwait(false); + await op.Should().ThrowAsync().ConfigureAwait(false); + } + + [TestMethod] + public async Task DeviceClient_ReceiveAsync_ThrowsWhenClientIsDisposed() + { + using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(1)); + Func op = async () => await s_client.ReceiveAsync(cts.Token).ConfigureAwait(false); + await op.Should().ThrowAsync().ConfigureAwait(false); + } + + [TestMethod] + public async Task DeviceClient_CompleteAsync_ThrowsWhenClientIsDisposed() + { + using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(1)); + Func op = async () => await s_client.CompleteAsync("fakeLockToken", cts.Token).ConfigureAwait(false); + await op.Should().ThrowAsync().ConfigureAwait(false); + } + + [TestMethod] + public async Task DeviceClient_AbandonAsync_ThrowsWhenClientIsDisposed() + { + using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(1)); + Func op = async () => await s_client.AbandonAsync("fakeLockToken", cts.Token).ConfigureAwait(false); + await op.Should().ThrowAsync().ConfigureAwait(false); + } + + [TestMethod] + public async Task DeviceClient_RejectAsync_ThrowsWhenClientIsDisposed() + { + using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(1)); + Func op = async () => await s_client.RejectAsync("fakeLockToken", cts.Token).ConfigureAwait(false); + await op.Should().ThrowAsync().ConfigureAwait(false); + } + + [TestMethod] + public async Task DeviceClient_SendEventAsync_ThrowsWhenClientIsDisposed() + { + using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(1)); + using var msg = new Message(); + Func op = async () => await s_client.SendEventAsync(msg, cts.Token).ConfigureAwait(false); + await op.Should().ThrowAsync().ConfigureAwait(false); + } + + [TestMethod] + public async Task DeviceClient_SendEventBatchAsync_ThrowsWhenClientIsDisposed() + { + using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(1)); + using var msg = new Message(); + Func op = async () => await s_client.SendEventBatchAsync(new[] { msg }, cts.Token).ConfigureAwait(false); + await op.Should().ThrowAsync().ConfigureAwait(false); + } + + [TestMethod] + public async Task DeviceClient_GetTwinAsync_ThrowsWhenClientIsDisposed() + { + using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(1)); + Func op = async () => await s_client.GetTwinAsync(cts.Token).ConfigureAwait(false); + await op.Should().ThrowAsync().ConfigureAwait(false); + } + + [TestMethod] + public async Task DeviceClient_UpdateReportedPropertiesAsync_ThrowsWhenClientIsDisposed() + { + using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(1)); + Func op = async () => await s_client.UpdateReportedPropertiesAsync(new TwinCollection(), cts.Token).ConfigureAwait(false); + await op.Should().ThrowAsync().ConfigureAwait(false); + } + + [TestMethod] + public async Task DeviceClient_UploadToBlobAsync_ThrowsWhenClientIsDisposed() + { + using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(1)); + using var stream = new MemoryStream(); +#pragma warning disable CS0618 // Type or member is obsolete + Func op = async () => await s_client.UploadToBlobAsync("blobName", stream, cts.Token).ConfigureAwait(false); +#pragma warning restore CS0618 // Type or member is obsolete + await op.Should().ThrowAsync().ConfigureAwait(false); + } + + [TestMethod] + public async Task DeviceClient_GetFileUploadSasUriAsync_ThrowsWhenClientIsDisposed() + { + using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(1)); + Func op = async () => await s_client.GetFileUploadSasUriAsync(new FileUploadSasUriRequest(), cts.Token).ConfigureAwait(false); + await op.Should().ThrowAsync().ConfigureAwait(false); + } + + [TestMethod] + public async Task DeviceClient_CompleteFileUploadAsync_ThrowsWhenClientIsDisposed() + { + using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(1)); + Func op = async () => await s_client.CompleteFileUploadAsync(new FileUploadCompletionNotification(), cts.Token).ConfigureAwait(false); + await op.Should().ThrowAsync().ConfigureAwait(false); + } + } +} diff --git a/iothub/device/tests/DeviceClientTests.cs b/iothub/device/tests/DeviceClientTests.cs index 34aa626def..d51a288f02 100644 --- a/iothub/device/tests/DeviceClientTests.cs +++ b/iothub/device/tests/DeviceClientTests.cs @@ -154,8 +154,6 @@ public void DeviceClient_CreateFromConnectionString_WithModuleIdThrows() act.Should().Throw(); } - /* Tests_SRS_DEVICECLIENT_28_002: [This property shall be defaulted to 240000 (4 minutes).] */ - [TestMethod] public void DeviceClient_OperationTimeoutInMilliseconds_Property_DefaultValue() { @@ -312,7 +310,6 @@ await innerHandler } [TestMethod] - // Tests_SRS_DEVICECLIENT_10_012: [** If the given methodRequestInternal argument is null, fail silently **]** public async Task DeviceClient_OnMethodCalled_NullMethodRequest() { using var deviceClient = DeviceClient.CreateFromConnectionString(FakeConnectionString); @@ -353,7 +350,6 @@ await deviceClient.SetMethodHandlerAsync("TestMethodName", (payload, context) => } [TestMethod] - // Tests_SRS_DEVICECLIENT_28_020: [** If the given methodRequestInternal data is not valid json, respond with status code 400 (BAD REQUEST) **]** public async Task DeviceClient_OnMethodCalled_MethodRequestHasInvalidJson() { using var deviceClient = DeviceClient.CreateFromConnectionString(FakeConnectionString); @@ -374,7 +370,6 @@ await deviceClient.SetMethodHandlerAsync("TestMethodName", (payload, context) => } [TestMethod] - // Tests_SRS_DEVICECLIENT_10_011: [ The OnMethodCalled shall invoke the specified delegate. ] public async Task DeviceClient_OnMethodCalled_MethodRequestHasValidJson() { using var deviceClient = DeviceClient.CreateFromConnectionString(FakeConnectionString); @@ -395,7 +390,6 @@ await deviceClient.SetMethodHandlerAsync("TestMethodName", (payload, context) => } [TestMethod] - // Tests_SRS_DEVICECLIENT_28_021: [** If the MethodResponse from the MethodHandler is not valid json, respond with status code 500 (USER CODE EXCEPTION) **]** public async Task DeviceClient_OnMethodCalled_MethodResponseHasInvalidJson() { using var deviceClient = DeviceClient.CreateFromConnectionString(FakeConnectionString); @@ -416,7 +410,6 @@ await deviceClient.SetMethodHandlerAsync("TestMethodName", (payload, context) => } [TestMethod] - // Tests_SRS_DEVICECLIENT_10_012: [** If the given methodRequestInternal argument is null, fail silently **]** public async Task DeviceClient_OnMethodCalled_NullMethodRequest_With_SetMethodHandler() { using var deviceClient = DeviceClient.CreateFromConnectionString(FakeConnectionString); @@ -461,8 +454,6 @@ public async Task DeviceClient_OnMethodCalled_MethodRequestHasEmptyBody_With_Set } [TestMethod] - // Tests_SRS_DEVICECLIENT_10_011: [ The OnMethodCalled shall invoke the specified delegate. ] - // Tests_SRS_DEVICECLIENT_03_013: [Otherwise, the MethodResponseInternal constructor shall be invoked with the result supplied.] public async Task DeviceClient_OnMethodCalled_MethodRequestHasValidJson_With_SetMethodHandler() { using var deviceClient = DeviceClient.CreateFromConnectionString(FakeConnectionString); @@ -485,8 +476,6 @@ public async Task DeviceClient_OnMethodCalled_MethodRequestHasValidJson_With_Set } [TestMethod] - // Tests_SRS_DEVICECLIENT_24_002: [ The OnMethodCalled shall invoke the default delegate if there is no specified delegate for that method. ] - // Tests_SRS_DEVICECLIENT_03_013: [Otherwise, the MethodResponseInternal constructor shall be invoked with the result supplied.] public async Task DeviceClient_OnMethodCalled_MethodRequestHasValidJson_With_SetMethodDefaultHandler() { using var deviceClient = DeviceClient.CreateFromConnectionString(FakeConnectionString); @@ -507,8 +496,6 @@ await deviceClient.SetMethodDefaultHandlerAsync((payload, context) => } [TestMethod] - // Tests_SRS_DEVICECLIENT_24_002: [ The OnMethodCalled shall invoke the default delegate if there is no specified delegate for that method. ] - // Tests_SRS_DEVICECLIENT_03_013: [Otherwise, the MethodResponseInternal constructor shall be invoked with the result supplied.] public async Task DeviceClient_OnMethodCalled_MethodRequestHasValidJson_With_SetMethodHandlerNotMatchedAndDefaultHandler() { using var deviceClient = DeviceClient.CreateFromConnectionString(FakeConnectionString); @@ -536,8 +523,6 @@ await deviceClient.SetMethodDefaultHandlerAsync((payload, context) => } [TestMethod] - // Tests_SRS_DEVICECLIENT_10_011: [ The OnMethodCalled shall invoke the specified delegate. ] - // Tests_SRS_DEVICECLIENT_03_013: [Otherwise, the MethodResponseInternal constructor shall be invoked with the result supplied.] public async Task DeviceClient_OnMethodCalled_MethodRequestHasValidJson_With_SetMethodHandlerAndDefaultHandler() { using var deviceClient = DeviceClient.CreateFromConnectionString(FakeConnectionString); @@ -565,8 +550,6 @@ await deviceClient.SetMethodDefaultHandlerAsync((payload, context) => } [TestMethod] - // Tests_SRS_DEVICECLIENT_10_011: [ The OnMethodCalled shall invoke the specified delegate. ] - // Tests_SRS_DEVICECLIENT_03_012: [If the MethodResponse does not contain result, the MethodResponseInternal constructor shall be invoked with no results.] public async Task DeviceClient_OnMethodCalled_MethodRequestHasValidJson_With_SetMethodHandler_With_No_Result() { using var deviceClient = DeviceClient.CreateFromConnectionString(FakeConnectionString); @@ -589,7 +572,6 @@ public async Task DeviceClient_OnMethodCalled_MethodRequestHasValidJson_With_Set } [TestMethod] - // Tests_SRS_DEVICECLIENT_28_021: [** If the MethodResponse from the MethodHandler is not valid json, respond with status code 500 (USER CODE EXCEPTION) **]** public async Task DeviceClientOnMethodCalledMethodResponseHasInvalidJsonWithSetMethodHandler() { using var deviceClient = DeviceClient.CreateFromConnectionString(FakeConnectionString); @@ -612,7 +594,6 @@ public async Task DeviceClientOnMethodCalledMethodResponseHasInvalidJsonWithSetM } [TestMethod] - // Tests_SRS_DEVICECLIENT_10_013: [** If the given method does not have an associated delegate and no default delegate was registered, respond with status code 501 (METHOD NOT IMPLEMENTED) **]** public async Task DeviceClientOnMethodCalledNoMethodHandler() { using var deviceClient = DeviceClient.CreateFromConnectionString(FakeConnectionString); @@ -627,8 +608,6 @@ public async Task DeviceClientOnMethodCalledNoMethodHandler() } [TestMethod] - // Tests_SRS_DEVICECLIENT_10_001: [ It shall lazy-initialize the deviceMethods property. ] - // Tests_SRS_DEVICECLIENT_10_003: [ The given delegate will only be added if it is not null. ] public async Task DeviceClientSetMethodHandlerSetFirstMethodHandler() { string connectionString = "HostName=acme.azure-devices.net;SharedAccessKeyName=AllAccessKey;DeviceId=dumpy;SharedAccessKey=dGVzdFN0cmluZzE="; @@ -675,8 +654,6 @@ public async Task DeviceClientSetMethodHandlerSetFirstMethodHandler() } [TestMethod] - // Tests_SRS_DEVICECLIENT_10_001: [ It shall lazy-initialize the deviceMethods property. ] - // Tests_SRS_DEVICECLIENT_10_003: [ The given delegate will only be added if it is not null. ] public async Task DeviceClientSetMethodHandlerSetFirstMethodDefaultHandler() { string connectionString = "HostName=acme.azure-devices.net;SharedAccessKeyName=AllAccessKey;DeviceId=dumpy;SharedAccessKey=dGVzdFN0cmluZzE="; @@ -723,7 +700,6 @@ public async Task DeviceClientSetMethodHandlerSetFirstMethodDefaultHandler() } [TestMethod] - // Tests_SRS_DEVICECLIENT_10_002: [ If the given methodName already has an associated delegate, the existing delegate shall be removed. ] public async Task DeviceClientSetMethodHandlerOverwriteExistingDelegate() { string connectionString = "HostName=acme.azure-devices.net;SharedAccessKeyName=AllAccessKey;DeviceId=dumpy;SharedAccessKey=dGVzdFN0cmluZzE="; @@ -783,7 +759,6 @@ public async Task DeviceClientSetMethodHandlerOverwriteExistingDelegate() } [TestMethod] - // Tests_SRS_DEVICECLIENT_24_001: [ If the default callback has already been set, it is replaced with the new callback. ] public async Task DeviceClientSetMethodHandlerOverwriteExistingDefaultDelegate() { string connectionString = "HostName=acme.azure-devices.net;SharedAccessKeyName=AllAccessKey;DeviceId=dumpy;SharedAccessKey=dGVzdFN0cmluZzE="; @@ -843,8 +818,6 @@ public async Task DeviceClientSetMethodHandlerOverwriteExistingDefaultDelegate() } [TestMethod] - // Tests_SRS_DEVICECLIENT_10_004: [ The deviceMethods property shall be deleted if the last delegate has been removed. ] - // Tests_SRS_DEVICECLIENT_10_006: [ It shall DisableMethodsAsync when the last delegate has been removed. ] public async Task DeviceClientSetMethodHandlerUnsetLastMethodHandler() { string connectionString = "HostName=acme.azure-devices.net;SharedAccessKeyName=AllAccessKey;DeviceId=dumpy;SharedAccessKey=dGVzdFN0cmluZzE="; @@ -887,8 +860,6 @@ public async Task DeviceClientSetMethodHandlerUnsetLastMethodHandler() } [TestMethod] - // Tests_SRS_DEVICECLIENT_10_004: [ The deviceMethods property shall be deleted if the last delegate has been removed. ] - // Tests_SRS_DEVICECLIENT_10_006: [ It shall DisableMethodsAsync when the last delegate has been removed. ] public async Task DeviceClientSetMethodHandlerUnsetLastMethodHandlerWithDefaultHandlerSet() { string connectionString = "HostName=acme.azure-devices.net;SharedAccessKeyName=AllAccessKey;DeviceId=dumpy;SharedAccessKey=dGVzdFN0cmluZzE="; @@ -948,8 +919,6 @@ public async Task DeviceClientSetMethodHandlerUnsetLastMethodHandlerWithDefaultH } [TestMethod] - // Tests_SRS_DEVICECLIENT_10_004: [ The deviceMethods property shall be deleted if the last delegate has been removed. ] - // Tests_SRS_DEVICECLIENT_10_006: [ It shall DisableMethodsAsync when the last delegate has been removed. ] public async Task DeviceClientSetMethodHandlerUnsetDefaultHandlerSet() { string connectionString = "HostName=acme.azure-devices.net;SharedAccessKeyName=AllAccessKey;DeviceId=dumpy;SharedAccessKey=dGVzdFN0cmluZzE="; @@ -1022,8 +991,6 @@ public async Task DeviceClientSetMethodHandlerUnsetWhenNoMethodHandler() } [TestMethod] - // Tests_SRS_DEVICECLIENT_10_001: [ It shall lazy-initialize the deviceMethods property. ] - // Tests_SRS_DEVICECLIENT_10_003: [ The given delegate will only be added if it is not null. ] public async Task DeviceClientSetMethodHandlerSetFirstMethodHandlerWithSetMethodHandler() { string connectionString = "HostName=acme.azure-devices.net;SharedAccessKeyName=AllAccessKey;DeviceId=dumpy;SharedAccessKey=dGVzdFN0cmluZzE="; @@ -1061,7 +1028,6 @@ public async Task DeviceClientSetMethodHandlerSetFirstMethodHandlerWithSetMethod } [TestMethod] - // Tests_SRS_DEVICECLIENT_10_002: [ If the given methodName already has an associated delegate, the existing delegate shall be removed. ] public async Task DeviceClientSetMethodHandlerOverwriteExistingDelegateWithSetMethodHandler() { string connectionString = "HostName=acme.azure-devices.net;SharedAccessKeyName=AllAccessKey;DeviceId=dumpy;SharedAccessKey=dGVzdFN0cmluZzE="; @@ -1123,8 +1089,6 @@ public async Task DeviceClientSetMethodHandlerOverwriteExistingDelegateWithSetMe } [TestMethod] - // Tests_SRS_DEVICECLIENT_10_004: [ The deviceMethods property shall be deleted if the last delegate has been removed. ] - // Tests_SRS_DEVICECLIENT_10_006: [ It shall DisableMethodsAsync when the last delegate has been removed. ] public async Task DeviceClientSetMethodHandlerUnsetLastMethodHandlerWithSetMethodHandler() { string connectionString = "HostName=acme.azure-devices.net;SharedAccessKeyName=AllAccessKey;DeviceId=dumpy;SharedAccessKey=dGVzdFN0cmluZzE="; @@ -1184,9 +1148,6 @@ public async Task DeviceClientSetMethodHandlerUnsetWhenNoMethodHandlerWithSetMet } [TestMethod] - // Tests_SRS_DEVICECLIENT_28_024: [** `OnConnectionOpened` shall invoke the connectionStatusChangesHandler if ConnectionStatus is changed **]** - // Tests_SRS_DEVICECLIENT_28_025: [** `SetConnectionStatusChangesHandler` shall set connectionStatusChangesHandler **]** - // Tests_SRS_DEVICECLIENT_28_026: [** `SetConnectionStatusChangesHandler` shall unset connectionStatusChangesHandler if `statusChangesHandler` is null **]** public void DeviceClientOnConnectionOpenedInvokeHandlerForStatusChange() { using var deviceClient = DeviceClient.CreateFromConnectionString(FakeConnectionString); @@ -1210,7 +1171,6 @@ public void DeviceClientOnConnectionOpenedInvokeHandlerForStatusChange() } [TestMethod] - // Tests_SRS_DEVICECLIENT_28_026: [** `SetConnectionStatusChangesHandler` shall unset connectionStatusChangesHandler if `statusChangesHandler` is null **]** public void DeviceClientOnConnectionOpenedWithNullHandler() { using var deviceClient = DeviceClient.CreateFromConnectionString(FakeConnectionString); @@ -1233,7 +1193,6 @@ public void DeviceClientOnConnectionOpenedWithNullHandler() } [TestMethod] - // Tests_SRS_DEVICECLIENT_28_024: [** `OnConnectionOpened` shall invoke the connectionStatusChangesHandler if ConnectionStatus is changed **]** public void DeviceClientOnConnectionOpenedNotInvokeHandlerWithoutStatusChange() { using var deviceClient = DeviceClient.CreateFromConnectionString(FakeConnectionString); @@ -1263,8 +1222,6 @@ public void DeviceClientOnConnectionOpenedNotInvokeHandlerWithoutStatusChange() } [TestMethod] - // Tests_SRS_DEVICECLIENT_28_022: [** `OnConnectionClosed` shall invoke the RecoverConnections process. **]** - // Tests_SRS_DEVICECLIENT_28_023: [** `OnConnectionClosed` shall invoke the connectionStatusChangesHandler if ConnectionStatus is changed. **]** public void DeviceClientOnConnectionClosedInvokeHandlerAndRecoveryForStatusChange() { using var deviceClient = DeviceClient.CreateFromConnectionString(FakeConnectionString); @@ -2126,7 +2083,6 @@ public void DeviceClient_SetDesiredPropertyCallbackAsync_Cancelled_MaintainLegac act.Should().Throw(); } - private class TestDeviceAuthenticationWithTokenRefresh : DeviceAuthenticationWithTokenRefresh { // This authentication method relies on the default sas token time to live and renewal buffer set by the SDK.